expo-modules-core 1.2.7 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/CHANGELOG.md +28 -5
  2. package/ExpoModulesCore.podspec +1 -0
  3. package/README.md +1 -1
  4. package/android/ExpoModulesCorePlugin.gradle +16 -0
  5. package/android/build.gradle +3 -2
  6. package/android/src/main/cpp/Exceptions.cpp +8 -0
  7. package/android/src/main/cpp/Exceptions.h +11 -0
  8. package/android/src/main/cpp/ExpoModulesHostObject.cpp +22 -5
  9. package/android/src/main/cpp/ExpoModulesHostObject.h +5 -0
  10. package/android/src/main/cpp/JNIInjector.cpp +2 -0
  11. package/android/src/main/cpp/JSIInteropModuleRegistry.cpp +25 -1
  12. package/android/src/main/cpp/JSIInteropModuleRegistry.h +14 -0
  13. package/android/src/main/cpp/JSIObjectWrapper.h +15 -4
  14. package/android/src/main/cpp/JSITypeConverter.h +3 -2
  15. package/android/src/main/cpp/JavaReferencesCache.cpp +2 -0
  16. package/android/src/main/cpp/JavaScriptFunction.cpp +56 -0
  17. package/android/src/main/cpp/JavaScriptFunction.h +54 -0
  18. package/android/src/main/cpp/JavaScriptModuleObject.cpp +225 -105
  19. package/android/src/main/cpp/JavaScriptModuleObject.h +67 -34
  20. package/android/src/main/cpp/JavaScriptObject.cpp +55 -1
  21. package/android/src/main/cpp/JavaScriptObject.h +17 -13
  22. package/android/src/main/cpp/JavaScriptRuntime.cpp +12 -3
  23. package/android/src/main/cpp/JavaScriptRuntime.h +9 -1
  24. package/android/src/main/cpp/JavaScriptValue.cpp +9 -0
  25. package/android/src/main/cpp/JavaScriptValue.h +4 -0
  26. package/android/src/main/cpp/MethodMetadata.cpp +66 -87
  27. package/android/src/main/cpp/MethodMetadata.h +18 -16
  28. package/android/src/main/cpp/ObjectDeallocator.h +25 -0
  29. package/android/src/main/cpp/WeakRuntimeHolder.cpp +7 -0
  30. package/android/src/main/cpp/WeakRuntimeHolder.h +4 -0
  31. package/android/src/main/cpp/types/CppType.h +4 -1
  32. package/android/src/main/cpp/types/FrontendConverter.cpp +58 -0
  33. package/android/src/main/cpp/types/FrontendConverter.h +45 -0
  34. package/android/src/main/cpp/types/FrontendConverterProvider.cpp +3 -0
  35. package/android/src/main/cpp/types/JNIToJSIConverter.cpp +88 -0
  36. package/android/src/main/cpp/types/JNIToJSIConverter.h +22 -0
  37. package/android/src/main/java/com/facebook/react/uimanager/ReactStylesDiffMapHelper.kt +10 -0
  38. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +8 -25
  39. package/android/src/main/java/expo/modules/kotlin/FilteredIterator.kt +37 -0
  40. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +1 -1
  41. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +30 -23
  42. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +0 -3
  43. package/android/src/main/java/expo/modules/kotlin/Utils.kt +21 -0
  44. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultCaller.kt +21 -1
  45. package/android/src/main/java/expo/modules/kotlin/classcomponent/ClassComponentBuilder.kt +112 -0
  46. package/android/src/main/java/expo/modules/kotlin/classcomponent/ClassDefinitionData.kt +10 -0
  47. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +21 -0
  48. package/android/src/main/java/expo/modules/kotlin/exception/CommonExceptions.kt +15 -0
  49. package/android/src/main/java/expo/modules/kotlin/functions/AnyFunction.kt +17 -3
  50. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +38 -8
  51. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionComponent.kt +3 -2
  52. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt +3 -2
  53. package/android/src/main/java/expo/modules/kotlin/functions/SuspendFunctionComponent.kt +1 -0
  54. package/android/src/main/java/expo/modules/kotlin/functions/SyncFunctionComponent.kt +18 -11
  55. package/android/src/main/java/expo/modules/kotlin/jni/CppType.kt +4 -1
  56. package/android/src/main/java/expo/modules/kotlin/jni/JNIDeallocator.kt +73 -0
  57. package/android/src/main/java/expo/modules/kotlin/jni/JSIInteropModuleRegistry.kt +28 -2
  58. package/android/src/main/java/expo/modules/kotlin/jni/JavaCallback.kt +8 -1
  59. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptFunction.kt +48 -0
  60. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptModuleObject.kt +40 -3
  61. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptObject.kt +23 -3
  62. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptValue.kt +26 -1
  63. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +0 -11
  64. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +26 -16
  65. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +3 -1
  66. package/android/src/main/java/expo/modules/kotlin/sharedobjects/SharedObject.kt +12 -0
  67. package/android/src/main/java/expo/modules/kotlin/sharedobjects/SharedObjectRegistry.kt +62 -0
  68. package/android/src/main/java/expo/modules/kotlin/sharedobjects/SharedObjectTypeConverter.kt +27 -0
  69. package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +2 -1
  70. package/android/src/main/java/expo/modules/kotlin/types/EitherTypeConverter.kt +7 -6
  71. package/android/src/main/java/expo/modules/kotlin/types/JavaScriptFunctionTypeConverter.kt +22 -0
  72. package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +30 -24
  73. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +45 -1
  74. package/android/src/main/java/expo/modules/kotlin/types/TypedArrayTypeConverter.kt +3 -2
  75. package/android/src/main/java/expo/modules/kotlin/views/AnyViewProp.kt +3 -1
  76. package/android/src/main/java/expo/modules/kotlin/views/ConcreteViewProp.kt +3 -3
  77. package/android/src/main/java/expo/modules/kotlin/views/FilteredReadableMap.kt +53 -0
  78. package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +25 -5
  79. package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +25 -5
  80. package/android/src/main/java/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +161 -10
  81. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +0 -67
  82. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +6 -7
  83. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +40 -3
  84. package/android/src/main/java/expo/modules/kotlin/views/ViewTypeConverter.kt +44 -0
  85. package/android-annotation/build.gradle +45 -0
  86. package/android-annotation/src/main/java/expo/modules/annotation/Config.kt +7 -0
  87. package/android-annotation/src/main/java/expo/modules/annotation/ConverterBinder.kt +7 -0
  88. package/android-annotation-processor/build.gradle +51 -0
  89. package/android-annotation-processor/src/main/java/expo/modules/annotationprocessor/ExpoSymbolProcessor.kt +175 -0
  90. package/android-annotation-processor/src/main/java/expo/modules/annotationprocessor/ExpoSymbolProcessorProvider.kt +10 -0
  91. package/android-annotation-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider +1 -0
  92. package/build/NativeViewManagerAdapter.native.d.ts.map +1 -1
  93. package/build/NativeViewManagerAdapter.native.js +36 -23
  94. package/build/NativeViewManagerAdapter.native.js.map +1 -1
  95. package/build/requireNativeModule.js +2 -2
  96. package/build/requireNativeModule.js.map +1 -1
  97. package/common/cpp/fabric/ExpoViewProps.cpp +18 -3
  98. package/common/cpp/fabric/ExpoViewProps.h +4 -1
  99. package/ios/Fabric/ExpoFabricView.swift +10 -10
  100. package/ios/Fabric/ExpoFabricViewObjC.h +2 -0
  101. package/ios/Fabric/ExpoFabricViewObjC.mm +17 -2
  102. package/ios/JSI/EXJSIInstaller.mm +1 -1
  103. package/ios/JSI/EXJSIUtils.h +5 -0
  104. package/ios/JSI/EXJSIUtils.mm +17 -0
  105. package/ios/JSI/EXJavaScriptRuntime.h +5 -0
  106. package/ios/JSI/EXJavaScriptRuntime.mm +6 -0
  107. package/ios/JSI/EXJavaScriptValue.h +2 -0
  108. package/ios/JSI/EXJavaScriptValue.mm +8 -0
  109. package/ios/JSI/EXJavaScriptWeakObject.mm +29 -8
  110. package/ios/JSI/EXRawJavaScriptFunction.h +24 -0
  111. package/ios/JSI/EXRawJavaScriptFunction.mm +52 -0
  112. package/ios/JSI/ExpoModulesHostObject.mm +1 -1
  113. package/ios/JSI/JavaScriptValue.swift +28 -1
  114. package/ios/ModuleRegistry/EXModuleRegistry.h +0 -4
  115. package/ios/ModuleRegistry/EXModuleRegistry.m +0 -23
  116. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +0 -16
  117. package/ios/ModuleRegistryProvider/EXModuleRegistryProvider.m +0 -6
  118. package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +1 -31
  119. package/ios/Swift/AppContext.swift +46 -6
  120. package/ios/Swift/Arguments/Convertible.swift +3 -3
  121. package/ios/Swift/Arguments/Convertibles.swift +5 -5
  122. package/ios/Swift/Classes/ClassComponent.swift +18 -12
  123. package/ios/Swift/Classes/ClassRegistry.swift +31 -0
  124. package/ios/Swift/Conversions.swift +19 -3
  125. package/ios/Swift/Convertibles/Convertibles+Color.swift +3 -3
  126. package/ios/Swift/Convertibles/Either.swift +6 -4
  127. package/ios/Swift/DynamicTypes/AnyDynamicType.swift +18 -2
  128. package/ios/Swift/DynamicTypes/DynamicArrayType.swift +3 -3
  129. package/ios/Swift/DynamicTypes/DynamicConvertibleType.swift +2 -2
  130. package/ios/Swift/DynamicTypes/DynamicEnumType.swift +1 -1
  131. package/ios/Swift/DynamicTypes/DynamicJavaScriptType.swift +27 -0
  132. package/ios/Swift/DynamicTypes/DynamicOptionalType.swift +9 -2
  133. package/ios/Swift/DynamicTypes/DynamicRawType.swift +1 -1
  134. package/ios/Swift/DynamicTypes/DynamicSharedObjectType.swift +16 -2
  135. package/ios/Swift/DynamicTypes/DynamicType.swift +6 -0
  136. package/ios/Swift/DynamicTypes/DynamicTypedArrayType.swift +15 -4
  137. package/ios/Swift/DynamicTypes/DynamicViewType.swift +68 -0
  138. package/ios/Swift/ExpoBridgeModule.swift +1 -1
  139. package/ios/Swift/Functions/AnyFunction.swift +5 -4
  140. package/ios/Swift/Functions/AsyncFunctionComponent.swift +22 -19
  141. package/ios/Swift/Functions/ConcurrentFunctionDefinition.swift +29 -13
  142. package/ios/Swift/Functions/SyncFunctionComponent.swift +26 -15
  143. package/ios/Swift/JavaScriptFunction.swift +68 -0
  144. package/ios/Swift/JavaScriptUtils.swift +57 -18
  145. package/ios/Swift/ModuleHolder.swift +22 -10
  146. package/ios/Swift/Modules/ModuleDefinition.swift +8 -2
  147. package/ios/Swift/Objects/JavaScriptObjectBuilder.swift +8 -8
  148. package/ios/Swift/Objects/ObjectDefinition.swift +17 -15
  149. package/ios/Swift/Objects/PropertyComponent.swift +23 -17
  150. package/ios/Swift/Records/AnyField.swift +1 -1
  151. package/ios/Swift/Records/Field.swift +2 -2
  152. package/ios/Swift/Records/Record.swift +5 -5
  153. package/ios/Swift/SharedObjects/SharedObjectRegistry.swift +4 -0
  154. package/ios/Swift/Views/AnyViewProp.swift +1 -1
  155. package/ios/Swift/Views/ComponentData.swift +37 -2
  156. package/ios/Swift/Views/ConcreteViewProp.swift +2 -2
  157. package/ios/Swift/Views/ViewDefinition.swift +39 -0
  158. package/ios/Swift/Views/ViewModuleWrapper.swift +0 -29
  159. package/ios/Tests/ClassComponentSpec.swift +39 -27
  160. package/ios/Tests/ConvertiblesSpec.swift +75 -49
  161. package/ios/Tests/DynamicTypeSpec.swift +29 -27
  162. package/ios/Tests/EitherSpec.swift +9 -7
  163. package/ios/Tests/ExpoModulesSpec.swift +13 -13
  164. package/ios/Tests/FunctionSpec.swift +38 -22
  165. package/ios/Tests/JavaScriptRuntimeSpec.swift +4 -0
  166. package/ios/Tests/PropertyComponentSpec.swift +33 -30
  167. package/ios/Tests/RecordSpec.swift +7 -5
  168. package/ios/Tests/SharedObjectRegistrySpec.swift +12 -12
  169. package/ios/Tests/TypedArraysSpec.swift +1 -1
  170. package/ios/Tests/ViewDefinitionSpec.swift +4 -2
  171. package/package.json +2 -2
  172. package/src/NativeViewManagerAdapter.native.tsx +33 -29
  173. package/src/requireNativeModule.ts +2 -2
  174. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +0 -132
  175. package/ios/EXViewManager.h +0 -21
  176. package/ios/EXViewManager.m +0 -128
  177. package/ios/ModuleRegistryAdapter/EXViewManagerAdapterClassesRegistry.h +0 -17
  178. package/ios/ModuleRegistryAdapter/EXViewManagerAdapterClassesRegistry.m +0 -67
  179. package/ios/ViewManagerAdapter/EXViewManagerAdapter.h +0 -17
  180. package/ios/ViewManagerAdapter/EXViewManagerAdapter.m +0 -45
