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
@@ -12,10 +12,17 @@
12
12
  */
13
13
  __weak EXJavaScriptRuntime *_runtime;
14
14
 
15
+ #if __has_include(<reacthermes/HermesExecutorFactory.h>)
15
16
  /**
16
- Shared pointer to the `WeakRef` JS object.
17
+ A weak reference to a JS object. Available only on Hermes engine.
17
18
  */
18
- std::shared_ptr<jsi::Object> _jsObject;
19
+ std::shared_ptr<jsi::WeakObject> _weakObject;
20
+ #else
21
+ /**
22
+ Shared pointer to the `WeakRef` JS object. Available only on JSC engine.
23
+ */
24
+ std::shared_ptr<jsi::Object> _weakObject;
25
+ #endif
19
26
  }
20
27
 
21
28
  - (nonnull instancetype)initWith:(std::shared_ptr<jsi::Object>)jsObject
@@ -24,15 +31,18 @@
24
31
  if (self = [super init]) {
25
32
  _runtime = runtime;
26
33
 
34
+ #if __has_include(<reacthermes/HermesExecutorFactory.h>)
35
+ _weakObject = std::make_shared<jsi::WeakObject>(*[runtime get], *jsObject);
36
+ #else
27
37
  // Check whether the runtime supports `WeakRef` objects. If it does not,
28
38
  // we consciously hold a strong reference to the object and cause memory leaks.
29
- // This is the case on hermes and JSC prior to iOS 14.5.
30
- // TODO: (@tsapeta) Use `jsi::WeakObject` on hermes
39
+ // This is the case on JSC prior to iOS 14.5.
31
40
  if (expo::isWeakRefSupported(*[runtime get])) {
32
- _jsObject = expo::createWeakRef(*[runtime get], jsObject);
41
+ _weakObject = expo::createWeakRef(*[runtime get], jsObject);
33
42
  } else {
34
- _jsObject = jsObject;
43
+ _weakObject = jsObject;
35
44
  }
45
+ #endif
36
46
  }
37
47
  return self;
38
48
  }
@@ -40,9 +50,20 @@
40
50
  - (nullable EXJavaScriptObject *)lock
