expo-modules-core 1.2.6 → 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 +33 -4
  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 +18 -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 +34 -21
  42. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +13 -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 -4
  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 +7 -8
  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
@@ -2,6 +2,7 @@
2
2
 
3
3
  #include "JavaScriptModuleObject.h"
4
4
  #include "JSIInteropModuleRegistry.h"
5
+ #include "ObjectDeallocator.h"
5
6
 
6
7
  #include <folly/dynamic.h>
7
8
  #include <jsi/JSIDynamic.h>
@@ -16,6 +17,7 @@
16
17
  #include <utility>
17
18
  #include <tuple>
18
19
  #include <algorithm>
20
+ #include <sstream>
19
21
 
20
22
  namespace jni = facebook::jni;
21
23
  namespace jsi = facebook::jsi;
@@ -23,6 +25,60 @@ namespace react = facebook::react;
23
25
 
24
26
  namespace expo {
25
27
 
28
+ void decorateObjectWithFunctions(
29
+ jsi::Runtime &runtime,
30
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry,
31
+ jsi::Object *jsObject,
32
+ JavaScriptModuleObject *objectData) {
33
+ for (auto &[name, method]: objectData->methodsMetadata) {
34
+ jsObject->setProperty(
35
+ runtime,
36
+ jsi::String::createFromUtf8(runtime, name),
37
+ jsi::Value(runtime, *method.toJSFunction(runtime, jsiInteropModuleRegistry))
38
+ );
39
+ }
40
+ }
41
+
42
+ void decorateObjectWithProperties(
43
+ jsi::Runtime &runtime,
44
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry,
45
+ jsi::Object *jsObject,
46
+ JavaScriptModuleObject *objectData) {
47
+ for (auto &[name, property]: objectData->properties) {
48
+ auto &[getter, setter] = property;
49
+
50
+ auto descriptor = JavaScriptObject::preparePropertyDescriptor(runtime,
51
+ 1 << 1 /* enumerable */);
52
+ descriptor.setProperty(
53
+ runtime,
54
+ "get",
55
+ jsi::Value(runtime, *getter.toJSFunction(runtime,
56
+ jsiInteropModuleRegistry))
57
+ );
58
+ descriptor.setProperty(
59
+ runtime,
60
+ "set",
61
+ jsi::Value(runtime, *setter.toJSFunction(runtime,
62
+ jsiInteropModuleRegistry))
63
+ );
64
+ JavaScriptObject::defineProperty(runtime, jsObject, name, std::move(descriptor));
65
+ }
66
+ }
67
+
68
+ void decorateObjectWithConstants(
69
+ jsi::Runtime &runtime,
70
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry,
71
+ jsi::Object *jsObject,
72
+ JavaScriptModuleObject *objectData) {
73
+ for (const auto &[name, value]: objectData->constants) {
74
+ jsObject->setProperty(
75
+ runtime,
76
+ jsi::String::createFromUtf8(runtime, name),
77
+ jsi::valueFromDynamic(runtime, value)
78
+ );
79
+ }
80
+ }
81
+
26
82
  jni::local_ref<jni::HybridClass<JavaScriptModuleObject>::jhybriddata>
27
83
  JavaScriptModuleObject::initHybrid(jni::alias_ref<jhybridobject> jThis) {
28
84
  return makeCxxInstance(jThis);
@@ -38,6 +94,10 @@ void JavaScriptModuleObject::registerNatives() {
38
94
  JavaScriptModuleObject::registerAsyncFunction),
39
95
  makeNativeMethod("registerProperty",
40
96
  JavaScriptModuleObject::registerProperty),
97
+ makeNativeMethod("registerClass",
98
+ JavaScriptModuleObject::registerClass),
99
+ makeNativeMethod("registerViewPrototype",
100
+ JavaScriptModuleObject::registerViewPrototype)
41
101
  });
42
102
  }
43
103
 
@@ -46,11 +106,133 @@ std::shared_ptr<jsi::Object> JavaScriptModuleObject::getJSIObject(jsi::Runtime &
46
106
  return object;
47
107
  }
48
108
 