@@ -6,6 +6,7 @@
6
6
  #include "JSITypeConverter.h"
7
7
  #include "JavaScriptRuntime.h"
8
8
  #include "WeakRuntimeHolder.h"
9
+ #include "JNIFunctionBody.h"
9
10
 
10
11
  #include <fbjni/fbjni.h>
11
12
  #include <jsi/jsi.h>
@@ -18,6 +19,8 @@ namespace jsi = facebook::jsi;
18
19
  namespace expo {
19
20
  class JavaScriptValue;
20
21
 
22
+ class JavaScriptFunction;
23
+
21
24
  /**
22
25
  * Represents any JavaScript object. Its purpose is to exposes `jsi::Object` API back to Kotlin.
23
26
  */
@@ -61,6 +64,17 @@ public:
61
64
 
62
65
  static jsi::Object preparePropertyDescriptor(jsi::Runtime &jsRuntime, int options);
63
66
 
67
+ static void defineProperty(
68
+ jsi::Runtime &runtime,
69
+ jsi::Object *jsthis,
70
+ const std::string &name,
71
+ jsi::Object descriptor
72
+ );
73
+
74
+ void defineNativeDeallocator(
75
+ jni::alias_ref<JNIFunctionBody::javaobject> deallocator
76
+ );
77
+
64
78
  protected:
65
79
  WeakRuntimeHolder runtimeHolder;
66
80
  std::shared_ptr<jsi::Object> jsObject;
@@ -76,6 +90,8 @@ private:
76
90
 
77
91
  jni::local_ref<jni::JArrayClass<jstring>> jniGetPropertyNames();
78
92
 
93
+ jni::local_ref<jni::HybridClass<JavaScriptFunction>::javaobject> jniAsFunction();
94
+
79
95
  /**
80
96
  * Unsets property with the given name.
81
97
  */
@@ -114,21 +130,9 @@ private:
114
130
  jsi::Runtime &jsRuntime = runtimeHolder.getJSRuntime();
115
131
 
116
132
  auto cName = name->toStdString();
117
- jsi::Object global = jsRuntime.global();
118
- jsi::Object objectClass = global.getPropertyAsObject(jsRuntime, "Object");
119
- jsi::Function definePropertyFunction = objectClass.getPropertyAsFunction(
120
- jsRuntime,
121
- "defineProperty"
122
- );
123
133
  jsi::Object descriptor = preparePropertyDescriptor(jsRuntime, options);
124
-
125
134
  descriptor.setProperty(jsRuntime, "value", jsi_type_converter<T>::convert(jsRuntime, value));
126
-
127
- definePropertyFunction.callWithThis(jsRuntime, objectClass, {
128
- jsi::Value(jsRuntime, *jsObject),
129
- jsi::String::createFromUtf8(jsRuntime, cName),
130
- std::move(descriptor)
131
- });
135
+ JavaScriptObject::defineProperty(jsRuntime, jsObject.get(), cName, std::move(descriptor));
132
136
  }
