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