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
getNativeMethodCallInvokerHolderCompatible(jni::alias_ref<NativeMethodCallInvokerHolderCompatible::javaobject> holder)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>
initHybrid(jni::alias_ref<jhybridobject> jThis)37 JSIInteropModuleRegistry::initHybrid(jni::alias_ref<jhybridobject> jThis) {
38 return makeCxxInstance(jThis);
39 }
40
registerNatives()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
JSIInteropModuleRegistry(jni::alias_ref<jhybridobject> jThis)54 JSIInteropModuleRegistry::JSIInteropModuleRegistry(jni::alias_ref<jhybridobject> jThis)
55 : javaPart_(jni::make_global(jThis)) {}
56
installJSI(jlong jsRuntimePointer,jni::alias_ref<JNIDeallocator::javaobject> jniDeallocator,jni::alias_ref<react::CallInvokerHolder::javaobject> jsInvokerHolder,jni::alias_ref<NativeMethodCallInvokerHolderCompatible::javaobject> nativeInvokerHolder)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
installJSIForTests(jni::alias_ref<JNIDeallocator::javaobject> jniDeallocator)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>
callGetJavaScriptModuleObjectMethod(const std::string & moduleName) const129 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>
callGetCoreModuleObject() const140 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>>
callGetJavaScriptModulesNames() const150 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
callHasModule(const std::string & moduleName) const158 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>
getModule(const std::string & moduleName) const167 JSIInteropModuleRegistry::getModule(const std::string &moduleName) const {
168 return callGetJavaScriptModuleObjectMethod(moduleName);
169 }
170
getCoreModule() const171 jni::local_ref<JavaScriptModuleObject::javaobject> JSIInteropModuleRegistry::getCoreModule() const {
172 return callGetCoreModuleObject();
173 }
174
hasModule(const std::string & moduleName) const175 bool JSIInteropModuleRegistry::hasModule(const std::string &moduleName) const {
176 return callHasModule(moduleName);
177 }
178
getModulesName() const179 jni::local_ref<jni::JArrayClass<jni::JString>> JSIInteropModuleRegistry::getModulesName() const {
180 return callGetJavaScriptModulesNames();
181 }
182
evaluateScript(jni::JString script)183 jni::local_ref<JavaScriptValue::javaobject> JSIInteropModuleRegistry::evaluateScript(
184 jni::JString script
185 ) {
186 return runtimeHolder->evaluateScript(script.toStdString());
187 }
188
global()189 jni::local_ref<JavaScriptObject::javaobject> JSIInteropModuleRegistry::global() {
190 return runtimeHolder->global();
191 }
192
createObject()193 jni::local_ref<JavaScriptObject::javaobject> JSIInteropModuleRegistry::createObject() {
194 return runtimeHolder->createObject();
195 }
196
drainJSEventLoop()197 void JSIInteropModuleRegistry::drainJSEventLoop() {
198 runtimeHolder->drainJSEventLoop();
199 }
200
registerSharedObject(jni::local_ref<jobject> native,jni::local_ref<JavaScriptObject::javaobject> js)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