41
51
  {
42
52
  jsi::Runtime *runtime = [_runtime get];
53
+
54
+ #if __has_include(<reacthermes/HermesExecutorFactory.h>)
55
+ jsi::Value value = _weakObject->lock(*runtime);
56
+
57
+ // `lock` returns an undefined value if the underlying object no longer exists.
58
+ if (value.isUndefined()) {
59
+ return nil;
60
+ }
61
+ std::shared_ptr<jsi::Object> objectPtr = std::make_shared<jsi::Object>(value.asObject(*runtime));
62
+ #else
43
63
  std::shared_ptr<jsi::Object> objectPtr = expo::isWeakRefSupported(*runtime)
44
- ? expo::derefWeakRef(*runtime, _jsObject)
45
- : _jsObject;
64
+ ? expo::derefWeakRef(*runtime, _weakObject)
65
+ : _weakObject;
66
+ #endif
46
67
 
47
68
  if (!objectPtr) {
48
69
  return nil;
@@ -0,0 +1,24 @@
1
+ // Copyright 2023-present 650 Industries. All rights reserved.
2
+
3
+ #import <Foundation/Foundation.h>
4
+ #import <ExpoModulesCore/EXJavaScriptRuntime.h>
5
+
6
+ #ifdef __cplusplus
7
+ #import <jsi/jsi.h>
8
+
9
+ namespace jsi = facebook::jsi;
10
+ #endif // __cplusplus
11
+
12
+ NS_SWIFT_NAME(RawJavaScriptFunction)
13
+ @interface EXRawJavaScriptFunction : NSObject
14
+
15
+ #ifdef __cplusplus
16
+ - (nonnull instancetype)initWith:(std::shared_ptr<jsi::Function>)function
17
+ runtime:(nonnull EXJavaScriptRuntime *)runtime;
18
+ #endif // __cplusplus
19
+
20
+ - (nonnull EXJavaScriptValue *)callWithArguments:(nonnull NSArray<id> *)arguments
21
+ thisObject:(nullable EXJavaScriptObject *)thisObject
22
+ asConstructor:(BOOL)asConstructor;
23
+
24
+ @end
@@ -0,0 +1,52 @@
1
+ // Copyright 2023-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoModulesCore/EXJSIConversions.h>
4
+ #import <ExpoModulesCore/EXRawJavaScriptFunction.h>
5
+
6
+ @implementation EXRawJavaScriptFunction {
7
+ /**
8
+ Pointer to the `EXJavaScriptRuntime` wrapper.
9
+
10
+ \note It must be weak because only then the original runtime can be safely deallocated
11
+ when the JS engine wants to without unsetting it on each created object.
12
+ */
13
+ __weak EXJavaScriptRuntime *_runtime;
14
+
15
+ /**
16
+ Shared pointer to the underlying JSI function.
17
+ */
18
+ std::shared_ptr<jsi::Function> _function;
19
+ }
20
+
21
+ - (nonnull instancetype)initWith:(std::shared_ptr<jsi::Function>)function
22
+ runtime:(nonnull EXJavaScriptRuntime *)runtime
23
+ {
24
+ if (self = [super init]) {
25
+ _runtime = runtime;
26
+ _function = function;
27
+ }
28
+ return self;
29
+ }
30
+
31
+ - (nonnull EXJavaScriptValue *)callWithArguments:(nonnull NSArray<id> *)arguments
32
+ thisObject:(nullable EXJavaScriptObject *)thisObject
33
+ asConstructor:(BOOL)asConstructor
34
+ {
35
+ jsi::Runtime *runtime = [_runtime get];
36
+ std::vector<jsi::Value> vector = expo::convertNSArrayToStdVector(*runtime, arguments);
37
+ const jsi::Value *data = vector.data();
38
+ jsi::Value result;
39
+
40
+ if (asConstructor) {
41
+ result = _function->callAsConstructor(*runtime, data, arguments.count);
42
+ } else if (thisObject) {
43
+ result = _function->callWithThis(*runtime, *[thisObject get], data, arguments.count);
44
+ } else {
45
+ result = _function->call(*runtime, data, arguments.count);
46
+ }
47
+
48
+ std::shared_ptr<jsi::Value> resultPtr = std::make_shared<jsi::Value>(*runtime, result);
49
+ return [[EXJavaScriptValue alloc] initWithRuntime:_runtime value:resultPtr];
50
+ }
51
+
52
+ @end
@@ -11,7 +11,7 @@ ExpoModulesHostObject::ExpoModulesHostObject(EXAppContext *appContext) : appCont
11
11
 
12
12
  ExpoModulesHostObject::~ExpoModulesHostObject() {
13
13
  modulesCache.clear();
14
- [appContext setRuntime:nil];
14
+ appContext._runtime = nil;
15
15
  }
16
16
 
17
17
  jsi::Value ExpoModulesHostObject::get(jsi::Runtime &runtime, const jsi::PropNameID &name) {
@@ -15,7 +15,17 @@ public enum JavaScriptValueKind: String {
15
15
  case object
16
16
  }
17
17
 
18
- public extension JavaScriptValue {
18
+ /**
19
+ A protocol that JavaScript values, objects and functions can conform to.
20
+ */
21
+ protocol AnyJavaScriptValue {
22
+ /**
23
+ Tries to convert a raw JavaScript value to the conforming type.
24
+ */
25
+ static func convert(from value: JavaScriptValue, appContext: AppContext) throws -> Self
26
+ }
27
+
28
+ extension JavaScriptValue: AnyJavaScriptValue {
19
29
  var kind: JavaScriptValueKind {
20
30
  switch true {
21
31
  case isUndefined():
@@ -86,12 +96,29 @@ public extension JavaScriptValue {
86
96
  throw JavaScriptValueConversionException((kind: kind, target: "Object"))
87
97
  }
88
98
 
99
+ func asFunction() throws -> RawJavaScriptFunction {
100
+ if isFunction() {
101
+ return getFunction()
102
+ }
103
+ throw JavaScriptValueConversionException((kind: kind, target: "Function"))
104
+ }
105
+
89
106
  func asTypedArray() throws -> JavaScriptTypedArray {
90
107
  if let typedArray = getTypedArray() {
91
108
  return typedArray
92
109
  }
93
110
  throw JavaScriptValueConversionException((kind: kind, target: "TypedArray"))
94
111
  }
112
+
113
+ // MARK: - AnyJavaScriptValue
114
+
115
+ internal static func convert(from value: JavaScriptValue, appContext: AppContext) throws -> Self {
116
+ // It's already a `JavaScriptValue` so it should always pass through.
117
+ if let value = value as? Self {
118
+ return value
119
+ }
120
+ throw JavaScriptValueConversionException((kind: value.kind, target: String(describing: Self.self)))
121
+ }
95
122
  }
96
123
 
97
124
  internal final class JavaScriptValueConversionException: GenericException<(kind: JavaScriptValueKind, target: String)> {
@@ -4,7 +4,6 @@
4
4
 
5
5
  #import <ExpoModulesCore/EXInternalModule.h>
6
6
  #import <ExpoModulesCore/EXExportedModule.h>
7
- #import <ExpoModulesCore/EXViewManager.h>
8
7
  #import <ExpoModulesCore/EXModuleRegistryDelegate.h>
9
8
 
10
9
  NS_ASSUME_NONNULL_BEGIN
@@ -13,12 +12,10 @@ NS_ASSUME_NONNULL_BEGIN
13
12
 
14
13
  - (instancetype)initWithInternalModules:(NSSet<id<EXInternalModule>> *)internalModules
15
14
  exportedModules:(NSSet<EXExportedModule *> *)exportedModules
16
- viewManagers:(NSSet<EXViewManager *> *)viewManagers
17
15
  singletonModules:(NSSet *)singletonModules;
18
16
 
19
17
  - (void)registerInternalModule:(id<EXInternalModule>)internalModule;
20
18
  - (void)registerExportedModule:(EXExportedModule *)exportedModule;
21
- - (void)registerViewManager:(EXViewManager *)viewManager;
22
19
 
23
20
  - (void)setDelegate:(id<EXModuleRegistryDelegate>)delegate;
24
21
 
@@ -32,7 +29,6 @@ NS_ASSUME_NONNULL_BEGIN
32
29
 
33
30
  - (NSArray<id<EXInternalModule>> *)getAllInternalModules;
34
31
  - (NSArray<EXExportedModule *> *)getAllExportedModules;
35
- - (NSArray<EXViewManager *> *)getAllViewManagers;
36
32
  - (NSArray *)getAllSingletonModules;
37
33
 
38
34
  @end
@@ -14,7 +14,6 @@
14
14
  @property NSMapTable<Protocol *, NSMutableArray<id<EXInternalModule>> *> *internalModulesPreResolution;
15
15
  @property NSMapTable<Class, EXExportedModule *> *exportedModulesByClass;
16
16
  @property NSMutableDictionary<const NSString *, EXExportedModule *> *exportedModules;
17
- @property NSMutableDictionary<const NSString *, EXViewManager *> *viewManagerModules;
18
17
  @property NSMutableDictionary<const NSString *, id> *singletonModules;
19
18
 
20
19
  @property NSPointerArray *registryConsumers;
@@ -31,7 +30,6 @@
31
30
  _internalModulesPreResolution = [NSMapTable weakToStrongObjectsMapTable];
32
31
  _exportedModulesByClass = [NSMapTable weakToWeakObjectsMapTable];
33
32
  _exportedModules = [NSMutableDictionary dictionary];
34
- _viewManagerModules = [NSMutableDictionary dictionary];
35
33
  _singletonModules = [NSMutableDictionary dictionary];
36
34
  _registryConsumers = [NSPointerArray weakObjectsPointerArray];
37
35
  }
@@ -40,7 +38,6 @@
40
38
 
41
39
  - (instancetype)initWithInternalModules:(NSSet<id<EXInternalModule>> *)internalModules
42
40
  exportedModules:(NSSet<EXExportedModule *> *)exportedModules
43
- viewManagers:(NSSet<EXViewManager *> *)viewManagers
44
41
  singletonModules:(NSSet *)singletonModules
45
42
  {
46
43
  if (self = [self init]) {
@@ -52,10 +49,6 @@
52
49
  [self registerExportedModule:exportedModule];
53
50
  }
54
51
 
55
- for (EXViewManager *viewManager in viewManagers) {
56
- [self registerViewManager:viewManager];
57
- }
58
-
59
52
  for (id singletonModule in singletonModules) {
60
53
  [self registerSingletonModule:singletonModule];
61
54
  }
@@ -140,17 +133,6 @@
140
133
  [self maybeAddRegistryConsumer:exportedModule];
141
134
  }
142
135
 
143
- - (void)registerViewManager:(EXViewManager *)viewManager
144
- {
145
- const NSString *exportedModuleName = [[viewManager class] exportedModuleName];
146
- if (_viewManagerModules[exportedModuleName]) {
147
- EXLogInfo(@"View manager %@ overrides %@ as the module exported as %@.", viewManager, _viewManagerModules[exportedModuleName], exportedModuleName);
148
- }
149
-
150
- _viewManagerModules[exportedModuleName] = viewManager;
151
- [self maybeAddRegistryConsumer:viewManager];
152
- }
153
-
154
136
  - (void)registerSingletonModule:(id)singletonModule
155
137
  {
156
138
  if ([[singletonModule class] respondsToSelector:@selector(name)]) {
@@ -216,11 +198,6 @@
216
198
  return [_exportedModules allValues];
217
199
  }
218
200
 
219
- - (NSArray<EXViewManager *> *)getAllViewManagers
220
- {
221
- return [_viewManagerModules allValues];
222
- }
223
-
224
201
  - (NSArray *)getAllSingletonModules
225
202
  {
226
203
  return [_singletonModules allValues];
@@ -1,17 +1,14 @@
1
1
  // Copyright 2018-present 650 Industries. All rights reserved.
2
2
 
3
3
  #import <ExpoModulesCore/EXNativeModulesProxy.h>
4
- #import <ExpoModulesCore/EXViewManagerAdapter.h>
5
4
  #import <ExpoModulesCore/EXModuleRegistryAdapter.h>
6
5
  #import <ExpoModulesCore/EXModuleRegistryProvider.h>
7
- #import <ExpoModulesCore/EXViewManagerAdapterClassesRegistry.h>
8
6
  #import <ExpoModulesCore/EXModuleRegistryHolderReactModule.h>
9
7
  #import <ExpoModulesCore/EXReactNativeEventEmitter.h>
10
8
 
11
9
  @interface EXModuleRegistryAdapter ()
12
10
 
13
11
  @property (nonatomic, strong) EXModuleRegistryProvider *moduleRegistryProvider;
14
- @property (nonatomic, strong) EXViewManagerAdapterClassesRegistry *viewManagersClassesRegistry;
15
12
 
16
13
  @end
17
14
 
@@ -21,7 +18,6 @@
21
18
  {
22
19
  if (self = [super init]) {
23
20
  _moduleRegistryProvider = moduleRegistryProvider;
24
- _viewManagersClassesRegistry = [[EXViewManagerAdapterClassesRegistry alloc] init];
25
21
  }
26
22
  return self;
27
23
  }
@@ -43,18 +39,6 @@
43
39
  EXReactNativeEventEmitter *eventEmitter = [EXReactNativeEventEmitter new];
44
40
  [moduleRegistry registerInternalModule:eventEmitter];
45
41
 
46
- for (EXViewManager *viewManager in [moduleRegistry getAllViewManagers]) {
47
- Class viewManagerAdapterClass = [EXViewManagerAdapterClassesRegistry createViewManagerAdapterClassForViewManager:viewManager];
48
- [extraModules addObject:[[viewManagerAdapterClass alloc] init]];
49
- }
50
-
51
- // Silence React Native warning `Base module "%s" does not exist`
52
- // occurring when view manager class is subclassing another class
53
- // that is not RCTViewManager (in our case all the view manager adapters
54
- // subclass EXViewManagerAdapter, so RN expects to find EXViewManagerAdapter
55
- // exported.
56
- [extraModules addObject:[[EXViewManagerAdapter alloc] init]];
57
-
58
42
  // It is possible that among internal modules there are some RCTBridgeModules --
59
43
  // let's add them to extraModules here.
60
44
  for (id<EXInternalModule> module in [moduleRegistry getAllInternalModules]) {
@@ -110,7 +110,6 @@ void (^EXinitializeGlobalSingletonModulesSet)(void) = ^{
110
110
  {
111
111
  NSMutableSet<id<EXInternalModule>> *internalModules = [NSMutableSet set];
112
112
  NSMutableSet<EXExportedModule *> *exportedModules = [NSMutableSet set];
113
- NSMutableSet<EXViewManager *> *viewManagerModules = [NSMutableSet set];
114
113
 
115
114
  for (Class klass in [self.class getModulesClasses]) {
116
115
  if (![klass conformsToProtocol:@protocol(EXInternalModule)]) {
@@ -127,15 +126,10 @@ void (^EXinitializeGlobalSingletonModulesSet)(void) = ^{
127
126
  if ([instance isKindOfClass:[EXExportedModule class]]) {
128
127
  [exportedModules addObject:(EXExportedModule *)instance];
129
128
  }
130
-
131
- if ([instance isKindOfClass:[EXViewManager class]]) {
132
- [viewManagerModules addObject:(EXViewManager *)instance];
133
- }
134
129
  }
135
130
 
136
131
  EXModuleRegistry *moduleRegistry = [[EXModuleRegistry alloc] initWithInternalModules:internalModules
137
132
  exportedModules:exportedModules
138
- viewManagers:viewManagerModules
139
133
  singletonModules:_singletonModules];
140
134
  [moduleRegistry setDelegate:_moduleRegistryDelegate];
141
135
  return moduleRegistry;
@@ -16,9 +16,6 @@
16
16
 
17
17
  #import <ExpoModulesCore/EXNativeModulesProxy.h>
18
18
  #import <ExpoModulesCore/EXEventEmitter.h>
19
- #import <ExpoModulesCore/EXViewManager.h>
20
- #import <ExpoModulesCore/EXViewManagerAdapter.h>
21
- #import <ExpoModulesCore/EXViewManagerAdapterClassesRegistry.h>
22
19
  #import <ExpoModulesCore/EXModuleRegistryProvider.h>
23
20
  #import <ExpoModulesCore/EXReactNativeEventEmitter.h>
24
21
  #import <ExpoModulesCore/EXJSIInstaller.h>
@@ -178,19 +175,9 @@ RCT_EXPORT_MODULE(NativeUnimoduleProxy)
178
175
  [self assignExportedMethodsKeys:exportedMethodsNamesAccumulator[exportedModuleName] forModuleName:exportedModuleName];
179
176
  }
180
177
 
181
- // Also, add `viewManagersMetadata` for sanity check and testing purposes -- with names we know what managers to mock on UIManager
182
- NSArray<EXViewManager *> *viewManagers = [_exModuleRegistry getAllViewManagers];
183
- NSMutableDictionary<NSString *, NSDictionary *> *viewManagersMetadata = [[NSMutableDictionary alloc] initWithCapacity:[viewManagers count]];
184
-
185
- for (EXViewManager *viewManager in viewManagers) {
186
- viewManagersMetadata[viewManager.viewName] = @{
187
- @"propsNames": [[viewManager getPropsNames] allKeys]
188
- };
189
- }
190
-
191
178
  EXModulesProxyConfig *config = [[EXModulesProxyConfig alloc] initWithConstants:exportedModulesConstants
192
179
  methodNames:exportedMethodsNamesAccumulator
193
- viewManagers:viewManagersMetadata];
180
+ viewManagers:[NSMutableDictionary new]];
194
181
  // decorate legacy config with sweet expo-modules config
195
182
  [config addEntriesFromConfig:[_appContext expoModulesConfig]];
196
183
 
@@ -289,23 +276,6 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
289
276
 
290
277
  // Add modules from legacy module registry only when the NativeModulesProxy owns the registry.
291
278
  if (ownsModuleRegistry) {
292
- // Add dynamic wrappers for the classic view managers.
293
- for (EXViewManager *viewManager in [_exModuleRegistry getAllViewManagers]) {
294
- if (![visitedSweetModules containsObject:viewManager.viewName]) {
295
- Class viewManagerWrapperClass = [EXViewManagerAdapterClassesRegistry createViewManagerAdapterClassForViewManager:viewManager];
296
- [additionalModuleClasses addObject:viewManagerWrapperClass];
297
- [self registerLegacyComponentData:viewManagerWrapperClass inBridge:bridge];
298
- }
299
- }
300
-
301
- // View manager wrappers don't have their own prop configs, so we must register
302
- // their base view managers that provides common props such as `proxiedProperties`.
303
- // Otherwise, React Native may treat these props as invalid in subclassing views.
304
- [additionalModuleClasses addObject:[EXViewManagerAdapter class]];
305
- // Also, we have to register component data for the View Adapter.
306
- // Otherwise, it won't be recognized by the UIManager.
307
- [self registerLegacyComponentData:[EXViewManagerAdapter class] inBridge:bridge];
308
-
309
279
  // Some modules might need access to the bridge.
310
280
  for (id module in [_exModuleRegistry getAllInternalModules]) {
311
281
  if ([module conformsToProtocol:@protocol(RCTBridgeModule)]) {
@@ -8,7 +8,7 @@ public final class AppContext: NSObject {
8
8
  internal static func create() -> AppContext {
9
9
  let appContext = AppContext()
10
10
 
11
- appContext.runtime = JavaScriptRuntime()
11
+ appContext._runtime = JavaScriptRuntime()
12
12
  return appContext
13
13
  }
14
14
 
@@ -41,17 +41,17 @@ public final class AppContext: NSObject {
41
41
  public internal(set) weak var reactBridge: RCTBridge?
42
42
 
43
43
  /**
44
- JSI runtime of the running app.
44
+ Underlying JSI runtime of the running app.
45
45
  */
46
46
  @objc
47
- public var runtime: JavaScriptRuntime? {
47
+ public var _runtime: JavaScriptRuntime? {
48
48
  didSet {
49
- if runtime == nil {
49
+ if _runtime == nil {
50
50
  // When the runtime is unpinned from the context (e.g. deallocated),
51
51
  // we should make sure to release all JS objects from the memory.
52
52
  // Otherwise the JSCRuntime asserts may fail on deallocation.
53
53
  releaseRuntimeObjects()
54
- } else if runtime != oldValue {
54
+ } else if _runtime != oldValue {
55
55
  // Try to install ExpoModules host object automatically when the runtime changes.
56
56
  // TODO: Should we uninstall in the old runtime? (@tsapeta)
57
57
  try? installExpoModulesHostObject()
@@ -59,6 +59,18 @@ public final class AppContext: NSObject {
59
59
  }
60
60
  }
61
61
 
62
+ /**
63
+ JSI runtime of the running app.
64
+ */
65
+ public var runtime: JavaScriptRuntime {
66
+ get throws {
67
+ if let runtime = _runtime {
68
+ return runtime
69
+ }
70
+ throw Exceptions.RuntimeLost()
71
+ }
72
+ }
73
+
62
74
  /**
63
75
  Designated initializer without modules provider.
64
76
  */
@@ -100,6 +112,29 @@ public final class AppContext: NSObject {
100
112
  reactBridge?.dispatchBlock(runBlock, queue: RCTJSThread)
101
113
  }
102
114
 
115
+ // MARK: - Classes
116
+
117
+ /**
118
+ A registry containing references to JavaScript classes.
119
+ - ToDo: Make one registry per module, not the entire app context.
120
+ Perhaps it should be kept by the `ModuleHolder`.
121
+ */
122
+ internal let classRegistry = ClassRegistry()
123
+
124
+ /**
125
+ Creates a new JavaScript object with the class prototype associated with the given native class.
126
+ - ToDo: Move this to `ModuleHolder` along the `classRegistry` property.
127
+ */
128
+ internal func newObject(nativeClassId: ObjectIdentifier) throws -> JavaScriptObject? {
129
+ guard let jsClass = classRegistry.getJavaScriptClass(nativeClassId: nativeClassId) else {
130
+ return nil
131
+ }
132
+ let prototype = try jsClass.getProperty("prototype").asObject()
133
+ let object = try runtime.createObject(withPrototype: prototype)
134
+
135
+ return object
136
+ }
137
+
103
138
  // MARK: - Legacy modules
104
139
 
105
140
  /**
@@ -308,7 +343,7 @@ public final class AppContext: NSObject {
308
343
  // MARK: - Runtime
309
344
 
310
345
  internal func installExpoModulesHostObject() throws {
311
- guard runtime != nil else {
346
+ guard _runtime != nil else {
312
347
  throw RuntimeLostException()
313
348
  }
314
349
  EXJavaScriptRuntimeManager.installExpoModulesHostObject(self)
@@ -318,6 +353,11 @@ public final class AppContext: NSObject {
318
353
  Unsets runtime objects that we hold for each module.
319
354
  */
320
355
  private func releaseRuntimeObjects() {
356
+ // FIXME: Release objects only from the current context.
357
+ // Making the registry non-global (similarly to the class registry) would fix it.
358
+ SharedObjectRegistry.clear()
359
+ classRegistry.clear()
360
+
321
361
  for module in moduleRegistry {
322
362
  module.javaScriptObject = nil
323
363
  }
@@ -2,16 +2,16 @@
2
2
 
3
3
  /**
4
4
  A protocol that allows custom classes or structs to be used as function arguments.
5
- It requires static `convert(from:)` function that knows how to convert incoming
5
+ It requires static `convert(from:appContext:)` function that knows how to convert incoming
6
6
  value of `Any` type to the type implemented by this protocol. It should throw an error
7
7
  when the value is not recognized, is invalid or doesn't meet type requirements.
8
8
  */
9
9
  public protocol Convertible: AnyArgument {
10
10
  /**
11
- Converts any value to the instance of its class (or struct).
11
+ Converts any value to the instance of its class (or struct) in the given app context.
12
12
  Throws an error when given value cannot be converted.
13
13
  */
14
- static func convert(from value: Any?) throws -> Self
14
+ static func convert(from value: Any?, appContext: AppContext) throws -> Self
15
15
  }
16
16
 
17
17
  @available(*, deprecated, renamed: "Convertible")
@@ -12,7 +12,7 @@ import CoreGraphics
12
12
  // MARK: - Foundation
13
13
 
14
14
  extension URL: Convertible {
15
- public static func convert(from value: Any?) throws -> Self {
15
+ public static func convert(from value: Any?, appContext: AppContext) throws -> Self {
16
16
  guard let value = value as? String else {
17
17
  throw Conversions.ConvertingException<URL>(value)
18
18
  }
@@ -47,7 +47,7 @@ internal class UrlContainsInvalidCharactersException: Exception {
47
47
  // MARK: - CoreGraphics
48
48
 
49
49
  extension CGPoint: Convertible {
50
- public static func convert(from value: Any?) throws -> CGPoint {
50
+ public static func convert(from value: Any?, appContext: AppContext) throws -> CGPoint {
51
51
  if let value = value as? [Double], value.count == 2 {
52
52
  return CGPoint(x: value[0], y: value[1])
53
53
  }
@@ -60,7 +60,7 @@ extension CGPoint: Convertible {
60
60
  }
61
61
 
62
62
  extension CGSize: Convertible {
63
- public static func convert(from value: Any?) throws -> CGSize {
63
+ public static func convert(from value: Any?, appContext: AppContext) throws -> CGSize {
64
64
  if let value = value as? [Double], value.count == 2 {
65
65
  return CGSize(width: value[0], height: value[1])
66
66
  }
@@ -73,7 +73,7 @@ extension CGSize: Convertible {
73
73
  }
74
74
 
75
75
  extension CGVector: Convertible {
76
- public static func convert(from value: Any?) throws -> CGVector {
76
+ public static func convert(from value: Any?, appContext: AppContext) throws -> CGVector {
77
77
  if let value = value as? [Double], value.count == 2 {
78
78
  return CGVector(dx: value[0], dy: value[1])
79
79
  }
@@ -86,7 +86,7 @@ extension CGVector: Convertible {
86
86
  }
87
87
 
88
88
  extension CGRect: Convertible {
89
- public static func convert(from value: Any?) throws -> CGRect {
89
+ public static func convert(from value: Any?, appContext: AppContext) throws -> CGRect {
90
90
  if let value = value as? [Double], value.count == 4 {
91
91
  return CGRect(x: value[0], y: value[1], width: value[2], height: value[3])
92
92
  }
@@ -37,35 +37,41 @@ public final class ClassComponent: ObjectDefinition {
37
37
 
38
38
  // MARK: - JavaScriptObjectBuilder
39
39
 
40
- public override func build(inRuntime runtime: JavaScriptRuntime) -> JavaScriptObject {
41
- let klass = runtime.createClass(name) { [weak self, weak runtime] this, arguments in
42
- guard let self = self, let runtime = runtime else {
40
+ public override func build(appContext: AppContext) throws -> JavaScriptObject {
41
+ let klass = try appContext.runtime.createClass(name) { [weak self, weak appContext] this, arguments in
42
+ guard let self = self, let appContext else {
43
43
  // TODO: Throw an exception? (@tsapeta)
44
44
  return
45
45
  }
46
- // The properties can't go into the prototype as they would be shared across all instances.
47
- // Instead, we decorate the instance object on initialization.
48
- self.decorateWithProperties(runtime: runtime, object: this)
49
46
 
50
47
  // Call the native constructor when defined.
51
- let result = try? self.constructor?.call(by: this, withArguments: arguments)
48
+ let result = try? self.constructor?.call(by: this, withArguments: arguments, appContext: appContext)
52
49
 
53
50
  // Register the shared object if returned by the constructor.
54
51
  if let result = result as? SharedObject {
55
52
  SharedObjectRegistry.add(native: result, javaScript: this)
56
53
  }
57
54
  }
58
- decorate(object: klass, inRuntime: runtime)
55
+
56
+ try decorate(object: klass, appContext: appContext)
57
+
58
+ // Register the JS class and its associated native type.
59
+ if let sharedObjectType = associatedType as? DynamicSharedObjectType {
60
+ appContext.classRegistry.register(nativeClassId: sharedObjectType.typeIdentifier, javaScriptClass: klass)
61
+ }
62
+
59
63
  return klass
60
64
  }
61
65
 
62
- public override func decorate(object: JavaScriptObject, inRuntime runtime: JavaScriptRuntime) {
66
+ public override func decorate(object: JavaScriptObject, appContext: AppContext) throws {
63
67
  // Here we actually don't decorate the input object (constructor) but its prototype.
64
68
  // Properties are intentionally skipped here — they have to decorate an instance instead of the prototype.
65
69
  let prototype = object.getProperty("prototype").getObject()
66
- decorateWithConstants(runtime: runtime, object: prototype)
67
- decorateWithFunctions(runtime: runtime, object: prototype)
68
- decorateWithClasses(runtime: runtime, object: prototype)
70
+
71
+ decorateWithConstants(object: prototype)
72
+ try decorateWithFunctions(object: prototype, appContext: appContext)
73
+ try decorateWithClasses(object: prototype, appContext: appContext)
74
+ try decorateWithProperties(object: prototype, appContext: appContext)
69
75
  }
70
76
  }
71
77
 
@@ -0,0 +1,31 @@
1
+ // Copyright 2023-present 650 Industries. All rights reserved.
2
+
3
+ internal final class ClassRegistry {
4
+ var nativeToJS = [ObjectIdentifier: JavaScriptWeakObject]()
5
+
6
+ // MARK: - Accessing
7
+
8
+ func getJavaScriptClass(nativeClassId: ObjectIdentifier) -> JavaScriptObject? {
9
+ return nativeToJS[nativeClassId]?.lock()
10
+ }
11
+
12
+ func getJavaScriptClass(nativeClass: SharedObject.Type) -> JavaScriptObject? {
13
+ let nativeClassId = ObjectIdentifier(nativeClass)
14
+ return getJavaScriptClass(nativeClassId: nativeClassId)
15
+ }
16
+
17
+ // MARK: - Registration
18
+
19
+ func register(nativeClassId: ObjectIdentifier, javaScriptClass: JavaScriptObject) {
20
+ nativeToJS[nativeClassId] = javaScriptClass.createWeak()
21
+ }
22
+
23
+ func register(nativeClass: SharedObject.Type, javaScriptClass: JavaScriptObject) {
24
+ let nativeClassId = ObjectIdentifier(nativeClass)
25
+ register(nativeClassId: nativeClassId, javaScriptClass: javaScriptClass)
26
+ }
27
+
28
+ internal func clear() {
29
+ nativeToJS.removeAll()
30
+ }
31
+ }