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<react::CallInvokerHolder::javaobject> jsInvokerHolder, 41 jni::alias_ref<react::CallInvokerHolder::javaobject> nativeInvokerHolder 42 ) { 43 auto runtime = reinterpret_cast<jsi::Runtime *>(jsRuntimePointer); 44 45 jsRegistry = std::make_unique<JSReferencesCache>(*runtime); 46 47 runtimeHolder = std::make_shared<JavaScriptRuntime>( 48 this, 49 runtime, 50 jsInvokerHolder->cthis()->getCallInvoker(), 51 nativeInvokerHolder->cthis()->getCallInvoker() 52 ); 53 54 auto expoModules = std::make_shared<ExpoModulesHostObject>(this); 55 auto expoModulesObject = jsi::Object::createFromHostObject(*runtime, expoModules); 56 57 // Define the `global.expo.modules` object. 58 runtimeHolder 59 ->getMainObject() 60 ->setProperty( 61 *runtime, 62 "modules", 63 expoModulesObject 64 ); 65 66 // Also define `global.ExpoModules` for backwards compatibility (used before SDK47, can be removed in SDK48). 67 runtime 68 ->global() 69 .setProperty( 70 *runtime, 71 "ExpoModules", 72 expoModulesObject 73 ); 74 } 75 76 void JSIInteropModuleRegistry::installJSIForTests() { 77 #if !UNIT_TEST 78 throw std::logic_error("The function is only available when UNIT_TEST is defined."); 79 #else 80 runtimeHolder = std::make_shared<JavaScriptRuntime>(this); 81 jsi::Runtime &jsiRuntime = runtimeHolder->get(); 82 83 jsRegistry = std::make_unique<JSReferencesCache>(jsiRuntime); 84 85 auto expoModules = std::make_shared<ExpoModulesHostObject>(this); 86 auto expoModulesObject = jsi::Object::createFromHostObject(jsiRuntime, expoModules); 87 88 runtimeHolder 89 ->getMainObject() 90 ->setProperty( 91 jsiRuntime, 92 "modules", 93 std::move(expoModulesObject) 94 ); 95 #endif // !UNIT_TEST 96 } 97 98 jni::local_ref<JavaScriptModuleObject::javaobject> 99 JSIInteropModuleRegistry::callGetJavaScriptModuleObjectMethod(const std::string &moduleName) const { 100 const static auto method = expo::JSIInteropModuleRegistry::javaClassLocal() 101 ->getMethod<jni::local_ref<JavaScriptModuleObject::javaobject>( 102 std::string)>( 103 "getJavaScriptModuleObject" 104 ); 105 106 return method(javaPart_, moduleName); 107 } 108 109 jni::local_ref<jni::JArrayClass<jni::JString>> 110 JSIInteropModuleRegistry::callGetJavaScriptModulesNames() const { 111 const static auto method = expo::JSIInteropModuleRegistry::javaClassLocal() 112 ->getMethod<jni::local_ref<jni::JArrayClass<jni::JString>>()>( 113 "getJavaScriptModulesName" 114 ); 115 return method(javaPart_); 116 } 117 118 bool JSIInteropModuleRegistry::callHasModule(const std::string &moduleName) const { 119 const static auto method = expo::JSIInteropModuleRegistry::javaClassLocal() 120 ->getMethod<jboolean(std::string)>( 121 "hasModule" 122 ); 123 return (bool) method(javaPart_, moduleName); 124 } 125 126 jni::local_ref<JavaScriptModuleObject::javaobject> 127 JSIInteropModuleRegistry::getModule(const std::string &moduleName) const { 128 return callGetJavaScriptModuleObjectMethod(moduleName); 129 } 130 131 bool JSIInteropModuleRegistry::hasModule(const std::string &moduleName) const { 132 return callHasModule(moduleName); 133 } 134 135 jni::local_ref<jni::JArrayClass<jni::JString>> JSIInteropModuleRegistry::getModulesName() const { 136 return callGetJavaScriptModulesNames(); 137 } 138 139 jni::local_ref<JavaScriptValue::javaobject> JSIInteropModuleRegistry::evaluateScript( 140 jni::JString script 141 ) { 142 return runtimeHolder->evaluateScript(script.toStdString()); 143 } 144 145 jni::local_ref<JavaScriptObject::javaobject> JSIInteropModuleRegistry::global() { 146 return runtimeHolder->global(); 147 } 148 149 jni::local_ref<JavaScriptObject::javaobject> JSIInteropModuleRegistry::createObject() { 150 return runtimeHolder->createObject(); 151 } 152 153 void JSIInteropModuleRegistry::drainJSEventLoop() { 154 runtimeHolder->drainJSEventLoop(); 155 } 156 157 void JSIInteropModuleRegistry::registerSharedObject( 158 jni::local_ref<jobject> native, 159 jni::local_ref<JavaScriptObject::javaobject> js 160 ) { 161 const static auto method = expo::JSIInteropModuleRegistry::javaClassLocal() 162 ->getMethod<void(jni::local_ref<jobject>, jni::local_ref<JavaScriptObject::javaobject>)>( 163 "registerSharedObject" 164 ); 165 method(javaPart_, std::move(native), std::move(js)); 166 } 167 } // namespace expo 168