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