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