133
137
  };
134
138
  } // namespace expo
@@ -4,6 +4,7 @@
4
4
  #include "JavaScriptValue.h"
5
5
  #include "JavaScriptObject.h"
6
6
  #include "Exceptions.h"
7
+ #include "JavaScriptRuntime.h"
7
8
 
8
9
  #if UNIT_TEST
9
10
 
@@ -37,9 +38,12 @@ void SyncCallInvoker::invokeSync(std::function<void()> &&func) {
37
38
  func();
38
39
  }
39
40
 
40
- JavaScriptRuntime::JavaScriptRuntime()
41
+ JavaScriptRuntime::JavaScriptRuntime(
42
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry
43
+ )
41
44
  : jsInvoker(std::make_shared<SyncCallInvoker>()),
42
- nativeInvoker(std::make_shared<SyncCallInvoker>()) {
45
+ nativeInvoker(std::make_shared<SyncCallInvoker>()),
46
+ jsiInteropModuleRegistry(jsiInteropModuleRegistry) {
43
47
  #if !UNIT_TEST
44
48
  throw std::logic_error(
45
49
  "The JavaScriptRuntime constructor is only avaiable when UNIT_TEST is defined.");
@@ -100,10 +104,12 @@ JavaScriptRuntime::JavaScriptRuntime()
100
104
  }
101
105
 
102
106
  JavaScriptRuntime::JavaScriptRuntime(
107
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry,
103
108
  jsi::Runtime *runtime,
104
109
  std::shared_ptr<react::CallInvoker> jsInvoker,
105
110
  std::shared_ptr<react::CallInvoker> nativeInvoker
106
- ) : jsInvoker(std::move(jsInvoker)), nativeInvoker(std::move(nativeInvoker)) {
111
+ ) : jsInvoker(std::move(jsInvoker)), nativeInvoker(std::move(nativeInvoker)),
112
+ jsiInteropModuleRegistry(jsiInteropModuleRegistry) {
107
113
  // Creating a shared pointer that points to the runtime but doesn't own it, thus doesn't release it.
108
114
  // In this code flow, the runtime should be owned by something else like the CatalystInstance.
109
115
  // See explanation for constructor (8): https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr
@@ -178,4 +184,7 @@ std::shared_ptr<jsi::Object> JavaScriptRuntime::getMainObject() {
178
184
  return mainObject;
179
185
  }
180
186
 
187
+ JSIInteropModuleRegistry *JavaScriptRuntime::getModuleRegistry() {
188
+ return jsiInteropModuleRegistry;
189
+ }
181
190
  } // namespace expo
@@ -15,6 +15,8 @@ class JavaScriptValue;
15
15
 
16
16
  class JavaScriptObject;
17
17
 
18
+ class JSIInteropModuleRegistry;
19
+
18
20
  /**
19
21
  * Dummy CallInvoker that invokes everything immediately.
20
22
  * Used in the test environment to check the async flow.
@@ -42,9 +44,12 @@ public:
42
44
  * Initializes a runtime that is independent from React Native and its runtime initialization.
43
45
  * This flow is mostly intended for tests. The JS call invoker is set to `SyncCallInvoker`.
44
46
  */
45
- JavaScriptRuntime();
47
+ JavaScriptRuntime(
48
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry
49
+ );
46
50
 
47
51
  JavaScriptRuntime(
52
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry,
48
53
  jsi::Runtime *runtime,
49
54
  std::shared_ptr<react::CallInvoker> jsInvoker,
50
55
  std::shared_ptr<react::CallInvoker> nativeInvoker
@@ -83,9 +88,12 @@ public:
83
88
  std::shared_ptr<react::CallInvoker> nativeInvoker;
84
89
 
85
90
  std::shared_ptr<jsi::Object> getMainObject();
91
+
92
+ JSIInteropModuleRegistry *getModuleRegistry();
86
93
  private:
87
94
  std::shared_ptr<jsi::Runtime> runtime;
88
95
  std::shared_ptr<jsi::Object> mainObject;
96
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry;
89
97
 
90
98
  void installMainObject();
91
99
  };
@@ -5,6 +5,7 @@
5
5
  #include "JavaScriptRuntime.h"
6
6
  #include "JavaScriptObject.h"
7
7
  #include "JavaScriptTypedArray.h"
8
+ #include "JavaScriptFunction.h"
8
9
  #include "TypedArray.h"
9
10
  #include "Exceptions.h"
10
11
 
@@ -28,6 +29,7 @@ void JavaScriptValue::registerNatives() {
28
29
  makeNativeMethod("getObject", JavaScriptValue::getObject),
29
30
  makeNativeMethod("getArray", JavaScriptValue::getArray),
30
31
  makeNativeMethod("getTypedArray", JavaScriptValue::getTypedArray),
32
+ makeNativeMethod("jniGetFunction", JavaScriptValue::jniGetFunction),
31
33
  });
