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
@@ -140,9 +140,18 @@ static std::unordered_map<std::string, ExpoViewComponentDescriptor::Flavor> _com
140
140
  - (void)updateProps:(const facebook::react::Props::Shared &)props oldProps:(const facebook::react::Props::Shared &)oldProps
141
141
  {
142
142
  const auto &newViewProps = *std::static_pointer_cast<ExpoViewProps const>(props);
143
- NSDictionary<NSString *, id> *proxiedProperties = convertFollyDynamicToId(newViewProps.proxiedProperties);
143
+ NSMutableDictionary<NSString *, id> *propsMap = [[NSMutableDictionary alloc] init];
144
144
 
145
- [self updateProps:proxiedProperties];
145
+ for (const auto &item : newViewProps.propsMap) {
146
+ NSString *propName = [NSString stringWithUTF8String:item.first.c_str()];
147
+
148
+ // Ignore props inherited from the base view and Yoga.
149
+ if ([self supportsPropWithName:propName]) {
150
+ propsMap[propName] = convertFollyDynamicToId(item.second);
151
+ }
152
+ }
153
+
154
+ [self updateProps:propsMap];
146
155
  [super updateProps:props oldProps:oldProps];
147
156
  [self viewDidUpdateProps];
148
157
  }
@@ -174,6 +183,12 @@ static std::unordered_map<std::string, ExpoViewComponentDescriptor::Flavor> _com
174
183
  // Implemented in `ExpoFabricView.swift`
175
184
  }
176
185
 
186
+ - (BOOL)supportsPropWithName:(nonnull NSString *)name
187
+ {
188
+ // Implemented in `ExpoFabricView.swift`
189
+ return NO;
190
+ }
191
+
177
192
  #pragma mark - Methods to override in the subclass
178
193
 
179
194
  - (nullable EXAppContext *)__injectedAppContext
@@ -35,7 +35,7 @@ static NSString *modulesHostObjectLegacyPropertyName = @"ExpoModules";
35
35
 
36
36
  + (BOOL)installExpoModulesHostObject:(nonnull EXAppContext *)appContext
