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     runtime,
49     jsInvokerHolder->cthis()->getCallInvoker(),
50     nativeInvokerHolder->cthis()->getCallInvoker()
51   );
52 
53   auto expoModules = std::make_shared<ExpoModulesHostObject>(this);
54   auto expoModulesObject = jsi::Object::createFromHostObject(*runtime, expoModules);
55 
56   runtime
57     ->global()
58     .setProperty(
59       *runtime,
60       "ExpoModules",
61       std::move(expoModulesObject)
62     );
63 }
64 
65 void JSIInteropModuleRegistry::installJSIForTests() {
66 #if !UNIT_TEST
67   throw std::logic_error("The function is only avaiable when UNIT_TEST is defined.");
68 #else
69   runtimeHolder = std::make_shared<JavaScriptRuntime>();
70   jsi::Runtime &jsiRuntime = runtimeHolder->get();
71 
72   jsRegistry = std::make_unique<JSReferencesCache>(jsiRuntime);
73 
74   auto expoModules = std::make_shared<ExpoModulesHostObject>(this);
75   auto expoModulesObject = jsi::Object::createFromHostObject(jsiRuntime, expoModules);
76 
77   jsiRuntime
78     .global()
79     .setProperty(
80       jsiRuntime,
81       "ExpoModules",
82       std::move(expoModulesObject)
83     );
84 #endif // !UNIT_TEST
85 }
86 
87 jni::local_ref<JavaScriptModuleObject::javaobject>
88 JSIInteropModuleRegistry::callGetJavaScriptModuleObjectMethod(const std::string &moduleName) const {
89   const static auto method = expo::JSIInteropModuleRegistry::javaClassLocal()
90     ->getMethod<jni::local_ref<JavaScriptModuleObject::javaobject>(
91       std::string)>(
92       "getJavaScriptModuleObject"
93     );
94 
95   return method(javaPart_, moduleName);
96 }
97 
98 jni::local_ref<jni::JArrayClass<jni::JString>>
99 JSIInteropModuleRegistry::callGetJavaScriptModulesNames() const {
100   const static auto method = expo::JSIInteropModuleRegistry::javaClassLocal()
101     ->getMethod<jni::local_ref<jni::JArrayClass<jni::JString>>()>(
102       "getJavaScriptModulesName"
103     );
104   return method(javaPart_);
105 }
106 
107 jni::local_ref<JavaScriptModuleObject::javaobject>
108 JSIInteropModuleRegistry::getModule(const std::string &moduleName) const {
109   return callGetJavaScriptModuleObjectMethod(moduleName);
110 }
111 
112 jni::local_ref<jni::JArrayClass<jni::JString>> JSIInteropModuleRegistry::getModulesName() const {
113   return callGetJavaScriptModulesNames();
114 }
115 
116 jni::local_ref<JavaScriptValue::javaobject> JSIInteropModuleRegistry::evaluateScript(
117   jni::JString script
118 ) {
119   return runtimeHolder->evaluateScript(script.toStdString());
120 }
121 
122 jni::local_ref<JavaScriptObject::javaobject> JSIInteropModuleRegistry::global() {
123   return runtimeHolder->global();
124 }
125 
126 jni::local_ref<JavaScriptObject::javaobject> JSIInteropModuleRegistry::createObject() {
127   return runtimeHolder->createObject();
128 }
129 
130 void JSIInteropModuleRegistry::drainJSEventLoop() {
131   runtimeHolder->drainJSEventLoop();
132 }
133 } // namespace expo
134