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    * Adds a shared object to the internal registry
87    * @param native part of the shared object
88    * @param js part of the shared object
89    */
90   void registerSharedObject(
91     jni::local_ref<jobject> native,
92     jni::local_ref<JavaScriptObject::javaobject> js
93   );
94 
95   /**
96    * Exposes a `JavaScriptRuntime::drainJSEventLoop` function to Kotlin
97    */
98   void drainJSEventLoop();
99 
100   std::shared_ptr<react::CallInvoker> jsInvoker;
101   std::shared_ptr<react::CallInvoker> nativeInvoker;
102   std::shared_ptr<JavaScriptRuntime> runtimeHolder;
103   std::unique_ptr<JSReferencesCache> jsRegistry;
104   jni::global_ref<JNIDeallocator::javaobject> jniDeallocator;
105 private:
106   friend HybridBase;
107   jni::global_ref<JSIInteropModuleRegistry::javaobject> javaPart_;
108 
109   explicit JSIInteropModuleRegistry(jni::alias_ref<jhybridobject> jThis);
110 
111   inline jni::local_ref<JavaScriptModuleObject::javaobject>
112   callGetJavaScriptModuleObjectMethod(const std::string &moduleName) const;
113 
114   inline jni::local_ref<jni::JArrayClass<jni::JString>> callGetJavaScriptModulesNames() const;
115 
116   inline bool callHasModule(const std::string &moduleName) const;
117 };
118 } // namespace expo
119