32
34
  }
33
35
 
@@ -156,6 +158,13 @@ jni::local_ref<JavaScriptObject::javaobject> JavaScriptValue::getObject() {
156
158
  return JavaScriptObject::newObjectCxxArgs(runtimeHolder, jsObject);
157
159
  }
158
160
 
161
+ jni::local_ref<JavaScriptFunction::javaobject> JavaScriptValue::jniGetFunction() {
162
+ auto &jsRuntime = runtimeHolder.getJSRuntime();
163
+ auto jsFunction = std::make_shared<jsi::Function>(
164
+ jsValue->getObject(jsRuntime).asFunction(jsRuntime));
165
+ return JavaScriptFunction::newObjectCxxArgs(runtimeHolder, jsFunction);
166
+ }
167
+
159
168
  jni::local_ref<jni::JArrayClass<JavaScriptValue::javaobject>> JavaScriptValue::getArray() {
160
169
  auto &jsRuntime = runtimeHolder.getJSRuntime();
161
170
 
@@ -21,6 +21,8 @@ class JavaScriptObject;
21
21
 
22
22
  class JavaScriptTypedArray;
23
23
 
24
+ class JavaScriptFunction;
25
+
24
26
  /**
25
27
  * Represents any JavaScript value. Its purpose is to expose the `jsi::Value` API back to Kotlin.
26
28
  */
@@ -78,6 +80,8 @@ public:
78
80
 
79
81
  jni::local_ref<JavaScriptTypedArray::javaobject> getTypedArray();
80
82
 
83
+ jni::local_ref<jni::HybridClass<JavaScriptFunction>::javaobject> jniGetFunction();
84
+
81
85
  private:
82
86
  friend HybridBase;
83
87
 
@@ -6,13 +6,11 @@
6
6
  #include "JavaReferencesCache.h"
7
7
  #include "Exceptions.h"
8
8
  #include "JavaCallback.h"
9
+ #include "types/JNIToJSIConverter.h"
9
10
 
10
11
  #include <utility>
12
+ #include <functional>
11
13
 
12
- #include <react/jni/ReadableNativeMap.h>
13
- #include <react/jni/ReadableNativeArray.h>
14
- #include <react/jni/WritableNativeArray.h>
15
- #include <react/jni/WritableNativeMap.h>
16
14
  #include "JSReferencesCache.h"
17
15
 
18
16
  namespace jni = facebook::jni;
@@ -25,18 +23,12 @@ namespace expo {
25
23
  // https://github.com/facebook/react-native/blob/7dceb9b63c0bfd5b13bf6d26f9530729506e9097/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp#L57
26
24
  jni::local_ref<JavaCallback::JavaPart> createJavaCallbackFromJSIFunction(
27
25
  jsi::Function &&function,
28
- std::weak_ptr<react::LongLivedObjectCollection> longLivedObjectCollection,
29
26
  jsi::Runtime &rt,
30
27
  JSIInteropModuleRegistry *moduleRegistry,
31
28
  bool isRejectCallback = false
32
29
  ) {
33
30
  std::shared_ptr<react::CallInvoker> jsInvoker = moduleRegistry->runtimeHolder->jsInvoker;
34
- auto strongLongLiveObjectCollection = longLivedObjectCollection.lock();
35
- if (!strongLongLiveObjectCollection) {
36
- throw std::runtime_error("The LongLivedObjectCollection for MethodMetadata is not alive.");
37
- }
38
- auto weakWrapper = react::CallbackWrapper::createWeak(strongLongLiveObjectCollection,
39
- std::move(function), rt,
31
+ auto weakWrapper = react::CallbackWrapper::createWeak(std::move(function), rt,
40
32
  std::move(jsInvoker));
41
33
 
42
34
  // This needs to be a shared_ptr because:
@@ -117,9 +109,25 @@ jobjectArray MethodMetadata::convertJSIArgsToJNI(
117
109
  JSIInteropModuleRegistry *moduleRegistry,
118
110
  JNIEnv *env,
119
111
  jsi::Runtime &rt,
112
+ const jsi::Value &thisValue,
120
113
  const jsi::Value *args,
121
114
  size_t count
122
115
  ) {
116
+ // This function takes the owner, so the args number is higher because we have access to the thisValue.
117
+ if (takesOwner) {
118
+ count++;
119
+ }
120
+
121
+ // The `count < this->args` case is handled by the Kotlin part
122
+ if (count > this->args) {
123
+ throwNewJavaException(
124
+ InvalidArgsNumberException::create(
125
+ count,
126
+ this->args
127
+ ).get()
128
+ );
129
+ }
130
+
123
131
  auto argumentArray = env->NewObjectArray(
124
132
  count,
125
133
  JavaReferencesCache::instance()->getJClass("java/lang/Object").clazz,
@@ -128,8 +136,21 @@ jobjectArray MethodMetadata::convertJSIArgsToJNI(
128
136
 
129
137
  std::vector<jobject> result(count);
130
138
 
131
- for (unsigned int argIndex = 0; argIndex < count; argIndex++) {
132
- const jsi::Value &arg = args[argIndex];
139
+ const auto getCurrentArg = [&thisValue, args, takesOwner = takesOwner](
140
+ size_t index
141
+ ) -> const jsi::Value & {
142
+ if (!takesOwner) {
143
+ return args[index];
144
+ } else {
145
+ if (index != 0) {
146
+ return args[index - 1];
147
+ }
148
+ return thisValue;
149
+ }
150
+ };
151
+
152
+ for (size_t argIndex = 0; argIndex < count; argIndex++) {
153
+ const jsi::Value &arg = getCurrentArg(argIndex);
133
154
  auto &type = argTypes[argIndex];
134
155
  if (arg.isNull() || arg.isUndefined()) {
135
156
  // If value is null or undefined, we just passes a null
@@ -154,17 +175,17 @@ jobjectArray MethodMetadata::convertJSIArgsToJNI(
154
175
  }
155
176
 
156
177
  MethodMetadata::MethodMetadata(
157
- std::weak_ptr<react::LongLivedObjectCollection> longLivedObjectCollection,
158
178
  std::string name,
179
+ bool takesOwner,
159
180
  int args,
160
181
  bool isAsync,
161
182
  jni::local_ref<jni::JArrayClass<ExpectedType>> expectedArgTypes,
162
183
  jni::global_ref<jobject> &&jBodyReference
163
184
  ) : name(std::move(name)),
185
+ takesOwner(takesOwner),
164
186
  args(args),
165
187
  isAsync(isAsync),
166
- jBodyReference(std::move(jBodyReference)),
167
- longLivedObjectCollection_(std::move(longLivedObjectCollection)) {
188
+ jBodyReference(std::move(jBodyReference)) {
168
189
  argTypes.reserve(args);
169
190
  for (size_t i = 0; i < args; i++) {
170
191
  auto expectedType = expectedArgTypes->getElement(i);
@@ -175,18 +196,18 @@ MethodMetadata::MethodMetadata(
175
196
  }
176
197
 
177
198
  MethodMetadata::MethodMetadata(
178
- std::weak_ptr<react::LongLivedObjectCollection> longLivedObjectCollection,
179
199
  std::string name,
200
+ bool takesOwner,
180
201
  int args,
181
202
  bool isAsync,
182
203
  std::vector<std::unique_ptr<AnyType>> &&expectedArgTypes,
183
204
  jni::global_ref<jobject> &&jBodyReference
184
205
  ) : name(std::move(name)),
206
+ takesOwner(takesOwner),
185
207
  args(args),
186
208
  isAsync(isAsync),
187
209
  argTypes(std::move(expectedArgTypes)),
188
- jBodyReference(std::move(jBodyReference)),
189
- longLivedObjectCollection_(std::move(longLivedObjectCollection)) {
210
+ jBodyReference(std::move(jBodyReference)) {
190
211
  }
191
212
 
192
213
  std::shared_ptr<jsi::Function> MethodMetadata::toJSFunction(
@@ -222,6 +243,7 @@ jsi::Function MethodMetadata::toSyncFunction(
222
243
  return this->callSync(
223
244
  rt,
224
245
  moduleRegistry,
246
+ thisValue,
225
247
  args,
226
248
  count
227
249
  );
@@ -231,26 +253,19 @@ jsi::Function MethodMetadata::toSyncFunction(
231
253
  });
232
254
  }
233
255
 
234
- jsi::Value MethodMetadata::callSync(
256
+ jni::local_ref<jobject> MethodMetadata::callJNISync(
257
+ JNIEnv *env,
235
258
  jsi::Runtime &rt,
236
259
  JSIInteropModuleRegistry *moduleRegistry,
260
+ const jsi::Value &thisValue,
237
261
  const jsi::Value *args,
238
262
  size_t count
239
263
  ) {
240
264
  if (this->jBodyReference == nullptr) {
241
- return jsi::Value::undefined();
265
+ return nullptr;
242
266
  }
243
267
 
244
- JNIEnv *env = jni::Environment::current();
245
-
246
- /**
247
- * This will push a new JNI stack frame for the LocalReferences in this
248
- * function call. When the stack frame for this lambda is popped,
249
- * all LocalReferences are deleted.
250
- */
251
- jni::JniLocalScope scope(env, (int) count);
252
-
253
- auto convertedArgs = convertJSIArgsToJNI(moduleRegistry, env, rt, args, count);
268
+ auto convertedArgs = convertJSIArgsToJNI(moduleRegistry, env, rt, thisValue, args, count);
254
269
 
255
270
  // Cast in this place is safe, cause we know that this function is promise-less.
256
271
  auto syncFunction = jni::static_ref_cast<JNIFunctionBody>(this->jBodyReference);
@@ -259,60 +274,26 @@ jsi::Value MethodMetadata::callSync(
259
274
  );
260
275
 
261
276
  env->DeleteLocalRef(convertedArgs);
262
- if (result == nullptr) {
263
- return jsi::Value::undefined();
264
- }
265
- auto unpackedResult = result.get();
266
- auto cache = JavaReferencesCache::instance();
267
- if (env->IsInstanceOf(unpackedResult, cache->getJClass("java/lang/Double").clazz)) {
268
- return {jni::static_ref_cast<jni::JDouble>(result)->value()};
269
- }
270
- if (env->IsInstanceOf(unpackedResult, cache->getJClass("java/lang/Integer").clazz)) {
271
- return {jni::static_ref_cast<jni::JInteger>(result)->value()};
272
- }
273
- if (env->IsInstanceOf(unpackedResult, cache->getJClass("java/lang/Long").clazz)) {
274
- return {(double) jni::static_ref_cast<jni::JLong>(result)->value()};
275
- }
276
- if (env->IsInstanceOf(unpackedResult, cache->getJClass("java/lang/String").clazz)) {
277
- return jsi::String::createFromUtf8(
278
- rt,
279
- jni::static_ref_cast<jni::JString>(result)->toStdString()
280
- );
281
- }
282
- if (env->IsInstanceOf(unpackedResult, cache->getJClass("java/lang/Boolean").clazz)) {
283
- return {(bool) jni::static_ref_cast<jni::JBoolean>(result)->value()};
284
- }
285
- if (env->IsInstanceOf(unpackedResult, cache->getJClass("java/lang/Float").clazz)) {
286
- return {(double) jni::static_ref_cast<jni::JFloat>(result)->value()};
287
- }
288
- if (env->IsInstanceOf(
289
- unpackedResult,
290
- cache->getJClass("com/facebook/react/bridge/WritableNativeArray").clazz
291
- )) {
292
- auto dynamic = jni::static_ref_cast<react::WritableNativeArray::javaobject>(result)
293
- ->cthis()
294
- ->consume();
295
- return jsi::valueFromDynamic(rt, dynamic);
296
- }
297
- if (env->IsInstanceOf(
298
- unpackedResult,
299
- cache->getJClass("com/facebook/react/bridge/WritableNativeMap").clazz
300
- )) {
301
- auto dynamic = jni::static_ref_cast<react::WritableNativeMap::javaobject>(result)
302
- ->cthis()
303
- ->consume();
304
- return jsi::valueFromDynamic(rt, dynamic);
305
- }
306
- if (env->IsInstanceOf(unpackedResult, JavaScriptModuleObject::javaClassStatic().get())) {
307
- auto anonymousObject = jni::static_ref_cast<JavaScriptModuleObject::javaobject>(result)
308
- ->cthis();
309
- anonymousObject->jsiInteropModuleRegistry = moduleRegistry;
310
- auto hostObject = std::make_shared<JavaScriptModuleObject::HostObject>(anonymousObject);
311
- hostObject->jObjectRef = jni::make_global(result);
312
- return jsi::Object::createFromHostObject(rt, hostObject);
313
- }
277
+ return result;
278
+ }
279
+
280
+ jsi::Value MethodMetadata::callSync(
281
+ jsi::Runtime &rt,
282
+ JSIInteropModuleRegistry *moduleRegistry,
283
+ const jsi::Value &thisValue,
284
+ const jsi::Value *args,
285
+ size_t count
286
+ ) {
287
+ JNIEnv *env = jni::Environment::current();
288
+ /**
289
+ * This will push a new JNI stack frame for the LocalReferences in this
290
+ * function call. When the stack frame for this lambda is popped,
291
+ * all LocalReferences are deleted.
292
+ */
293
+ jni::JniLocalScope scope(env, (int) count);
314
294
 
315
- return jsi::Value::undefined();
295
+ auto result = this->callJNISync(env, rt, moduleRegistry, thisValue, args, count);
296
+ return convert(moduleRegistry, env, rt, std::move(result));
316
297
  }
317
298
 
318
299
  jsi::Function MethodMetadata::toAsyncFunction(
@@ -343,7 +324,7 @@ jsi::Function MethodMetadata::toAsyncFunction(
343
324
  );
344
325
 
345
326
  try {
346
- auto convertedArgs = convertJSIArgsToJNI(moduleRegistry, env, rt, args, count);
327
+ auto convertedArgs = convertJSIArgsToJNI(moduleRegistry, env, rt, thisValue, args, count);
347
328
  auto globalConvertedArgs = (jobjectArray) env->NewGlobalRef(convertedArgs);
348
329
  env->DeleteLocalRef(convertedArgs);
349
330
 
@@ -423,14 +404,12 @@ jsi::Function MethodMetadata::createPromiseBody(
423
404
 
424
405
  jobject resolve = createJavaCallbackFromJSIFunction(
425
406
  std::move(resolveJSIFn),
426
- longLivedObjectCollection_,
427
407
  rt,
428
408
  moduleRegistry
429
409
  ).release();
430
410
 
431
411
  jobject reject = createJavaCallbackFromJSIFunction(
432
412
  std::move(rejectJSIFn),
433
- longLivedObjectCollection_,
434
413
  rt,
435
414
  moduleRegistry,
436
415
  true
@@ -9,7 +9,6 @@
9
9
  #include <jsi/jsi.h>
10
10
  #include <fbjni/fbjni.h>
11
11
  #include <ReactCommon/TurboModuleUtils.h>
12
- #include <react/bridging/LongLivedObject.h>
13
12
  #include <react/jni/ReadableNativeArray.h>
14
13
  #include <memory>
15
14
  #include <vector>
@@ -32,11 +31,15 @@ public:
32
31
  * Function name
33
32
  */
34
33
  std::string name;
34
+ /**
35
+ * Whether this function takes owner
36
+ */
37
+ bool takesOwner;
35
38
  /**
36
39
  * Number of arguments
37
40
  */
38
41
  int args;
39
- /*
42
+ /**
40
43
  * Whether this function is async
41
44
  */
42
45
  bool isAsync;
@@ -46,8 +49,8 @@ public:
46
49
  std::vector<std::unique_ptr<AnyType>> argTypes;
47
50
 
48
51
  MethodMetadata(
49
- std::weak_ptr<react::LongLivedObjectCollection> longLivedObjectCollection,
50
52
  std::string name,
53
+ bool takesOwner,
51
54
  int args,
52
55
  bool isAsync,
53
56
  jni::local_ref<jni::JArrayClass<ExpectedType>> expectedArgTypes,
@@ -55,8 +58,8 @@ public:
55
58
  );
56
59
 
57
60
  MethodMetadata(
58
- std::weak_ptr<react::LongLivedObjectCollection> longLivedObjectCollection,
59
61
  std::string name,
62
+ bool takesOwner,
60
63
  int args,
61
64
  bool isAsync,
62
65
  std::vector<std::unique_ptr<AnyType>> &&expectedArgTypes,
@@ -68,16 +71,6 @@ public:
68
71
 
69
72
  MethodMetadata(MethodMetadata &&other) = default;
70
73
 
71
- /**
72
- * MethodMetadata owns the only reference to the Kotlin function.
73
- * We have to clean that, cause it's a `global_ref`.
74
- */
75
- ~MethodMetadata() {
76
- if (jBodyReference != nullptr) {
77
- jBodyReference.release();
78
- }
79
- }
80
-
81
74
  /**
82
75
  * Transforms metadata to a jsi::Function.
83
76
  *
@@ -96,6 +89,16 @@ public:
96
89
  jsi::Value callSync(
97
90
  jsi::Runtime &rt,
98
91
  JSIInteropModuleRegistry *moduleRegistry,
92
+ const jsi::Value &thisValue,
93
+ const jsi::Value *args,
94
+ size_t count
95
+ );
96
+
97
+ jni::local_ref<jobject> callJNISync(
98
+ JNIEnv *env,
99
+ jsi::Runtime &rt,
100
+ JSIInteropModuleRegistry *moduleRegistry,
101
+ const jsi::Value &thisValue,
99
102
  const jsi::Value *args,
100
103
  size_t count
101
104
  );
@@ -114,8 +117,6 @@ private:
114
117
  */
115
118
  std::shared_ptr<jsi::Function> body = nullptr;
116
119
 
117
- std::weak_ptr<react::LongLivedObjectCollection> longLivedObjectCollection_;
118
-
119
120
  jsi::Function toSyncFunction(jsi::Runtime &runtime, JSIInteropModuleRegistry *moduleRegistry);
120
121
 
121
122
  jsi::Function toAsyncFunction(jsi::Runtime &runtime, JSIInteropModuleRegistry *moduleRegistry);
@@ -130,6 +131,7 @@ private:
130
131
  JSIInteropModuleRegistry *moduleRegistry,
131
132
  JNIEnv *env,
132
133
  jsi::Runtime &rt,
134
+ const jsi::Value &thisValue,
133
135
  const jsi::Value *args,
134
136
  size_t count
135
137
  );
@@ -0,0 +1,25 @@
1
+ // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2
+
3
+ #pragma once
4
+
5
+ #include <jsi/jsi.h>
6
+
7
+ namespace jsi = facebook::jsi;
8
+
9
+ namespace expo {
10
+
11
+ class JSI_EXPORT ObjectDeallocator : public jsi::HostObject {
12
+ public:
13
+ typedef std::function<void()> ObjectDeallocatorType;
14
+
15
+ ObjectDeallocator(ObjectDeallocatorType deallocator) : deallocator(deallocator) {};
16
+
17
+ virtual ~ObjectDeallocator() {
18
+ deallocator();
19
+ }
20
+
21
+ const ObjectDeallocatorType deallocator;
22
+
23
+ }; // class ObjectDeallocator
24
+
25
+ }
@@ -1,5 +1,6 @@
1
1
  #include "WeakRuntimeHolder.h"
2
2
  #include "JavaScriptRuntime.h"
3
+ #include "JSIInteropModuleRegistry.h"
3
4
 
4
5
  namespace expo {
5
6
  WeakRuntimeHolder::WeakRuntimeHolder(std::weak_ptr<JavaScriptRuntime> runtime)
@@ -14,4 +15,10 @@ jsi::Runtime &WeakRuntimeHolder::getJSRuntime() {
14
15
  void WeakRuntimeHolder::ensureRuntimeIsValid() {
15
16
  assert((!expired()) && "JS Runtime was used after deallocation");
16
17
  }
18
+
19
+ JSIInteropModuleRegistry *WeakRuntimeHolder::getModuleRegistry() {
20
+ auto runtime = lock();
21
+ assert((runtime != nullptr) && "JS Runtime was used after deallocation");
22
+ return runtime->getModuleRegistry();
23
+ }
17
24
  } // namespace expo
@@ -12,6 +12,8 @@ namespace jsi = facebook::jsi;
12
12
 
13
13
  class JavaScriptRuntime;
14
14
 
15
+ class JSIInteropModuleRegistry;
16
+
15
17
  /**
16
18
  * A convenient class to access underlying jni::Runtime and hold a weak reference to expo::JavaScriptRuntime.
17
19
  * It's working like std::weak_ptr but can have more helper methods.
@@ -31,6 +33,8 @@ public:
31
33
  */
32
34
  jsi::Runtime &getJSRuntime();
33
35
 
36
+ JSIInteropModuleRegistry *getModuleRegistry();
37
+
34
38
  void ensureRuntimeIsValid();
35
39
  };
36
40
  } // namespace expo
@@ -22,6 +22,9 @@ enum CppType {
22
22
  TYPED_ARRAY = 1 << 10,
23
23
  PRIMITIVE_ARRAY = 1 << 11,
24
24
  LIST = 1 << 12,
25
- MAP = 1 << 13
25
+ MAP = 1 << 13,
26
+ VIEW_TAG = 1 << 14,
27
+ SHARED_OBJECT_ID = 1 << 15,
28
+ JS_FUNCTION = 1 << 16
26
29
  };
27
30
  } // namespace expo