37
37
  {
38
- EXJavaScriptRuntime *runtime = [appContext runtime];
38
+ EXJavaScriptRuntime *runtime = [appContext _runtime];
39
39
 
40
40
  // The runtime may be unavailable, e.g. remote debugger is enabled or it hasn't been set yet.
41
41
  if (!runtime) {
@@ -26,6 +26,11 @@ using ClassConstructor = std::function<void(jsi::Runtime &runtime, const jsi::Va
26
26
 
27
27
  std::shared_ptr<jsi::Function> createClass(jsi::Runtime &runtime, const char *name, ClassConstructor constructor);
28
28
 
29
+ /**
30
+ Creates a new object, using the provided object as the prototype.
31
+ */
32
+ std::shared_ptr<jsi::Object> createObjectWithPrototype(jsi::Runtime &runtime, std::shared_ptr<jsi::Object> prototype);
33
+
29
34
  #pragma mark - Weak objects
30
35
 
31
36
  /**
@@ -115,6 +115,23 @@ std::shared_ptr<jsi::Function> createClass(jsi::Runtime &runtime, const char *na
115
115
  return std::make_shared<jsi::Function>(klass.asFunction(runtime));
116
116
  }
117
117
 
118
+ std::shared_ptr<jsi::Object> createObjectWithPrototype(jsi::Runtime &runtime, std::shared_ptr<jsi::Object> prototype) {
119
+ // Get the "Object" class.
120
+ jsi::Object objectClass = runtime
121
+ .global()
122
+ .getPropertyAsObject(runtime, "Object");
123
+
124
+ // Call "Object.create(prototype)" to create an object with the given prototype without calling the constructor.
125
+ jsi::Object object = objectClass
126
+ .getPropertyAsFunction(runtime, "create")
127
+ .callWithThis(runtime, objectClass, {
128
+ jsi::Value(runtime, *prototype)
129
+ })
130
+ .asObject(runtime);
131
+
132
+ return std::make_shared<jsi::Object>(std::move(object));
133
+ }
134
+
118
135
  #pragma mark - Weak objects
119
136
 
120
137
  bool isWeakRefSupported(jsi::Runtime &runtime) {
@@ -103,6 +103,11 @@ typedef void (^ClassConstructorBlock)(EXJavaScriptObject * _Nonnull thisValue, N
103
103
  - (nonnull EXJavaScriptObject *)createClass:(nonnull NSString *)name
104
104
  constructor:(nonnull ClassConstructorBlock)constructor;
105
105
 
106
+ /**
107
+ Creates a new object, using the provided object as the prototype.
108
+ */
109
+ - (nullable EXJavaScriptObject *)createObjectWithPrototype:(nonnull EXJavaScriptObject *)prototype;
110
+
106
111
  #pragma mark - Script evaluation
107
112
 
108
113
  /**
@@ -160,6 +160,12 @@ static NSString *mainObjectPropertyName = @"expo";
160
160
  return [[EXJavaScriptObject alloc] initWith:klass runtime:self];
161
161
  }
162
162
 
163
+ - (nullable EXJavaScriptObject *)createObjectWithPrototype:(nonnull EXJavaScriptObject *)prototype
164
+ {
165
+ std::shared_ptr<jsi::Object> object = expo::createObjectWithPrototype(*_runtime, [prototype getShared]);
166
+ return object ? [[EXJavaScriptObject alloc] initWith:object runtime:self] : nil;
167
+ }
168
+
163
169
  #pragma mark - Script evaluation
164
170
 
165
171
  - (nonnull EXJavaScriptValue *)evaluateScript:(nonnull NSString *)scriptSource
@@ -9,6 +9,7 @@ namespace jsi = facebook::jsi;
9
9
  #endif // __cplusplus
10
10
 
11
11
  @class EXJavaScriptRuntime;
12
+ @class EXRawJavaScriptFunction;
12
13
  @class EXJavaScriptTypedArray;
13
14
 
14
15
  /**
@@ -49,6 +50,7 @@ NS_SWIFT_NAME(JavaScriptValue)
49
50
  - (nonnull NSArray<EXJavaScriptValue *> *)getArray;
50
51
  - (nonnull NSDictionary<NSString *, id> *)getDictionary;
51
52
  - (nonnull EXJavaScriptObject *)getObject;
53
+ - (nonnull EXRawJavaScriptFunction *)getFunction;
52
54
  - (nullable EXJavaScriptTypedArray *)getTypedArray;
53
55
 
54
56
  #pragma mark - Helpers
@@ -3,6 +3,7 @@
3
3
  #import <ExpoModulesCore/EXJSIConversions.h>
4
4
  #import <ExpoModulesCore/EXJavaScriptValue.h>
5
5
  #import <ExpoModulesCore/EXJavaScriptRuntime.h>
6
+ #import <ExpoModulesCore/EXRawJavaScriptFunction.h>
6
7
  #import <ExpoModulesCore/EXJavaScriptTypedArray.h>
7
8
  #import <ExpoModulesCore/TypedArray.h>
8
9
 
@@ -142,6 +143,13 @@
142
143
  return [[EXJavaScriptObject alloc] initWith:objectPtr runtime:_runtime];
143
144
  }
144
145
 
146
+ - (nonnull EXRawJavaScriptFunction *)getFunction
147
+ {
148
+ jsi::Runtime *runtime = [_runtime get];
149
+ std::shared_ptr<jsi::Function> functionPtr = std::make_shared<jsi::Function>(_value->asObject(*runtime).asFunction(*runtime));
150
+ return [[EXRawJavaScriptFunction alloc] initWith:functionPtr runtime:_runtime];
151
+ }
152
+
145
153
  - (nullable EXJavaScriptTypedArray *)getTypedArray
146
154
  {
147
155
  if (![self isTypedArray]) {
@@ -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
  }