1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo) 2 3 #pragma once 4 5 #include <jsi/jsi.h> 6 #include <fbjni/fbjni.h> 7 #include <ReactCommon/CallInvoker.h> 8 9 namespace jsi = facebook::jsi; 10 namespace jni = facebook::jni; 11 namespace react = facebook::react; 12 13 namespace expo { 14 class JavaScriptValue; 15 16 class JavaScriptObject; 17 18 class JSIInteropModuleRegistry; 19 20 /** 21 * Dummy CallInvoker that invokes everything immediately. 22 * Used in the test environment to check the async flow. 23 */ 24 class SyncCallInvoker : public react::CallInvoker { 25 public: 26 void invokeAsync(std::function<void()> &&func) override; 27 28 void invokeSync(std::function<void()> &&func) override; 29 30 ~SyncCallInvoker() override = default; 31 }; 32 33 /** 34 * A wrapper for the jsi::Runtime. 35 * This class is used as a bridge between CPP and Kotlin and to encapsulate common runtime helper functions. 36 * 37 * Instances of this class should be managed using a shared smart pointer. 38 * To pass runtime information to all of `JavaScriptValue` and `JavaScriptObject` we use `weak_from_this()` 39 * that requires that the object is held via a smart pointer. Otherwise, `weak_from_this()` returns `nullptr`. 40 */ 41 class JavaScriptRuntime : public std::enable_shared_from_this<JavaScriptRuntime> { 42 public: 43 /** 44 * Initializes a runtime that is independent from React Native and its runtime initialization. 45 * This flow is mostly intended for tests. The JS call invoker is set to `SyncCallInvoker`. 46 */ 47 JavaScriptRuntime( 48 JSIInteropModuleRegistry *jsiInteropModuleRegistry 49 ); 50 51 JavaScriptRuntime( 52 JSIInteropModuleRegistry *jsiInteropModuleRegistry, 53 jsi::Runtime *runtime, 54 std::shared_ptr<react::CallInvoker> jsInvoker, 55 std::shared_ptr<react::CallInvoker> nativeInvoker 56 ); 57 58 /** 59 * Returns the underlying runtime object. 60 */ 61 jsi::Runtime &get() const; 62 63 /** 64 * Evaluates given JavaScript source code. 65 * @throws if the input format is unknown, or evaluation causes an error, 66 * a jni::JniException<JavaScriptEvaluateException> will be thrown. 67 */ 68 jni::local_ref<jni::HybridClass<JavaScriptValue>::javaobject> evaluateScript( 69 const std::string &script 70 ); 71 72 /** 73 * Returns the runtime global object for use in Kotlin. 74 */ 75 jni::local_ref<jni::HybridClass<JavaScriptObject>::javaobject> global(); 76 77 /** 78 * Creates a new object for use in Kotlin. 79 */ 80 jni::local_ref<jni::HybridClass<JavaScriptObject>::javaobject> createObject(); 81 82 /** 83 * Drains the JavaScript VM internal Microtask (a.k.a. event loop) queue. 84 */ 85 void drainJSEventLoop(); 86 87 std::shared_ptr<react::CallInvoker> jsInvoker; 88 std::shared_ptr<react::CallInvoker> nativeInvoker; 89 90 std::shared_ptr<jsi::Object> getMainObject(); 91 92 JSIInteropModuleRegistry *getModuleRegistry(); 93 private: 94 std::shared_ptr<jsi::Runtime> runtime; 95 std::shared_ptr<jsi::Object> mainObject; 96 JSIInteropModuleRegistry *jsiInteropModuleRegistry; 97 98 void installMainObject(); 99 }; 100 } // namespace expo 101