1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2 
3 #pragma once
4 
5 #include "JavaScriptRuntime.h"
6 #include "JavaScriptModuleObject.h"
7 #include "JavaScriptValue.h"
8 #include "JavaScriptObject.h"
9 #include "JavaReferencesCache.h"
10 #include "JSReferencesCache.h"
11 #include "JNIDeallocator.h"
12 
13 #include <fbjni/fbjni.h>
14 #include <jsi/jsi.h>
15 #include <ReactCommon/CallInvokerHolder.h>
16 #include <ReactCommon/CallInvoker.h>
17 #if REACT_NATIVE_TARGET_VERSION >= 73
18 #include <ReactCommon/NativeMethodCallInvokerHolder.h>
19 #endif
20 
21 #include <memory>
22 
23 namespace jni = facebook::jni;
24 namespace jsi = facebook::jsi;
25 namespace react = facebook::react;
26 
27 namespace expo {
28 
29 #if REACT_NATIVE_TARGET_VERSION >= 73
30 using NativeMethodCallInvokerHolderCompatible = react::NativeMethodCallInvokerHolder;
31 #else
32 using NativeMethodCallInvokerHolderCompatible = react::CallInvokerHolder;
33 #endif
34 
35 /**
36  * A JNI wrapper to initialize CPP part of modules and access all data from the module registry.
37  */
38 class JSIInteropModuleRegistry : public jni::HybridClass<JSIInteropModuleRegistry> {
39 public:
40   static auto constexpr
41     kJavaDescriptor = "Lexpo/modules/kotlin/jni/JSIInteropModuleRegistry;";
42   static auto constexpr TAG = "JSIInteropModuleRegistry";
43 
44   static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jhybridobject> jThis);
45 
46   static void registerNatives();
47 
48   /**
49    * Initializes the `ExpoModulesHostObject` and adds it to the global object.
50    */
51   void installJSI(
52     jlong jsRuntimePointer,
53     jni::alias_ref<JNIDeallocator::javaobject> jniDeallocator,
54     jni::alias_ref<react::CallInvokerHolder::javaobject> jsInvokerHolder,
55     jni::alias_ref<NativeMethodCallInvokerHolderCompatible::javaobject> nativeInvokerHolder
56   );
57 
58   /**
59    * Initializes the test runtime. Shouldn't be used in the production.
60    */
61   void installJSIForTests(
62     jni::alias_ref<JNIDeallocator::javaobject> jniDeallocator
63   );
64 
65   /**
66    * Gets a module for a given name. It will throw an exception if the module doesn't exist.
67    *
68    * @param moduleName
69    * @return An instance of `JavaScriptModuleObject`
70    */
71   jni::local_ref<JavaScriptModuleObject::javaobject> getModule(const std::string &moduleName) const;
72 
73   bool hasModule(const std::string &moduleName) const;
74 
75   /**
76    * Gets names of all available modules.
77    */
78   jni::local_ref<jni::JArrayClass<jni::JString>> getModulesName() const;
79 
80   /**
81    * Exposes a `JavaScriptRuntime::evaluateScript` function to Kotlin
82    */
83   jni::local_ref<JavaScriptValue::javaobject> evaluateScript(jni::JString script);
84 
85   /**
86    * Exposes a `JavaScriptRuntime::global` function to Kotlin
87    */
88   jni::local_ref<JavaScriptObject::javaobject> global();
89 
90   /**
91    * Exposes a `JavaScriptRuntime::createObject` function to Kotlin
92    */
93   jni::local_ref<JavaScriptObject::javaobject> createObject();
94 
95   /**
96   * Gets a core module.
97   */
98   jni::local_ref<JavaScriptModuleObject::javaobject> getCoreModule() const;
99 
100   /**
101    * Adds a shared object to the internal registry
102    * @param native part of the shared object
103    * @param js part of the shared object
104    */
105   void registerSharedObject(
106     jni::local_ref<jobject> native,
107     jni::local_ref<JavaScriptObject::javaobject> js
108   );
109 
110   /**
111    * Exposes a `JavaScriptRuntime::drainJSEventLoop` function to Kotlin
112    */
113   void drainJSEventLoop();
114 
115   std::shared_ptr<react::CallInvoker> jsInvoker;
116   std::shared_ptr<react::CallInvoker> nativeInvoker;
117   std::shared_ptr<JavaScriptRuntime> runtimeHolder;
118   std::unique_ptr<JSReferencesCache> jsRegistry;
119   jni::global_ref<JNIDeallocator::javaobject> jniDeallocator;
120 private:
121   friend HybridBase;
122   jni::global_ref<JSIInteropModuleRegistry::javaobject> javaPart_;
123 
124   explicit JSIInteropModuleRegistry(jni::alias_ref<jhybridobject> jThis);
125 
126   inline jni::local_ref<JavaScriptModuleObject::javaobject>
127   callGetJavaScriptModuleObjectMethod(const std::string &moduleName) const;
128 
129   inline jni::local_ref<jni::JArrayClass<jni::JString>> callGetJavaScriptModulesNames() const;
130 
131   inline jni::local_ref<JavaScriptModuleObject::javaobject> callGetCoreModuleObject() const;
132 
133   inline bool callHasModule(const std::string &moduleName) const;
134 };
135 } // namespace expo
136