1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo) 2 3 #pragma once 4 5 #include "types/CppType.h" 6 #include "types/ExpectedType.h" 7 #include "types/AnyType.h" 8 9 #include <jsi/jsi.h> 10 #include <fbjni/fbjni.h> 11 #include <ReactCommon/TurboModuleUtils.h> 12 #include <react/bridging/LongLivedObject.h> 13 #include <react/jni/ReadableNativeArray.h> 14 #include <memory> 15 #include <vector> 16 #include <folly/dynamic.h> 17 #include <jsi/JSIDynamic.h> 18 19 namespace jni = facebook::jni; 20 namespace jsi = facebook::jsi; 21 namespace react = facebook::react; 22 23 namespace expo { 24 class JSIInteropModuleRegistry; 25 26 /** 27 * A class that holds information about the exported function. 28 */ 29 class MethodMetadata { 30 public: 31 /** 32 * Function name 33 */ 34 std::string name; 35 /** 36 * Whether this function takes owner 37 */ 38 bool takesOwner; 39 /** 40 * Number of arguments 41 */ 42 int args; 43 /** 44 * Whether this function is async 45 */ 46 bool isAsync; 47 /** 48 * Representation of expected argument types. 49 */ 50 std::vector<std::unique_ptr<AnyType>> argTypes; 51 52 MethodMetadata( 53 std::weak_ptr<react::LongLivedObjectCollection> longLivedObjectCollection, 54 std::string name, 55 bool takesOwner, 56 int args, 57 bool isAsync, 58 jni::local_ref<jni::JArrayClass<ExpectedType>> expectedArgTypes, 59 jni::global_ref<jobject> &&jBodyReference 60 ); 61 62 MethodMetadata( 63 std::weak_ptr<react::LongLivedObjectCollection> longLivedObjectCollection, 64 std::string name, 65 bool takesOwner, 66 int args, 67 bool isAsync, 68 std::vector<std::unique_ptr<AnyType>> &&expectedArgTypes, 69 jni::global_ref<jobject> &&jBodyReference 70 ); 71 72 // We deleted the copy contractor to not deal with transforming the ownership of the `jBodyReference`. 73 MethodMetadata(const MethodMetadata &) = delete; 74 75 MethodMetadata(MethodMetadata &&other) = default; 76 77 /** 78 * Transforms metadata to a jsi::Function. 79 * 80 * @param runtime 81 * @param moduleRegistry 82 * @return shared ptr to the jsi::Function that wrapped the underlying Kotlin's function. 83 */ 84 std::shared_ptr<jsi::Function> toJSFunction( 85 jsi::Runtime &runtime, 86 JSIInteropModuleRegistry *moduleRegistry 87 ); 88 89 /** 90 * Calls the underlying Kotlin function. 91 */ 92 jsi::Value callSync( 93 jsi::Runtime &rt, 94 JSIInteropModuleRegistry *moduleRegistry, 95 const jsi::Value &thisValue, 96 const jsi::Value *args, 97 size_t count 98 ); 99 100 jni::local_ref<jobject> callJNISync( 101 JNIEnv *env, 102 jsi::Runtime &rt, 103 JSIInteropModuleRegistry *moduleRegistry, 104 const jsi::Value &thisValue, 105 const jsi::Value *args, 106 size_t count 107 ); 108 109 private: 110 /** 111 * Reference to one of two java objects - `JNIFunctionBody` or `JNIAsyncFunctionBody`. 112 * 113 * In case when `isAsync` is `true`, this variable will point to `JNIAsyncFunctionBody`. 114 * Otherwise to `JNIFunctionBody` 115 */ 116 jni::global_ref<jobject> jBodyReference; 117 118 /** 119 * To not create a jsi::Function always when we need it, we cached that value. 120 */ 121 std::shared_ptr<jsi::Function> body = nullptr; 122 123 std::weak_ptr<react::LongLivedObjectCollection> longLivedObjectCollection_; 124 125 jsi::Function toSyncFunction(jsi::Runtime &runtime, JSIInteropModuleRegistry *moduleRegistry); 126 127 jsi::Function toAsyncFunction(jsi::Runtime &runtime, JSIInteropModuleRegistry *moduleRegistry); 128 129 jsi::Function createPromiseBody( 130 jsi::Runtime &runtime, 131 JSIInteropModuleRegistry *moduleRegistry, 132 jobjectArray globalArgs 133 ); 134 135 jobjectArray convertJSIArgsToJNI( 136 JSIInteropModuleRegistry *moduleRegistry, 137 JNIEnv *env, 138 jsi::Runtime &rt, 139 const jsi::Value &thisValue, 140 const jsi::Value *args, 141 size_t count 142 ); 143 }; 144 } // namespace expo 145