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 class JavaScriptModuleObject; 25 26 void decorateObjectWithFunctions( 27 jsi::Runtime &runtime, 28 JSIInteropModuleRegistry *jsiInteropModuleRegistry, 29 jsi::Object *jsObject, 30 JavaScriptModuleObject *objectData 31 ); 32 33 void decorateObjectWithProperties( 34 jsi::Runtime &runtime, 35 JSIInteropModuleRegistry *jsiInteropModuleRegistry, 36 jsi::Object *jsObject, 37 JavaScriptModuleObject *objectData 38 ); 39 40 void decorateObjectWithConstants( 41 jsi::Runtime &runtime, 42 JSIInteropModuleRegistry *jsiInteropModuleRegistry, 43 jsi::Object *jsObject, 44 JavaScriptModuleObject *objectData 45 ); 46 47 /** 48 * A CPP part of the module. 49 * 50 * Right now objects of this class are stored by the ModuleHolder to ensure they will live 51 * as long as the RN context. 52 */ 53 class JavaScriptModuleObject : public jni::HybridClass<JavaScriptModuleObject> { 54 public: 55 static auto constexpr 56 kJavaDescriptor = "Lexpo/modules/kotlin/jni/JavaScriptModuleObject;"; 57 static auto constexpr TAG = "JavaScriptModuleObject"; 58 59 static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jhybridobject> jThis); 60 61 static void registerNatives(); 62 63 /** 64 * Pointer to the module registry interop. 65 */ 66 JSIInteropModuleRegistry *jsiInteropModuleRegistry; 67 68 /** 69 * Returns a cached instance of jsi::Object representing this module. 70 * @param runtime 71 * @return Wrapped instance of JavaScriptModuleObject::HostObject 72 */ 73 std::shared_ptr<jsi::Object> getJSIObject(jsi::Runtime &runtime); 74 75 /** 76 * Exports constants that will be assigned to the underlying HostObject. 77 */ 78 void exportConstants(jni::alias_ref<react::NativeMap::javaobject> constants); 79 80 /** 81 * Registers a sync function. 82 * That function can be called via the `JavaScriptModuleObject.callSyncMethod` method. 83 */ 84 void registerSyncFunction( 85 jni::alias_ref<jstring> name, 86 jboolean takesOwner, 87 jint args, 88 jni::alias_ref<jni::JArrayClass<ExpectedType>> expectedArgTypes, 89 jni::alias_ref<JNIFunctionBody::javaobject> body 90 ); 91 92 /** 93 * Registers a async function. 94 * That function can be called via the `JavaScriptModuleObject.callAsyncMethod` method. 95 */ 96 void registerAsyncFunction( 97 jni::alias_ref<jstring> name, 98 jboolean takesOwner, 99 jint args, 100 jni::alias_ref<jni::JArrayClass<ExpectedType>> expectedArgTypes, 101 jni::alias_ref<JNIAsyncFunctionBody::javaobject> body 102 ); 103 104 void registerClass( 105 jni::alias_ref<jstring> name, 106 jni::alias_ref<JavaScriptModuleObject::javaobject> classObject 107 ); 108 109 /** 110 * Registers a property 111 * @param name of the property 112 * @param desiredType of the setter argument 113 * @param getter body for the get method - can be nullptr 114 * @param setter body for the set method - can be nullptr 115 */ 116 void registerProperty( 117 jni::alias_ref<jstring> name, 118 jni::alias_ref<ExpectedType> expectedArgType, 119 jni::alias_ref<JNIFunctionBody::javaobject> getter, 120 jni::alias_ref<JNIFunctionBody::javaobject> setter 121 ); 122 123 private: 124 explicit JavaScriptModuleObject(jni::alias_ref<jhybridobject> jThis); 125 126 private: 127 friend HybridBase; 128 129 friend void decorateObjectWithFunctions( 130 jsi::Runtime &runtime, 131 JSIInteropModuleRegistry *jsiInteropModuleRegistry, 132 jsi::Object *jsObject, 133 JavaScriptModuleObject *objectData 134 ); 135 136 friend void decorateObjectWithProperties( 137 jsi::Runtime &runtime, 138 JSIInteropModuleRegistry *jsiInteropModuleRegistry, 139 jsi::Object *jsObject, 140 JavaScriptModuleObject *objectData 141 ); 142 143 friend void decorateObjectWithConstants( 144 jsi::Runtime &runtime, 145 JSIInteropModuleRegistry *jsiInteropModuleRegistry, 146 jsi::Object *jsObject, 147 JavaScriptModuleObject *objectData 148 ); 149 150 /** 151 * A reference to the `jsi::Object`. 152 * Simple we cached that value to return the same object each time. 153 * It's a weak reference because the JS runtime holds the actual object. 154 * Doing that allows the runtime to deallocate jsi::Object if it's not needed anymore. 155 */ 156 std::weak_ptr<jsi::Object> jsiObject; 157 jni::global_ref<JavaScriptModuleObject::javaobject> javaPart_; 158 159 /** 160 * Metadata map that stores information about all available methods on this module. 161 */ 162 std::unordered_map<std::string, MethodMetadata> methodsMetadata; 163 164 /** 165 * A constants map. 166 */ 167 std::unordered_map<std::string, folly::dynamic> constants; 168 169 /** 170 * A registry of properties 171 * The first MethodMetadata points to the getter and the second one to the setter. 172 */ 173 std::map<std::string, std::pair<MethodMetadata, MethodMetadata>> properties; 174 175 /** 176 * The `LongLivedObjectCollection` to hold `LongLivedObject` (callbacks or promises) for this module. 177 */ 178 std::shared_ptr<react::LongLivedObjectCollection> longLivedObjectCollection_; 179 180 std::map<std::string, jni::global_ref<JavaScriptModuleObject::javaobject>> classes; 181 }; 182 } // namespace expo 183