1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo) 2 3 #include "JSIInteropModuleRegistry.h" 4 #include "ExpoModulesHostObject.h" 5 #include "JavaReferencesCache.h" 6 #include "JSReferencesCache.h" 7 8 #include <fbjni/detail/Meta.h> 9 #include <fbjni/fbjni.h> 10 11 #include <memory> 12 13 namespace jni = facebook::jni; 14 namespace jsi = facebook::jsi; 15 16 namespace expo { 17 jni::local_ref<JSIInteropModuleRegistry::jhybriddata> 18 JSIInteropModuleRegistry::initHybrid(jni::alias_ref<jhybridobject> jThis) { 19 return makeCxxInstance(jThis); 20 } 21 22 void JSIInteropModuleRegistry::registerNatives() { 23 registerHybrid({ 24 makeNativeMethod("initHybrid", JSIInteropModuleRegistry::initHybrid), 25 makeNativeMethod("installJSI", JSIInteropModuleRegistry::installJSI), 26 makeNativeMethod("installJSIForTests", 27 JSIInteropModuleRegistry::installJSIForTests), 28 makeNativeMethod("evaluateScript", JSIInteropModuleRegistry::evaluateScript), 29 makeNativeMethod("global", JSIInteropModuleRegistry::global), 30 makeNativeMethod("createObject", JSIInteropModuleRegistry::createObject), 31 makeNativeMethod("drainJSEventLoop", JSIInteropModuleRegistry::drainJSEventLoop), 32 }); 33 } 34 35 JSIInteropModuleRegistry::JSIInteropModuleRegistry(jni::alias_ref<jhybridobject> jThis) 36 : javaPart_(jni::make_global(jThis)) {} 37 38 void JSIInteropModuleRegistry::installJSI( 39 jlong jsRuntimePointer, 40 jni::alias_ref<JNIDeallocator::javaobject> jniDeallocator, 41 jni::alias_ref<react::CallInvokerHolder::javaobject> jsInvokerHolder, 42 jni::alias_ref<react::CallInvokerHolder::javaobject> nativeInvokerHolder 43 ) { 44 this->jniDeallocator = jni::make_global(jniDeallocator); 45 46 auto runtime = reinterpret_cast<jsi::Runtime *>(jsRuntimePointer); 47 48 jsRegistry = std::make_unique<JSReferencesCache>(*runtime); 49 50 runtimeHolder = std::make_shared<JavaScriptRuntime>( 51 this, 52 runtime, 53 jsInvokerHolder->cthis()->getCallInvoker(), 54 nativeInvokerHolder->cthis()->getCallInvoker() 55 ); 56 57 auto expoModules = std::make_shared<ExpoModulesHostObject>(this); 58 auto expoModulesObject = jsi::Object::createFromHostObject(*runtime, expoModules); 59 60 // Define the `global.expo.modules` object. 61 runtimeHolder 62 ->getMainObject() 63 ->setProperty( 64 *runtime, 65 "modules", 66 expoModulesObject 67 ); 68 69 // Also define `global.ExpoModules` for backwards compatibility (used before SDK47, can be removed in SDK48). 70 runtime 71 ->global() 72 .setProperty( 73 *runtime, 74 "ExpoModules", 75 expoModulesObject 76 ); 77 } 78 79 void JSIInteropModuleRegistry::installJSIForTests( 80 jni::alias_ref<JNIDeallocator::javaobject> jniDeallocator 81 ) { 82 #if !UNIT_TEST 83 throw std::logic_error("The function is only available when UNIT_TEST is defined."); 84 #else 85 this->jniDeallocator = jni::make_global(jniDeallocator); 86 87 runtimeHolder = std::make_shared<JavaScriptRuntime>(this); 88 jsi::Runtime &jsiRuntime = runtimeHolder->get(); 89 90 jsRegistry = std::make_unique<JSReferencesCache>(jsiRuntime); 91 92 auto expoModules = std::make_shared<ExpoModulesHostObject>(this); 93 auto expoModulesObject = jsi::Object::createFromHostObject(jsiRuntime, expoModules); 94 95 runtimeHolder 96 ->getMainObject() 97 ->setProperty( 98 jsiRuntime, 99 "modules", 100 std::move(expoModulesObject) 101 ); 102 #endif // !UNIT_TEST 103 } 104 105 jni::local_ref<JavaScriptModuleObject::javaobject> 106 JSIInteropModuleRegistry::callGetJavaScriptModuleObjectMethod(const std::string &moduleName) const { 107 const static auto method = expo::JSIInteropModuleRegistry::javaClassLocal() 108 ->getMethod<jni::local_ref<JavaScriptModuleObject::javaobject>( 109 std::string)>( 110 "getJavaScriptModuleObject" 111 ); 112 113 return method(javaPart_, moduleName); 114 } 115 116 jni::local_ref<JavaScriptModuleObject::javaobject> 117 JSIInteropModuleRegistry::callGetCoreModuleObject() const { 118 const static auto method = expo::JSIInteropModuleRegistry::javaClassLocal() 119 ->getMethod<jni::local_ref<JavaScriptModuleObject::javaobject>()>( 120 "getCoreModuleObject" 121 ); 122 123 return method(javaPart_); 124 } 125 126 jni::local_ref<jni::JArrayClass<jni::JString>> 127 JSIInteropModuleRegistry::callGetJavaScriptModulesNames() const { 128 const static auto method = expo::JSIInteropModuleRegistry::javaClassLocal() 129 ->getMethod<jni::local_ref<jni::JArrayClass<jni::JString>>()>( 130 "getJavaScriptModulesName" 131 ); 132 return method(javaPart_); 133 } 134 135 bool JSIInteropModuleRegistry::callHasModule(const std::string &moduleName) const { 136 const static auto method = expo::JSIInteropModuleRegistry::javaClassLocal() 137 ->getMethod<jboolean(std::string)>( 138 "hasModule" 139 ); 140 return (bool) method(javaPart_, moduleName); 141 } 142 143 jni::local_ref<JavaScriptModuleObject::javaobject> 144 JSIInteropModuleRegistry::getModule(const std::string &moduleName) const { 145 return callGetJavaScriptModuleObjectMethod(moduleName); 146 } 147 148 jni::local_ref<JavaScriptModuleObject::javaobject> JSIInteropModuleRegistry::getCoreModule() const { 149 return callGetCoreModuleObject(); 150 } 151 152 bool JSIInteropModuleRegistry::hasModule(const std::string &moduleName) const { 153 return callHasModule(moduleName); 154 } 155 156 jni::local_ref<jni::JArrayClass<jni::JString>> JSIInteropModuleRegistry::getModulesName() const { 157 return callGetJavaScriptModulesNames(); 158 } 159 160 jni::local_ref<JavaScriptValue::javaobject> JSIInteropModuleRegistry::evaluateScript( 161 jni::JString script 162 ) { 163 return runtimeHolder->evaluateScript(script.toStdString()); 164 } 165 166 jni::local_ref<JavaScriptObject::javaobject> JSIInteropModuleRegistry::global() { 167 return runtimeHolder->global(); 168 } 169 170 jni::local_ref<JavaScriptObject::javaobject> JSIInteropModuleRegistry::createObject() { 171 return runtimeHolder->createObject(); 172 } 173 174 void JSIInteropModuleRegistry::drainJSEventLoop() { 175 runtimeHolder->drainJSEventLoop(); 176 } 177 178 void JSIInteropModuleRegistry::registerSharedObject( 179 jni::local_ref<jobject> native, 180 jni::local_ref<JavaScriptObject::javaobject> js 181 ) { 182 const static auto method = expo::JSIInteropModuleRegistry::javaClassLocal() 183 ->getMethod<void(jni::local_ref<jobject>, jni::local_ref<JavaScriptObject::javaobject>)>( 184 "registerSharedObject" 185 ); 186 method(javaPart_, std::move(native), std::move(js)); 187 } 188 } // namespace expo 189