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 /**
19  * Dummy CallInvoker that invokes everything immediately.
20  * Used in the test environment to check the async flow.
21  */
22 class SyncCallInvoker : public react::CallInvoker {
23 public:
24   void invokeAsync(std::function<void()> &&func) override;
25 
26   void invokeSync(std::function<void()> &&func) override;
27 
28   ~SyncCallInvoker() override = default;
29 };
30 
31 /**
32  * A wrapper for the jsi::Runtime.
33  * This class is used as a bridge between CPP and Kotlin and to encapsulate common runtime helper functions.
34  *
35  * Instances of this class should be managed using a shared smart pointer.
36  * To pass runtime information to all of `JavaScriptValue` and `JavaScriptObject` we use `weak_from_this()`
37  * that requires that the object is held via a smart pointer. Otherwise, `weak_from_this()` returns `nullptr`.
38  */
39 class JavaScriptRuntime : public std::enable_shared_from_this<JavaScriptRuntime> {
40 public:
41   /**
42    * Initializes a runtime that is independent from React Native and its runtime initialization.
43    * This flow is mostly intended for tests. The JS call invoker is set to `SyncCallInvoker`.
44    */
45   JavaScriptRuntime();
46 
47   JavaScriptRuntime(
48     jsi::Runtime *runtime,
49     std::shared_ptr<react::CallInvoker> jsInvoker,
50     std::shared_ptr<react::CallInvoker> nativeInvoker
51   );
52 
53   /**
54    * Returns the underlying runtime object.
55    */
56   jsi::Runtime &get() const;
57 
58   /**
59    * Evaluates given JavaScript source code.
60    * @throws if the input format is unknown, or evaluation causes an error,
61    * a jni::JniException<JavaScriptEvaluateException> will be thrown.
62    */
63   jni::local_ref<jni::HybridClass<JavaScriptValue>::javaobject> evaluateScript(
64     const std::string &script
65   );
66 
67   /**
68    * Returns the runtime global object for use in Kotlin.
69    */
70   jni::local_ref<jni::HybridClass<JavaScriptObject>::javaobject> global();
71 
72   /**
73    * Creates a new object for use in Kotlin.
74    */
75   jni::local_ref<jni::HybridClass<JavaScriptObject>::javaobject> createObject();
76 
77   /**
78    * Drains the JavaScript VM internal Microtask (a.k.a. event loop) queue.
79    */
80   void drainJSEventLoop();
81 
82   std::shared_ptr<react::CallInvoker> jsInvoker;
83   std::shared_ptr<react::CallInvoker> nativeInvoker;
84 private:
85   std::shared_ptr<jsi::Runtime> runtime;
86 };
87 } // namespace expo
88