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