1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo) 2 3 #pragma once 4 5 #include <fbjni/fbjni.h> 6 #include <jsi/jsi.h> 7 #include <react/bridging/LongLivedObject.h> 8 #include <react/jni/ReadableNativeArray.h> 9 #include <jni/JCallback.h> 10 11 #include <unordered_map> 12 13 #include "MethodMetadata.h" 14 #include "JNIFunctionBody.h" 15 #include "types/ExpectedType.h" 16 17 namespace jni = facebook::jni; 18 namespace jsi = facebook::jsi; 19 namespace react = facebook::react; 20 21 namespace expo { 22 class JSIInteropModuleRegistry; 23 24 /** 25 * A CPP part of the module. 26 * 27 * Right now objects of this class are stored by the ModuleHolder to ensure they will live 28 * as long as the RN context. 29 */ 30 class JavaScriptModuleObject : public jni::HybridClass<JavaScriptModuleObject> { 31 public: 32 static auto constexpr 33 kJavaDescriptor = "Lexpo/modules/kotlin/jni/JavaScriptModuleObject;"; 34 static auto constexpr TAG = "JavaScriptModuleObject"; 35 36 static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jhybridobject> jThis); 37 38 static void registerNatives(); 39 40 /** 41 * Pointer to the module registry interop. 42 */ 43 JSIInteropModuleRegistry *jsiInteropModuleRegistry; 44 45 /** 46 * Returns a cached instance of jsi::Object representing this module. 47 * @param runtime 48 * @return Wrapped instance of JavaScriptModuleObject::HostObject 49 */ 50 std::shared_ptr<jsi::Object> getJSIObject(jsi::Runtime &runtime); 51 52 /** 53 * Exports constants that will be assigned to the underlying HostObject. 54 */ 55 void exportConstants(jni::alias_ref<react::NativeMap::javaobject> constants); 56 57 /** 58 * Registers a sync function. 59 * That function can be called via the `JavaScriptModuleObject.callSyncMethod` method. 60 */ 61 void registerSyncFunction( 62 jni::alias_ref<jstring> name, 63 jint args, 64 jni::alias_ref<jni::JArrayClass<ExpectedType>> expectedArgTypes, 65 jni::alias_ref<JNIFunctionBody::javaobject> body 66 ); 67 68 /** 69 * Registers a async function. 70 * That function can be called via the `JavaScriptModuleObject.callAsyncMethod` method. 71 */ 72 void registerAsyncFunction( 73 jni::alias_ref<jstring> name, 74 jint args, 75 jni::alias_ref<jni::JArrayClass<ExpectedType>> expectedArgTypes, 76 jni::alias_ref<JNIAsyncFunctionBody::javaobject> body 77 ); 78 79 /** 80 * Registers a property 81 * @param name of the property 82 * @param desiredType of the setter argument 83 * @param getter body for the get method - can be nullptr 84 * @param setter body for the set method - can be nullptr 85 */ 86 void registerProperty( 87 jni::alias_ref<jstring> name, 88 jni::alias_ref<ExpectedType> expectedArgType, 89 jni::alias_ref<JNIFunctionBody::javaobject> getter, 90 jni::alias_ref<JNIFunctionBody::javaobject> setter 91 ); 92 93 private: 94 explicit JavaScriptModuleObject(jni::alias_ref<jhybridobject> jThis); 95 96 private: 97 friend HybridBase; 98 /** 99 * A reference to the `jsi::Object`. 100 * Simple we cached that value to return the same object each time. 101 * It's a weak reference because the JS runtime holds the actual object. 102 * Doing that allows the runtime to deallocate jsi::Object if it's not needed anymore. 103 */ 104 std::weak_ptr<jsi::Object> jsiObject; 105 jni::global_ref<JavaScriptModuleObject::javaobject> javaPart_; 106 107 /** 108 * Metadata map that stores information about all available methods on this module. 109 */ 110 std::unordered_map<std::string, MethodMetadata> methodsMetadata; 111 112 /** 113 * A constants map. 114 */ 115 std::unordered_map<std::string, folly::dynamic> constants; 116 117 /** 118 * A registry of properties 119 * The first MethodMetadata points to the getter and the second one to the setter. 120 */ 121 std::map<std::string, std::pair<MethodMetadata, MethodMetadata>> properties; 122 123 /** 124 * The `LongLivedObjectCollection` to hold `LongLivedObject` (callbacks or promises) for this module. 125 */ 126 std::shared_ptr<react::LongLivedObjectCollection> longLivedObjectCollection_; 127 }; 128 } // namespace expo 129