49
- auto hostObject = std::make_shared<JavaScriptModuleObject::HostObject>(this);
50
- auto object = std::make_shared<jsi::Object>(
51
- jsi::Object::createFromHostObject(runtime, hostObject));
52
- jsiObject = object;
53
- return object;
109
+ auto moduleObject = std::make_shared<jsi::Object>(runtime);
110
+
111
+ decorateObjectWithConstants(
112
+ runtime,
113
+ jsiInteropModuleRegistry,
114
+ moduleObject.get(),
115
+ this
116
+ );
117
+ decorateObjectWithProperties(
118
+ runtime,
119
+ jsiInteropModuleRegistry,
120
+ moduleObject.get(),
121
+ this
122
+ );
123
+ decorateObjectWithFunctions(
124
+ runtime,
125
+ jsiInteropModuleRegistry,
126
+ moduleObject.get(),
127
+ this
128
+ );
129
+
130
+ if (viewPrototype) {
131
+ auto viewPrototypeObject = viewPrototype->cthis();
132
+ viewPrototypeObject->jsiInteropModuleRegistry = jsiInteropModuleRegistry;
133
+ auto viewPrototypeJSIObject = viewPrototypeObject->getJSIObject(runtime);
134
+ moduleObject->setProperty(
135
+ runtime,
136
+ "ViewPrototype",
137
+ jsi::Value(runtime, *viewPrototypeJSIObject)
138
+ );
139
+ }
140
+
141
+ for (auto &[name, classInfo]: classes) {
142
+ auto &[classRef, constructor] = classInfo;
143
+ auto classObject = classRef->cthis();
144
+ classObject->jsiInteropModuleRegistry = jsiInteropModuleRegistry;
145
+
146
+ std::string nativeConstructorKey("__native_constructor__");
147
+
148
+ // Create a string buffer of the source code to evaluate.
149
+ std::stringstream source;
150
+ source << "(function " << name << "(...args) { this." << nativeConstructorKey
151
+ << "(...args); return this; })";
152
+ std::shared_ptr<jsi::StringBuffer> sourceBuffer = std::make_shared<jsi::StringBuffer>(
153
+ source.str());
154
+
155
+ // Evaluate the code and obtain returned value (the constructor function).
156
+ jsi::Object klass = runtime.evaluateJavaScript(sourceBuffer, "").asObject(runtime);
157
+
158
+ // Set the native constructor in the prototype.
159
+ jsi::Object prototype = klass.getPropertyAsObject(runtime, "prototype");
160
+ jsi::PropNameID nativeConstructorPropId = jsi::PropNameID::forAscii(runtime,
161
+ nativeConstructorKey);
162
+ jsi::Function nativeConstructor = jsi::Function::createFromHostFunction(
163
+ runtime,
164
+ nativeConstructorPropId,
165
+ // The paramCount is not obligatory to match, it only affects the `length` property of the function.
166
+ 0,
167
+ [classObject, &constructor = constructor, jsiInteropModuleRegistry = jsiInteropModuleRegistry](
168
+ jsi::Runtime &runtime,
169
+ const jsi::Value &thisValue,
170
+ const jsi::Value *args,
171
+ size_t count
172
+ ) -> jsi::Value {
173
+ auto thisObject = std::make_shared<jsi::Object>(thisValue.asObject(runtime));
174
+ decorateObjectWithProperties(runtime, jsiInteropModuleRegistry, thisObject.get(),
175
+ classObject);
176
+ try {
177
+ JNIEnv *env = jni::Environment::current();
178
+ /**
179
+ * This will push a new JNI stack frame for the LocalReferences in this
180
+ * function call. When the stack frame for this lambda is popped,
181
+ * all LocalReferences are deleted.
182
+ */
183
+ jni::JniLocalScope scope(env, (int) count);
184
+ auto result = constructor.callJNISync(
185
+ env,
186
+ runtime,
187
+ jsiInteropModuleRegistry,
188
+ thisValue,
189
+ args,
190
+ count
191
+ );
192
+ if (result == nullptr) {
193
+ return jsi::Value::undefined();
194
+ }
195
+ jobject unpackedResult = result.get();
196
+ jclass resultClass = env->GetObjectClass(unpackedResult);
197
+ if (env->IsAssignableFrom(
198
+ resultClass,
199
+ JavaReferencesCache::instance()->getJClass(
200
+ "expo/modules/kotlin/sharedobjects/SharedObject").clazz
201
+ )) {
202
+ auto jsThisObject = JavaScriptObject::newObjectCxxArgs(
203
+ jsiInteropModuleRegistry->runtimeHolder,
204
+ thisObject
205
+ );
206
+ jsiInteropModuleRegistry->registerSharedObject(result, jsThisObject);
207
+ }
208
+ } catch (jni::JniException &jniException) {
209
+ rethrowAsCodedError(runtime, jniException);
210
+ }
211
+ return jsi::Value::undefined();
212
+ });
213
+
214
+ auto descriptor = JavaScriptObject::preparePropertyDescriptor(runtime, 0);
215
+ descriptor.setProperty(runtime, "value", jsi::Value(runtime, nativeConstructor));
216
+
217
+ JavaScriptObject::defineProperty(runtime, &prototype, nativeConstructorKey,
218
+ std::move(descriptor));
219
+
220
+ moduleObject->setProperty(
221
+ runtime,
222
+ jsi::String::createFromUtf8(runtime, name),
223
+ jsi::Value(runtime, klass.asFunction(runtime))
224
+ );
225
+
226
+ decorateObjectWithFunctions(
227
+ runtime,
228
+ jsiInteropModuleRegistry,
229
+ &prototype,
230
+ classObject
231
+ );
232
+ }
233
+
234
+ jsiObject = moduleObject;
235
+ return moduleObject;
54
236
  }
