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