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   /**
60    * Gets names of all available modules.
61    */
62   jni::local_ref<jni::JArrayClass<jni::JString>> getModulesName() const;
63 
64   /**
65    * Exposes a `JavaScriptRuntime::evaluateScript` function to Kotlin
66    */
67   jni::local_ref<JavaScriptValue::javaobject> evaluateScript(jni::JString script);
68 
69   /**
70    * Exposes a `JavaScriptRuntime::global` function to Kotlin
71    */
72   jni::local_ref<JavaScriptObject::javaobject> global();
73 
74   /**
75    * Exposes a `JavaScriptRuntime::createObject` function to Kotlin
76    */
77   jni::local_ref<JavaScriptObject::javaobject> createObject();
78 
79   /**
80    * Exposes a `JavaScriptRuntime::drainJSEventLoop` function to Kotlin
81    */
82   void drainJSEventLoop();
83 
84   std::shared_ptr<react::CallInvoker> jsInvoker;
85   std::shared_ptr<react::CallInvoker> nativeInvoker;
86   std::shared_ptr<JavaScriptRuntime> runtimeHolder;
87   std::unique_ptr<JSReferencesCache> jsRegistry;
88 private:
89   friend HybridBase;
90   jni::global_ref<JSIInteropModuleRegistry::javaobject> javaPart_;
91 
92   explicit JSIInteropModuleRegistry(jni::alias_ref<jhybridobject> jThis);
93 
94   inline jni::local_ref<JavaScriptModuleObject::javaobject>
95   callGetJavaScriptModuleObjectMethod(const std::string &moduleName) const;
96 
97   inline jni::local_ref<jni::JArrayClass<jni::JString>> callGetJavaScriptModulesNames() const;
98 };
99 } // namespace expo
100