55
237
 
56
238
  void JavaScriptModuleObject::exportConstants(
@@ -66,6 +248,7 @@ void JavaScriptModuleObject::exportConstants(
66
248
 
67
249
  void JavaScriptModuleObject::registerSyncFunction(
68
250
  jni::alias_ref<jstring> name,
251
+ jboolean takesOwner,
69
252
  jint args,
70
253
  jni::alias_ref<jni::JArrayClass<ExpectedType>> expectedArgTypes,
71
254
  jni::alias_ref<JNIFunctionBody::javaobject> body
@@ -74,8 +257,8 @@ void JavaScriptModuleObject::registerSyncFunction(
74
257
 
75
258
  methodsMetadata.try_emplace(
76
259
  cName,
77
- longLivedObjectCollection_,
78
260
  cName,
261
+ takesOwner,
79
262
  args,
80
263
  false,
81
264
  jni::make_local(expectedArgTypes),
@@ -85,6 +268,7 @@ void JavaScriptModuleObject::registerSyncFunction(
85
268
 
86
269
  void JavaScriptModuleObject::registerAsyncFunction(
87
270
  jni::alias_ref<jstring> name,
271
+ jboolean takesOwner,
88
272
  jint args,
89
273
  jni::alias_ref<jni::JArrayClass<ExpectedType>> expectedArgTypes,
90
274
  jni::alias_ref<JNIAsyncFunctionBody::javaobject> body
@@ -93,8 +277,8 @@ void JavaScriptModuleObject::registerAsyncFunction(
93
277
 
94
278
  methodsMetadata.try_emplace(
95
279
  cName,
96
- longLivedObjectCollection_,
97
280
  cName,
281
+ takesOwner,
98
282
  args,
99
283
  true,
100
284
  jni::make_local(expectedArgTypes),
@@ -102,6 +286,38 @@ void JavaScriptModuleObject::registerAsyncFunction(
102
286
  );
103
287
  }
104
288
 
289
+ void JavaScriptModuleObject::registerClass(
290
+ jni::alias_ref<jstring> name,
291
+ jni::alias_ref<JavaScriptModuleObject::javaobject> classObject,
292
+ jboolean takesOwner,
293
+ jint args,
294
+ jni::alias_ref<jni::JArrayClass<ExpectedType>> expectedArgTypes,
295
+ jni::alias_ref<JNIFunctionBody::javaobject> body
296
+ ) {
297
+ std::string cName = name->toStdString();
298
+ MethodMetadata constructor(
299
+ "constructor",
300
+ takesOwner,
301
+ args,
302
+ false,
303
+ jni::make_local(expectedArgTypes),
304
+ jni::make_global(body)
305
+ );
306
+
307
+ auto pair = std::make_pair(jni::make_global(classObject), std::move(constructor));
308
+
309
+ classes.try_emplace(
310
+ cName,
311
+ std::move(pair)
312
+ );
313
+ }
314
+
315
+ void JavaScriptModuleObject::registerViewPrototype(
316
+ jni::alias_ref<JavaScriptModuleObject::javaobject> viewPrototype
317
+ ) {
318
+ this->viewPrototype = jni::make_global(viewPrototype);
319
+ }
320
+
105
321
  void JavaScriptModuleObject::registerProperty(
106
322
  jni::alias_ref<jstring> name,
107
323
  jni::alias_ref<ExpectedType> expectedArgType,
@@ -111,8 +327,8 @@ void JavaScriptModuleObject::registerProperty(
111
327
  auto cName = name->toStdString();
112
328
 
113
329
  auto getterMetadata = MethodMetadata(
114
- longLivedObjectCollection_,
115
330
  cName,
331
+ false,
116
332
  0,
117
333
  false,
118
334
  std::vector<std::unique_ptr<AnyType>>(),
@@ -122,8 +338,8 @@ void JavaScriptModuleObject::registerProperty(
122
338
  auto types = std::vector<std::unique_ptr<AnyType>>();
123
339
  types.push_back(std::make_unique<AnyType>(jni::make_local(expectedArgType)));
124
340
  auto setterMetadata = MethodMetadata(
125
- longLivedObjectCollection_,
126
341
  cName,
342
+ false,
127
343
  1,
128
344
  false,
129
345
  std::move(types),
@@ -138,103 +354,7 @@ void JavaScriptModuleObject::registerProperty(
138
354
  properties.insert({cName, std::move(functions)});
139
355
  }
140
356
 
141
- JavaScriptModuleObject::HostObject::HostObject(
142
- JavaScriptModuleObject *jsModule) : jsModule(jsModule) {}
143
-
144
- /**
145
- * Clears all the JSI references held by the `JavaScriptModuleObject`.
146
- */
147
- JavaScriptModuleObject::HostObject::~HostObject() {
148
- jObjectRef.reset();
149
- jsModule->jsiObject.reset();
150
- jsModule->methodsMetadata.clear();
151
- jsModule->constants.clear();
152
- jsModule->properties.clear();
153
- jsModule->longLivedObjectCollection_->clear();
154
- }
155
-
156
- jsi::Value JavaScriptModuleObject::HostObject::get(jsi::Runtime &runtime,
157
- const jsi::PropNameID &name) {
158
- auto cName = name.utf8(runtime);
159
-
160
- auto constantsRecord = jsModule->constants.find(cName);
161
- if (constantsRecord != jsModule->constants.end()) {
162
- auto dynamic = constantsRecord->second;
163
- return jsi::valueFromDynamic(runtime, dynamic);
164
- }
165
-
166
- auto propertyRecord = jsModule->properties.find(cName);
167
- if (propertyRecord != jsModule->properties.end()) {
168
- auto&[getter, _] = propertyRecord->second;
169
- return getter.callSync(runtime, jsModule->jsiInteropModuleRegistry, nullptr, 0);
170
- }
171
-
172
- auto metadataRecord = jsModule->methodsMetadata.find(cName);
173
- if (metadataRecord == jsModule->methodsMetadata.end()) {
174
- return jsi::Value::undefined();
175
- }
176
- auto &metadata = metadataRecord->second;
177
- return jsi::Value(runtime, *metadata.toJSFunction(runtime, jsModule->jsiInteropModuleRegistry));
178
- }
179
-
180
- void JavaScriptModuleObject::HostObject::set(
181
- jsi::Runtime &runtime,
182
- const jsi::PropNameID &name,
183
- const jsi::Value &value
184
- ) {
185
- auto cName = name.utf8(runtime);
186
- auto propertyRecord = jsModule->properties.find(cName);
187
- if (propertyRecord != jsModule->properties.end()) {
188
- auto&[_, setter] = propertyRecord->second;
189
- setter.callSync(runtime, jsModule->jsiInteropModuleRegistry, &value, 1);
190
- return;
191
- }
192
-
193
- throw jsi::JSError(
194
- runtime,
195
- "RuntimeError: Cannot override the host object for expo module '" + name.utf8(runtime) + "'"
196
- );
197
- }
198
-
199
- std::vector<jsi::PropNameID> JavaScriptModuleObject::HostObject::getPropertyNames(
200
- jsi::Runtime &rt
201
- ) {
202
- auto &metadata = jsModule->methodsMetadata;
203
- std::vector<jsi::PropNameID> result;
204
- std::transform(
205
- metadata.begin(),
206
- metadata.end(),
207
- std::back_inserter(result),
208
- [&rt](const auto &kv) {
209
- return jsi::PropNameID::forUtf8(rt, kv.first);
210
- }
211
- );
212
-
213
- auto &constants = jsModule->constants;
214
- std::transform(
215
- constants.begin(),
216
- constants.end(),
217
- std::back_inserter(result),
218
- [&rt](const auto &kv) {
219
- return jsi::PropNameID::forUtf8(rt, kv.first);
220
- }
221
- );
222
-
223
- auto &properties = jsModule->properties;
224
- std::transform(
225
- properties.begin(),
226
- properties.end(),
227
- std::back_inserter(result),
228
- [&rt](const auto &kv) {
229
- return jsi::PropNameID::forUtf8(rt, kv.first);
230
- }
231
- );
232
-
233
- return result;
234
- }
235
-
236
357
  JavaScriptModuleObject::JavaScriptModuleObject(jni::alias_ref<jhybridobject> jThis)
237
358
  : javaPart_(jni::make_global(jThis)) {
238
- longLivedObjectCollection_ = std::make_shared<react::LongLivedObjectCollection>();
239
359
  }
240
360
  } // namespace expo
@@ -4,7 +4,6 @@
4
4
 
5
5
  #include <fbjni/fbjni.h>
6
6
  #include <jsi/jsi.h>
7
- #include <react/bridging/LongLivedObject.h>
8
7
  #include <react/jni/ReadableNativeArray.h>
9
8
  #include <jni/JCallback.h>
10
9
 
@@ -21,6 +20,29 @@ namespace react = facebook::react;
21
20
  namespace expo {
22
21
  class JSIInteropModuleRegistry;
23
22
 
23
+ class JavaScriptModuleObject;
24
+
25
+ void decorateObjectWithFunctions(
26
+ jsi::Runtime &runtime,
27
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry,
28
+ jsi::Object *jsObject,
29
+ JavaScriptModuleObject *objectData
30
+ );
31
+
32
+ void decorateObjectWithProperties(
33
+ jsi::Runtime &runtime,
34
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry,
35
+ jsi::Object *jsObject,
36
+ JavaScriptModuleObject *objectData
37
+ );
38
+
39
+ void decorateObjectWithConstants(
40
+ jsi::Runtime &runtime,
41
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry,
42
+ jsi::Object *jsObject,
43
+ JavaScriptModuleObject *objectData
44
+ );
45
+
24
46
  /**
25
47
  * A CPP part of the module.
26
48
  *
@@ -60,6 +82,7 @@ public:
60
82
  */
61
83
  void registerSyncFunction(
62
84
  jni::alias_ref<jstring> name,
85
+ jboolean takesOwner,
63
86
  jint args,
64
87
  jni::alias_ref<jni::JArrayClass<ExpectedType>> expectedArgTypes,
65
88
  jni::alias_ref<JNIFunctionBody::javaobject> body
@@ -71,11 +94,25 @@ public:
71
94
  */
72
95
  void registerAsyncFunction(
73
96
  jni::alias_ref<jstring> name,
97
+ jboolean takesOwner,
74
98
  jint args,
75
99
  jni::alias_ref<jni::JArrayClass<ExpectedType>> expectedArgTypes,
76
100
  jni::alias_ref<JNIAsyncFunctionBody::javaobject> body
77
101
  );
78
102
 
103
+ void registerClass(
104
+ jni::alias_ref<jstring> name,
105
+ jni::alias_ref<JavaScriptModuleObject::javaobject> classObject,
106
+ jboolean takesOwner,
107
+ jint args,
108
+ jni::alias_ref<jni::JArrayClass<ExpectedType>> expectedArgTypes,
109
+ jni::alias_ref<JNIFunctionBody::javaobject> body
110
+ );
111
+
112
+ void registerViewPrototype(
113
+ jni::alias_ref<JavaScriptModuleObject::javaobject> viewPrototype
114
+ );
115
+
79
116
  /**
80
117
  * Registers a property
81
118
  * @param name of the property
@@ -90,41 +127,35 @@ public:
90
127
  jni::alias_ref<JNIFunctionBody::javaobject> setter
91
128
  );
92
129
 
93
- /**
94
- * An inner class of the `JavaScriptModuleObject` that is exported to the JS.
95
- * It's an additional communication layer between JS and Kotlin.
96
- * So the high-level view on accessing the exported function will look like this:
97
- * `JS` --get function--> `JavaScriptModuleObject::HostObject` --access module metadata--> `JavaScriptModuleObject`
98
- * --create JSI function--> `MethodMetadata`
99
- *
100
- * This abstraction wasn't necessary. However, it makes the management of ownership much easier -
101
- * `JavaScriptModuleObject` is held by the ModuleHolder and `JavaScriptModuleObject::HostObject` is stored in the JS runtime.
102
- * Without this distinction the `JavaScriptModuleObject` would have to turn into `HostObject` and `HybridObject` at the same time.
103
- */
104
- class HostObject : public jsi::HostObject {
105
- public:
106
- HostObject(JavaScriptModuleObject *);
107
-
108
- ~HostObject() override;
109
-
110
- jsi::Value get(jsi::Runtime &, const jsi::PropNameID &name) override;
111
-
112
- void set(jsi::Runtime &, const jsi::PropNameID &name, const jsi::Value &value) override;
113
-
114
- std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime &rt) override;
115
-
116
- jni::global_ref<jobject> jObjectRef;
117
- private:
118
- JavaScriptModuleObject *jsModule;
119
- };
120
-
121
130
  private:
122
131
  explicit JavaScriptModuleObject(jni::alias_ref<jhybridobject> jThis);
123
132
 
124
133
  private:
125
134
  friend HybridBase;
135
+
136
+ friend void decorateObjectWithFunctions(
137
+ jsi::Runtime &runtime,
138
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry,
139
+ jsi::Object *jsObject,
140
+ JavaScriptModuleObject *objectData
141
+ );
142
+
143
+ friend void decorateObjectWithProperties(
144
+ jsi::Runtime &runtime,
145
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry,
146
+ jsi::Object *jsObject,
147
+ JavaScriptModuleObject *objectData
148
+ );
149
+
150
+ friend void decorateObjectWithConstants(
151
+ jsi::Runtime &runtime,
152
+ JSIInteropModuleRegistry *jsiInteropModuleRegistry,
153
+ jsi::Object *jsObject,
154
+ JavaScriptModuleObject *objectData
155
+ );
156
+
126
157
  /**
127
- * A reference to the `JavaScriptModuleObject::HostObject`.
158
+ * A reference to the `jsi::Object`.
128
159
  * Simple we cached that value to return the same object each time.
129
160
  * It's a weak reference because the JS runtime holds the actual object.
130
161
  * Doing that allows the runtime to deallocate jsi::Object if it's not needed anymore.
@@ -148,9 +179,11 @@ private:
148
179
  */
149
180
  std::map<std::string, std::pair<MethodMetadata, MethodMetadata>> properties;
150
181
 
151
- /**
152
- * The `LongLivedObjectCollection` to hold `LongLivedObject` (callbacks or promises) for this module.
153
- */
154
- std::shared_ptr<react::LongLivedObjectCollection> longLivedObjectCollection_;
182
+ std::map<
183
+ std::string,
184
+ std::pair<jni::global_ref<JavaScriptModuleObject::javaobject>, MethodMetadata>
185
+ > classes;
186
+
187
+ jni::global_ref<JavaScriptModuleObject::javaobject> viewPrototype;
155
188
  };
156
189
  } // namespace expo
@@ -2,8 +2,11 @@
2
2
 
3
3
  #include "JavaScriptObject.h"
4
4
  #include "JavaScriptValue.h"
5
+ #include "JavaScriptFunction.h"
5
6
  #include "JavaScriptRuntime.h"
6
7
  #include "JSITypeConverter.h"
8
+ #include "ObjectDeallocator.h"
9
+ #include "JavaReferencesCache.h"
7
10
 
8
11
  namespace expo {
9
12
  void JavaScriptObject::registerNatives() {
@@ -29,6 +32,8 @@ void JavaScriptObject::registerNatives() {
29
32
  JavaScriptObject::defineProperty<jni::alias_ref<JavaScriptValue::javaobject>>),
30
33
  makeNativeMethod("defineJSObjectProperty",
31
34
  JavaScriptObject::defineProperty<jni::alias_ref<JavaScriptObject::javaobject>>),
35
+ makeNativeMethod("defineNativeDeallocator",
36
+ JavaScriptObject::defineNativeDeallocator),
32
37
  });
33
38
  }
34
39
 
@@ -99,6 +104,12 @@ jni::local_ref<jni::JArrayClass<jstring>> JavaScriptObject::jniGetPropertyNames(
99
104
  return paredResult;
100
105
  }
101
106
 
107
+ jni::local_ref<JavaScriptFunction::javaobject> JavaScriptObject::jniAsFunction() {
108
+ auto &jsRuntime = runtimeHolder.getJSRuntime();
109
+ auto jsFuncion = std::make_shared<jsi::Function>(jsObject->asFunction(jsRuntime));
110
+ return JavaScriptFunction::newObjectCxxArgs(runtimeHolder, jsFuncion);
111
+ }
112
+
102
113
  void JavaScriptObject::setProperty(const std::string &name, jsi::Value value) {
103
114
  auto &jsRuntime = runtimeHolder.getJSRuntime();
104
115
  jsObject->setProperty(jsRuntime, name.c_str(), value);
@@ -121,7 +132,50 @@ jsi::Object JavaScriptObject::preparePropertyDescriptor(
121
132
  jsi::Object descriptor(jsRuntime);
122
133
  descriptor.setProperty(jsRuntime, "configurable", (bool) ((1 << 0) & options));
123
134
  descriptor.setProperty(jsRuntime, "enumerable", (bool) ((1 << 1) & options));
124
- descriptor.setProperty(jsRuntime, "writable", (bool) ((1 << 2) & options));
135
+ if ((bool) (1 << 2 & options)) {
136
+ descriptor.setProperty(jsRuntime, "writable", true);
137
+ }
125
138
  return descriptor;
126
139
  }
140
+
141
+ void JavaScriptObject::defineProperty(
142
+ jsi::Runtime &runtime,
143
+ jsi::Object *jsthis,
144
+ const std::string &name,
145
+ jsi::Object descriptor
146
+ ) {
147
+ jsi::Object global = runtime.global();
148
+ jsi::Object objectClass = global.getPropertyAsObject(runtime, "Object");
149
+ jsi::Function definePropertyFunction = objectClass.getPropertyAsFunction(
150
+ runtime,
151
+ "defineProperty"
152
+ );
153
+
154
+ // This call is basically the same as `Object.defineProperty(object, name, descriptor)` in JS
155
+ definePropertyFunction.callWithThis(runtime, objectClass, {
156
+ jsi::Value(runtime, *jsthis),
157
+ jsi::String::createFromUtf8(runtime, name),
158
+ std::move(descriptor),
159
+ });
160
+ }
161
+
162
+ void JavaScriptObject::defineNativeDeallocator(
163
+ jni::alias_ref<JNIFunctionBody::javaobject> deallocator
164
+ ) {
165
+ auto &rt = runtimeHolder.getJSRuntime();
166
+ jni::global_ref<JNIFunctionBody::javaobject> globalRef = jni::make_global(deallocator);
167
+ std::shared_ptr<ObjectDeallocator> nativeDeallocator = std::make_shared<ObjectDeallocator>(
168
+ [globalRef = std::move(globalRef)]() mutable {
169
+ auto args = jni::Environment::current()->NewObjectArray(
170
+ 0,
171
+ JavaReferencesCache::instance()->getJClass("java/lang/Object").clazz,
172
+ nullptr
173
+ );
174
+ globalRef->invoke(args);
175
+ globalRef.reset();
176
+ });
177
+ auto descriptor = JavaScriptObject::preparePropertyDescriptor(rt, 0);
178
+ descriptor.setProperty(rt, "value", jsi::Object::createFromHostObject(rt, nativeDeallocator));
179
+ jsObject->setProperty(rt, "__expo_shared_object_deallocator__", std::move(descriptor));
180
+ }
127
181
  } // namespace expo