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