expo-modules-core 0.6.4 → 0.7.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 (159) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +1 -1
  3. package/android/build.gradle +5 -5
  4. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +11 -1
  5. package/android/src/main/java/expo/modules/kotlin/DynamicExtenstions.kt +5 -3
  6. package/android/src/main/java/expo/modules/kotlin/KPromiseWrapper.kt +8 -2
  7. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +13 -4
  8. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +7 -6
  9. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +6 -1
  10. package/android/src/main/java/expo/modules/kotlin/Promise.kt +1 -1
  11. package/android/src/main/java/expo/modules/kotlin/callbacks/Callback.kt +5 -0
  12. package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallback.kt +28 -0
  13. package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallbackDelegate.kt +27 -0
  14. package/android/src/main/java/expo/modules/kotlin/defaultmodules/ErrorManagerModule.kt +25 -0
  15. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +68 -8
  16. package/android/src/main/java/expo/modules/kotlin/exception/ExceptionDecorator.kt +11 -0
  17. package/android/src/main/java/expo/modules/kotlin/methods/AnyMethod.kt +13 -14
  18. package/android/src/main/java/expo/modules/kotlin/modules/DefinitionMarker.kt +4 -0
  19. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +3 -2
  20. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +44 -4
  21. package/android/src/main/java/expo/modules/kotlin/records/Record.kt +39 -0
  22. package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +14 -7
  23. package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +11 -5
  24. package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +10 -4
  25. package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +12 -6
  26. package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +29 -13
  27. package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +2 -1
  28. package/android/src/main/java/expo/modules/kotlin/views/CallbacksDefinition.kt +3 -0
  29. package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +22 -0
  30. package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +22 -0
  31. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +27 -2
  32. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +29 -1
  33. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +59 -2
  34. package/build/EventEmitter.d.ts +1 -0
  35. package/build/EventEmitter.d.ts.map +1 -0
  36. package/build/NativeModulesProxy.d.ts +1 -0
  37. package/build/NativeModulesProxy.d.ts.map +1 -0
  38. package/build/NativeModulesProxy.native.d.ts +1 -0
  39. package/build/NativeModulesProxy.native.d.ts.map +1 -0
  40. package/build/NativeModulesProxy.types.d.ts +1 -0
  41. package/build/NativeModulesProxy.types.d.ts.map +1 -0
  42. package/build/NativeViewManagerAdapter.d.ts +1 -0
  43. package/build/NativeViewManagerAdapter.d.ts.map +1 -0
  44. package/build/NativeViewManagerAdapter.native.d.ts +1 -0
  45. package/build/NativeViewManagerAdapter.native.d.ts.map +1 -0
  46. package/build/PermissionsHook.d.ts +1 -0
  47. package/build/PermissionsHook.d.ts.map +1 -0
  48. package/build/PermissionsInterface.d.ts +1 -0
  49. package/build/PermissionsInterface.d.ts.map +1 -0
  50. package/build/Platform.d.ts +1 -0
  51. package/build/Platform.d.ts.map +1 -0
  52. package/build/SyntheticPlatformEmitter.d.ts +1 -0
  53. package/build/SyntheticPlatformEmitter.d.ts.map +1 -0
  54. package/build/SyntheticPlatformEmitter.web.d.ts +1 -0
  55. package/build/SyntheticPlatformEmitter.web.d.ts.map +1 -0
  56. package/build/deprecate.d.ts +1 -0
  57. package/build/deprecate.d.ts.map +1 -0
  58. package/build/environment/browser.d.ts +1 -0
  59. package/build/environment/browser.d.ts.map +1 -0
  60. package/build/environment/browser.web.d.ts +1 -0
  61. package/build/environment/browser.web.d.ts.map +1 -0
  62. package/build/errors/CodedError.d.ts +1 -0
  63. package/build/errors/CodedError.d.ts.map +1 -0
  64. package/build/errors/UnavailabilityError.d.ts +1 -0
  65. package/build/errors/UnavailabilityError.d.ts.map +1 -0
  66. package/build/index.d.ts +3 -0
  67. package/build/index.d.ts.map +1 -0
  68. package/build/index.js +2 -0
  69. package/build/index.js.map +1 -1
  70. package/build/requireNativeModule.d.ts +16 -0
  71. package/build/requireNativeModule.d.ts.map +1 -0
  72. package/build/requireNativeModule.js +18 -0
  73. package/build/requireNativeModule.js.map +1 -0
  74. package/build/sweet/NativeErrorManager.d.ts +3 -0
  75. package/build/sweet/NativeErrorManager.d.ts.map +1 -0
  76. package/build/sweet/NativeErrorManager.js +3 -0
  77. package/build/sweet/NativeErrorManager.js.map +1 -0
  78. package/build/sweet/setUpErrorManager.fx.d.ts +2 -0
  79. package/build/sweet/setUpErrorManager.fx.d.ts.map +1 -0
  80. package/build/sweet/setUpErrorManager.fx.js +11 -0
  81. package/build/sweet/setUpErrorManager.fx.js.map +1 -0
  82. package/ios/AppDelegates/ExpoAppDelegate.swift +18 -10
  83. package/ios/JSI/ExpoModulesHostObject.h +33 -0
  84. package/ios/JSI/ExpoModulesHostObject.mm +40 -0
  85. package/ios/JSI/ExpoModulesProxySpec.h +4 -0
  86. package/ios/JSI/ExpoModulesProxySpec.mm +1 -3
  87. package/ios/JSI/JSIConversions.h +2 -0
  88. package/ios/JSI/JSIConversions.mm +9 -0
  89. package/ios/JSI/JSIInstaller.h +10 -0
  90. package/ios/JSI/JSIInstaller.mm +14 -2
  91. package/ios/JSI/JavaScriptObject.h +60 -0
  92. package/ios/JSI/JavaScriptObject.mm +93 -0
  93. package/ios/JSI/JavaScriptRuntime.h +54 -0
  94. package/ios/JSI/JavaScriptRuntime.mm +102 -0
  95. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +2 -12
  96. package/ios/NativeModulesProxy/EXComponentDataCompatibleWrapper.h +16 -0
  97. package/ios/NativeModulesProxy/EXComponentDataCompatibleWrapper.m +28 -0
  98. package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +90 -66
  99. package/ios/RCTComponentData+Privates.h +12 -0
  100. package/ios/ReactDelegates/ExpoReactDelegate.swift +2 -2
  101. package/ios/ReactDelegates/ExpoReactDelegateHandler.swift +3 -3
  102. package/ios/ReactDelegates/ModulePriorities.swift +1 -1
  103. package/ios/Swift/AppContext.swift +38 -4
  104. package/ios/Swift/Arguments/ArgumentType.swift +4 -0
  105. package/ios/Swift/Arguments/Convertibles.swift +13 -13
  106. package/ios/Swift/Arguments/Types/EnumArgumentType.swift +11 -17
  107. package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +1 -1
  108. package/ios/Swift/Arguments/Types/RawArgumentType.swift +2 -2
  109. package/ios/Swift/Conversions.swift +51 -56
  110. package/ios/Swift/EventListener.swift +8 -10
  111. package/ios/Swift/Events/Callback.swift +66 -0
  112. package/ios/Swift/Events/Event.swift +43 -0
  113. package/ios/Swift/Exceptions/ChainableException.swift +51 -0
  114. package/ios/Swift/{CodedError.swift → Exceptions/CodedError.swift} +1 -12
  115. package/ios/Swift/Exceptions/Exception.swift +62 -0
  116. package/ios/Swift/Exceptions/ExceptionOrigin.swift +28 -0
  117. package/ios/Swift/Exceptions/GenericException.swift +20 -0
  118. package/ios/Swift/Exceptions/UnexpectedException.swift +16 -0
  119. package/ios/Swift/Functions/AnyFunction.swift +11 -1
  120. package/ios/Swift/Functions/ConcreteFunction.swift +37 -16
  121. package/ios/Swift/JavaScriptUtils.swift +43 -0
  122. package/ios/Swift/ModuleHolder.swift +53 -14
  123. package/ios/Swift/ModuleRegistry.swift +4 -1
  124. package/ios/Swift/Modules/AnyModule.swift +0 -1
  125. package/ios/Swift/Modules/ModuleDefinition.swift +4 -13
  126. package/ios/Swift/Modules/ModuleDefinitionBuilder.swift +0 -1
  127. package/ios/Swift/Modules/ModuleDefinitionComponents.swift +0 -188
  128. package/ios/Swift/ModulesProvider.swift +0 -1
  129. package/ios/Swift/Objects/ObjectDefinition.swift +30 -0
  130. package/ios/Swift/Objects/ObjectDefinitionComponents.swift +208 -0
  131. package/ios/Swift/Promise.swift +8 -3
  132. package/ios/Swift/Records/AnyField.swift +7 -0
  133. package/ios/Swift/Records/Field.swift +24 -19
  134. package/ios/Swift/Records/FieldOption.swift +1 -1
  135. package/ios/Swift/Records/Record.swift +12 -4
  136. package/ios/Swift/SwiftInteropBridge.swift +39 -10
  137. package/ios/Swift/Views/AnyViewProp.swift +1 -1
  138. package/ios/Swift/Views/ComponentData.swift +95 -0
  139. package/ios/Swift/Views/ConcreteViewProp.swift +6 -8
  140. package/ios/Swift/Views/ViewFactory.swift +1 -1
  141. package/ios/Swift/Views/ViewManagerDefinition.swift +23 -2
  142. package/ios/Swift/Views/ViewManagerDefinitionBuilder.swift +0 -1
  143. package/ios/Swift/Views/ViewManagerDefinitionComponents.swift +26 -0
  144. package/ios/Swift/Views/ViewModuleWrapper.swift +5 -2
  145. package/ios/Tests/ArgumentTypeSpec.swift +3 -4
  146. package/ios/Tests/ConstantsSpec.swift +4 -4
  147. package/ios/Tests/ConvertiblesSpec.swift +33 -33
  148. package/ios/Tests/ExceptionsSpec.swift +112 -0
  149. package/ios/Tests/FunctionSpec.swift +20 -22
  150. package/ios/Tests/FunctionWithConvertiblesSpec.swift +2 -2
  151. package/ios/Tests/Mocks/ModuleMocks.swift +1 -1
  152. package/ios/Tests/Mocks/ModulesProviderMock.swift +0 -1
  153. package/ios/Tests/ModuleEventListenersSpec.swift +1 -1
  154. package/ios/Tests/RecordSpec.swift +7 -17
  155. package/package.json +3 -3
  156. package/src/index.ts +4 -0
  157. package/src/requireNativeModule.ts +29 -0
  158. package/src/sweet/NativeErrorManager.ts +2 -0
  159. package/src/sweet/setUpErrorManager.fx.ts +12 -0
@@ -0,0 +1,54 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoModulesCore/JavaScriptObject.h>
4
+
5
+ #ifdef __cplusplus
6
+ #import <ReactCommon/CallInvoker.h>
7
+
8
+ namespace jsi = facebook::jsi;
9
+ namespace react = facebook::react;
10
+ #endif // __cplusplus
11
+
12
+ @interface JavaScriptRuntime : NSObject
13
+
14
+ #ifdef __cplusplus
15
+ typedef jsi::Value (^JSHostFunctionBlock)(jsi::Runtime &runtime, std::shared_ptr<react::CallInvoker> callInvoker, NSArray * _Nonnull arguments);
16
+
17
+ - (nonnull instancetype)initWithRuntime:(jsi::Runtime &)runtime
18
+ callInvoker:(std::shared_ptr<react::CallInvoker>)callInvoker;
19
+
20
+ /**
21
+ Returns the underlying runtime object.
22
+ */
23
+ - (nonnull jsi::Runtime *)get;
24
+
25
+ /**
26
+ Returns the call invoker the runtime was initialized with.
27
+ */
28
+ - (std::shared_ptr<react::CallInvoker>)callInvoker;
29
+
30
+ /**
31
+ Wraps given host object to `JavaScriptObject`.
32
+ */
33
+ - (nonnull JavaScriptObject *)createHostObject:(std::shared_ptr<jsi::HostObject>)jsiHostObjectPtr;
34
+
35
+ - (jsi::Function)createSyncFunction:(nonnull NSString *)name
36
+ argsCount:(NSInteger)argsCount
37
+ block:(nonnull JSSyncFunctionBlock)block;
38
+
39
+ - (jsi::Function)createAsyncFunction:(nonnull NSString *)name
40
+ argsCount:(NSInteger)argsCount
41
+ block:(nonnull JSAsyncFunctionBlock)block;
42
+ #endif // __cplusplus
43
+
44
+ /**
45
+ Returns the runtime global object for use in Swift.
46
+ */
47
+ - (nonnull JavaScriptObject *)global;
48
+
49
+ /**
50
+ Creates a new object for use in Swift.
51
+ */
52
+ - (nonnull JavaScriptObject *)createObject;
53
+
54
+ @end
@@ -0,0 +1,102 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ #import <jsi/jsi.h>
4
+
5
+ #import <ExpoModulesCore/JavaScriptRuntime.h>
6
+ #import <ExpoModulesCore/ExpoModulesHostObject.h>
7
+ #import <ExpoModulesCore/Swift.h>
8
+
9
+ using namespace facebook;
10
+
11
+ @implementation JavaScriptRuntime {
12
+ jsi::Runtime *_runtime;
13
+ std::shared_ptr<react::CallInvoker> _jsCallInvoker;
14
+
15
+ JavaScriptObject *_global;
16
+ }
17
+
18
+ - (nonnull instancetype)initWithRuntime:(jsi::Runtime &)runtime callInvoker:(std::shared_ptr<react::CallInvoker>)callInvoker
19
+ {
20
+ if (self = [super init]) {
21
+ _runtime = &runtime;
22
+ _jsCallInvoker = callInvoker;
23
+
24
+ auto jsGlobalPtr = std::make_shared<jsi::Object>(_runtime->global());
25
+ _global = [[JavaScriptObject alloc] initWith:jsGlobalPtr runtime:self];
26
+ }
27
+ return self;
28
+ }
29
+
30
+ - (nonnull jsi::Runtime *)get
31
+ {
32
+ return _runtime;
33
+ }
34
+
35
+ - (std::shared_ptr<react::CallInvoker>)callInvoker
36
+ {
37
+ return _jsCallInvoker;
38
+ }
39
+
40
+ - (nonnull JavaScriptObject *)createObject
41
+ {
42
+ auto jsObjectPtr = std::make_shared<jsi::Object>(*_runtime);
43
+ return [[JavaScriptObject alloc] initWith:jsObjectPtr runtime:self];
44
+ }
45
+
46
+ - (nonnull JavaScriptObject *)createHostObject:(std::shared_ptr<jsi::HostObject>)jsiHostObjectPtr
47
+ {
48
+ auto jsObjectPtr = std::make_shared<jsi::Object>(jsi::Object::createFromHostObject(*_runtime, jsiHostObjectPtr));
49
+ return [[JavaScriptObject alloc] initWith:jsObjectPtr runtime:self];
50
+ }
51
+
52
+ - (nonnull JavaScriptObject *)global
53
+ {
54
+ return _global;
55
+ }
56
+
57
+ - (jsi::Function)createSyncFunction:(nonnull NSString *)name
58
+ argsCount:(NSInteger)argsCount
59
+ block:(nonnull JSSyncFunctionBlock)block
60
+ {
61
+ return [self createHostFunction:name argsCount:argsCount block:^jsi::Value(jsi::Runtime &runtime, std::shared_ptr<react::CallInvoker> callInvoker, NSArray * _Nonnull arguments) {
62
+ return expo::convertObjCObjectToJSIValue(runtime, block(arguments));
63
+ }];
64
+ }
65
+
66
+ - (jsi::Function)createAsyncFunction:(nonnull NSString *)name
67
+ argsCount:(NSInteger)argsCount
68
+ block:(nonnull JSAsyncFunctionBlock)block
69
+ {
70
+ return [self createHostFunction:name argsCount:argsCount block:^jsi::Value(jsi::Runtime &runtime, std::shared_ptr<react::CallInvoker> callInvoker, NSArray *arguments) {
71
+ // The function that is invoked as a setup of the JavaScript `Promise`.
72
+ auto promiseSetup = [callInvoker, block, arguments](jsi::Runtime &runtime, std::shared_ptr<Promise> promise) {
73
+ expo::callPromiseSetupWithBlock(runtime, callInvoker, promise, ^(RCTPromiseResolveBlock resolver, RCTPromiseRejectBlock rejecter) {
74
+ block(arguments, resolver, rejecter);
75
+ });
76
+ };
77
+ return createPromiseAsJSIValue(runtime, promiseSetup);
78
+ }];
79
+ }
80
+
81
+ #pragma mark - Private
82
+
83
+ typedef jsi::Value (^JSHostFunctionBlock)(jsi::Runtime &runtime, std::shared_ptr<react::CallInvoker> callInvoker, NSArray * _Nonnull arguments);
84
+
85
+ - (jsi::Function)createHostFunction:(nonnull NSString *)name
86
+ argsCount:(NSInteger)argsCount
87
+ block:(nonnull JSHostFunctionBlock)block
88
+ {
89
+ jsi::PropNameID propNameId = jsi::PropNameID::forAscii(*_runtime, [name UTF8String], [name length]);
90
+ std::weak_ptr<react::CallInvoker> weakCallInvoker = _jsCallInvoker;
91
+ jsi::HostFunctionType function = [weakCallInvoker, block](jsi::Runtime &runtime, const jsi::Value &thisVal, const jsi::Value *args, size_t count) -> jsi::Value {
92
+ if (auto callInvoker = weakCallInvoker.lock()) {
93
+ NSArray *arguments = expo::convertJSIValuesToNSArray(runtime, args, count, callInvoker);
94
+ return block(runtime, callInvoker, arguments);
95
+ }
96
+ // TODO: We should throw some kind of error.
97
+ return jsi::Value::undefined();
98
+ };
99
+ return jsi::Function::createFromHostFunction(*_runtime, propNameId, (unsigned int)argsCount, function);
100
+ }
101
+
102
+ @end
@@ -55,18 +55,9 @@
55
55
  EXReactNativeEventEmitter *eventEmitter = [EXReactNativeEventEmitter new];
56
56
  [moduleRegistry registerInternalModule:eventEmitter];
57
57
 
58
- NSMutableSet *exportedSwiftViewModuleNames = [NSMutableSet new];
59
-
60
- for (ViewModuleWrapper *swiftViewModule in [nativeModulesProxy.swiftInteropBridge getViewManagers]) {
61
- Class wrappedViewModuleClass = [ViewModuleWrapper createViewModuleWrapperClassWithModule:swiftViewModule];
62
- [extraModules addObject:[[wrappedViewModuleClass alloc] init]];
63
- [exportedSwiftViewModuleNames addObject:swiftViewModule.name];
64
- }
65
58
  for (EXViewManager *viewManager in [moduleRegistry getAllViewManagers]) {
66
- if (![exportedSwiftViewModuleNames containsObject:viewManager.viewName]) {
67
- Class viewManagerAdapterClass = [EXViewManagerAdapterClassesRegistry createViewManagerAdapterClassForViewManager:viewManager];
68
- [extraModules addObject:[[viewManagerAdapterClass alloc] init]];
69
- }
59
+ Class viewManagerAdapterClass = [EXViewManagerAdapterClassesRegistry createViewManagerAdapterClassForViewManager:viewManager];
60
+ [extraModules addObject:[[viewManagerAdapterClass alloc] init]];
70
61
  }
71
62
 
72
63
  // Silence React Native warning `Base module "%s" does not exist`
@@ -75,7 +66,6 @@
75
66
  // subclass EXViewManagerAdapter, so RN expects to find EXViewManagerAdapter
76
67
  // exported.
77
68
  [extraModules addObject:[[EXViewManagerAdapter alloc] init]];
78
- [extraModules addObject:[[ViewModuleWrapper alloc] initWithDummy:nil]];
79
69
 
80
70
  // It is possible that among internal modules there are some RCTBridgeModules --
81
71
  // let's add them to extraModules here.
@@ -0,0 +1,16 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ #import <React/RCTComponentData.h>
4
+
5
+ /**
6
+ * A compatible wrapper for `RCTComponentData` which has different designated initializers between different react-native versions.
7
+ * This class unifies the interface to make react-native <= 0.64 backward compatible.
8
+ * Remove when we drop support for SDK 44
9
+ */
10
+ @interface EXComponentDataCompatibleWrapper : RCTComponentData
11
+
12
+ - (instancetype)initWithManagerClass:(Class)managerClass
13
+ bridge:(RCTBridge *)bridge
14
+ eventDispatcher:(id<RCTEventDispatcherProtocol>)eventDispatcher NS_DESIGNATED_INITIALIZER;
15
+
16
+ @end
@@ -0,0 +1,28 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoModulesCore/EXComponentDataCompatibleWrapper.h>
4
+
5
+ @interface RCTComponentData (EXComponentDataCompatibleWrapper)
6
+
7
+ // available in RN 0.65+
8
+ - (instancetype)initWithManagerClass:(Class)managerClass
9
+ bridge:(RCTBridge *)bridge
10
+ eventDispatcher:(id<RCTEventDispatcherProtocol>) eventDispatcher;
11
+
12
+ - (instancetype)initWithManagerClass:(Class)managerClass bridge:(RCTBridge *)bridge;
13
+
14
+ @end
15
+
16
+ @implementation EXComponentDataCompatibleWrapper
17
+
18
+ - (instancetype)initWithManagerClass:(Class)managerClass
19
+ bridge:(RCTBridge *)bridge
20
+ eventDispatcher:(id<RCTEventDispatcherProtocol>)eventDispatcher
21
+ {
22
+ if ([self respondsToSelector:@selector(initWithManagerClass:bridge:)]) {
23
+ return [super initWithManagerClass:managerClass bridge:bridge];
24
+ }
25
+ return [super initWithManagerClass:managerClass bridge:bridge eventDispatcher:eventDispatcher];
26
+ }
27
+
28
+ @end
@@ -10,6 +10,7 @@
10
10
 
11
11
  #import <jsi/jsi.h>
12
12
 
13
+ #import <ExpoModulesCore/EXComponentDataCompatibleWrapper.h>
13
14
  #import <ExpoModulesCore/EXNativeModulesProxy.h>
14
15
  #import <ExpoModulesCore/EXEventEmitter.h>
15
16
  #import <ExpoModulesCore/EXViewManager.h>
@@ -41,13 +42,6 @@ static const NSString *methodInfoArgumentsCountKey = @"argumentsCount";
41
42
 
42
43
  @end
43
44
 
44
- @interface RCTComponentData (EXNativeModulesProxy)
45
-
46
- - (instancetype)initWithManagerClass:(Class)managerClass bridge:(RCTBridge *)bridge eventDispatcher:(id<RCTEventDispatcherProtocol>) eventDispatcher; // available in RN 0.65+
47
- - (instancetype)initWithManagerClass:(Class)managerClass bridge:(RCTBridge *)bridge;
48
-
49
- @end
50
-
51
45
  @interface EXNativeModulesProxy ()
52
46
 
53
47
  @property (nonatomic, strong) NSRegularExpression *regexp;
@@ -150,8 +144,18 @@ RCT_EXPORT_MODULE(NativeUnimoduleProxy)
150
144
  - (void)setBridge:(RCTBridge *)bridge
151
145
  {
152
146
  if (!_bridge) {
153
- [self registerExpoModulesInBridge:bridge];
147
+ // The `setBridge` can be called during module setup or after. Registering more modules
148
+ // during setup causes a crash due to mutating `_moduleDataByID` while it's being enumerated.
149
+ // In that case we register them asynchronously.
150
+ if ([[bridge valueForKey:@"_moduleSetupComplete"] boolValue]) {
151
+ [self registerExpoModulesInBridge:bridge];
152
+ } else {
153
+ dispatch_async(dispatch_get_main_queue(), ^{
154
+ [self registerExpoModulesInBridge:bridge];
155
+ });
156
+ }
154
157
  }
158
+ [_swiftInteropBridge setReactBridge:bridge];
155
159
  _bridge = bridge;
156
160
  }
157
161
 
@@ -233,45 +237,49 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
233
237
 
234
238
  - (void)registerExpoModulesInBridge:(RCTBridge *)bridge
235
239
  {
236
- // Registering expo modules in bridge is needed only when the proxy module owns the registry
237
- // (was autoinitialized by React Native). Otherwise they're registered by the registry adapter.
238
- if (!_ownsModuleRegistry || [bridge moduleIsInitialized:[EXReactNativeEventEmitter class]]) {
239
- return;
240
- }
240
+ // Registering expo modules (excluding Swifty view managers!) in bridge is needed only when the proxy module owns
241
+ // the registry (was autoinitialized by React Native). Otherwise they're registered by the registry adapter.
242
+ BOOL ownsModuleRegistry = _ownsModuleRegistry && ![bridge moduleIsInitialized:[EXReactNativeEventEmitter class]];
241
243
 
242
244
  // An array of `RCTBridgeModule` classes to register.
243
245
  NSMutableArray<Class<RCTBridgeModule>> *additionalModuleClasses = [NSMutableArray new];
244
246
  NSMutableSet *visitedSweetModules = [NSMutableSet new];
245
247
 
246
- // Event emitter is a bridge module, however it's also needed by expo modules,
247
- // so later we'll register an instance created by React Native as expo module.
248
- [additionalModuleClasses addObject:[EXReactNativeEventEmitter class]];
249
-
250
248
  // Add dynamic wrappers for view modules written in Sweet API.
251
249
  for (ViewModuleWrapper *swiftViewModule in [_swiftInteropBridge getViewManagers]) {
252
- Class wrappedViewModuleClass = [ViewModuleWrapper createViewModuleWrapperClassWithModule:swiftViewModule];
250
+ Class wrappedViewModuleClass = [self registerComponentData:swiftViewModule inBridge:bridge];
253
251
  [additionalModuleClasses addObject:wrappedViewModuleClass];
254
252
  [visitedSweetModules addObject:swiftViewModule.name];
255
253
  }
256
254
 
257
- // Add dynamic wrappers for the classic view managers.
258
- for (EXViewManager *viewManager in [_exModuleRegistry getAllViewManagers]) {
259
- if (![visitedSweetModules containsObject:viewManager.viewName]) {
260
- Class viewManagerWrapperClass = [EXViewManagerAdapterClassesRegistry createViewManagerAdapterClassForViewManager:viewManager];
261
- [additionalModuleClasses addObject:viewManagerWrapperClass];
255
+ [additionalModuleClasses addObject:[ViewModuleWrapper class]];
256
+ [self registerLegacyComponentData:[ViewModuleWrapper class] inBridge:bridge];
257
+
258
+ // Add modules from legacy module registry only when the NativeModulesProxy owns the registry.
259
+ if (ownsModuleRegistry) {
260
+ // Event emitter is a bridge module, however it's also needed by expo modules,
261
+ // so later we'll register an instance created by React Native as expo module.
262
+ [additionalModuleClasses addObject:[EXReactNativeEventEmitter class]];
263
+
264
+ // Add dynamic wrappers for the classic view managers.
265
+ for (EXViewManager *viewManager in [_exModuleRegistry getAllViewManagers]) {
266
+ if (![visitedSweetModules containsObject:viewManager.viewName]) {
267
+ Class viewManagerWrapperClass = [EXViewManagerAdapterClassesRegistry createViewManagerAdapterClassForViewManager:viewManager];
268
+ [additionalModuleClasses addObject:viewManagerWrapperClass];
269
+ [self registerLegacyComponentData:viewManagerWrapperClass inBridge:bridge];
270
+ }
262
271
  }
263
- }
264
272
 
265
- // View manager wrappers don't have their own prop configs, so we must register
266
- // their base view managers that provides common props such as `proxiedProperties`.
267
- // Otherwise, React Native may treat these props as invalid in subclassing views.
268
- [additionalModuleClasses addObject:[EXViewManagerAdapter class]];
269
- [additionalModuleClasses addObject:[ViewModuleWrapper class]];
273
+ // View manager wrappers don't have their own prop configs, so we must register
274
+ // their base view managers that provides common props such as `proxiedProperties`.
275
+ // Otherwise, React Native may treat these props as invalid in subclassing views.
276
+ [additionalModuleClasses addObject:[EXViewManagerAdapter class]];
270
277
 
271
- // Some modules might need access to the bridge.
272
- for (id module in [_exModuleRegistry getAllInternalModules]) {
273
- if ([module conformsToProtocol:@protocol(RCTBridgeModule)]) {
274
- [module setValue:bridge forKey:@"bridge"];
278
+ // Some modules might need access to the bridge.
279
+ for (id module in [_exModuleRegistry getAllInternalModules]) {
280
+ if ([module conformsToProtocol:@protocol(RCTBridgeModule)]) {
281
+ [module setValue:bridge forKey:@"bridge"];
282
+ }
275
283
  }
276
284
  }
277
285
 
@@ -283,19 +291,19 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
283
291
  // Register the view managers as additional modules.
284
292
  [self registerAdditionalModuleClasses:additionalModuleClasses inBridge:bridge];
285
293
 
286
- // Bridge's `registerAdditionalModuleClasses:` method doesn't register
287
- // components in UIManager we need to register them on our own.
288
- [self registerComponentDataForModuleClasses:additionalModuleClasses inBridge:bridge];
289
-
290
- // Get the newly created instance of `EXReactEventEmitter` bridge module,
291
- // pass event names supported by Swift modules and register it in legacy modules registry.
292
- EXReactNativeEventEmitter *eventEmitter = [bridge moduleForClass:[EXReactNativeEventEmitter class]];
293
- [eventEmitter setSwiftInteropBridge:_swiftInteropBridge];
294
- [_exModuleRegistry registerInternalModule:eventEmitter];
295
-
296
- // Let the modules consume the registry :)
297
- // It calls `setModuleRegistry:` on all `EXModuleRegistryConsumer`s.
298
- [_exModuleRegistry initialize];
294
+ // As the last step, when the registry is owned,
295
+ // register the event emitter and initialize the registry.
296
+ if (ownsModuleRegistry) {
297
+ // Get the newly created instance of `EXReactEventEmitter` bridge module,
298
+ // pass event names supported by Swift modules and register it in legacy modules registry.
299
+ EXReactNativeEventEmitter *eventEmitter = [bridge moduleForClass:[EXReactNativeEventEmitter class]];
300
+ [eventEmitter setSwiftInteropBridge:_swiftInteropBridge];
301
+ [_exModuleRegistry registerInternalModule:eventEmitter];
302
+
303
+ // Let the modules consume the registry :)
304
+ // It calls `setModuleRegistry:` on all `EXModuleRegistryConsumer`s.
305
+ [_exModuleRegistry initialize];
306
+ }
299
307
  }
300
308
 
301
309
  - (void)registerAdditionalModuleClasses:(NSArray<Class> *)moduleClasses inBridge:(RCTBridge *)bridge
@@ -324,27 +332,38 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
324
332
  [bridge registerAdditionalModuleClasses:moduleClasses];
325
333
  }
326
334
 
327
- - (void)registerComponentDataForModuleClasses:(NSArray<Class> *)moduleClasses inBridge:(RCTBridge *)bridge
335
+ - (Class)registerComponentData:(ViewModuleWrapper *)viewModule inBridge:(RCTBridge *)bridge
328
336
  {
329
337
  // Hacky way to get a dictionary with `RCTComponentData` from UIManager.
330
338
  NSMutableDictionary<NSString *, RCTComponentData *> *componentDataByName = [bridge.uiManager valueForKey:@"_componentDataByName"];
339
+ Class wrappedViewModuleClass = [ViewModuleWrapper createViewModuleWrapperClassWithModule:viewModule];
340
+ NSString *className = NSStringFromClass(wrappedViewModuleClass);
331
341
 
332
- // Register missing components data for all view managers.
333
- for (Class moduleClass in moduleClasses) {
334
- NSString *className = NSStringFromClass(moduleClass);
335
-
336
- if ([moduleClass isSubclassOfClass:[RCTViewManager class]] && !componentDataByName[className]) {
337
- RCTComponentData *componentData = [RCTComponentData alloc];
338
- if ([componentData respondsToSelector:@selector(initWithManagerClass:bridge:eventDispatcher:)]) {
339
- // Init method was changed in RN 0.65
340
- [componentData initWithManagerClass:moduleClass bridge:bridge eventDispatcher:bridge.eventDispatcher];
341
- } else {
342
- // fallback for older RNs
343
- [componentData initWithManagerClass:moduleClass bridge:bridge];
344
- }
345
-
346
- componentDataByName[className] = componentData;
347
- }
342
+ if (componentDataByName[className]) {
343
+ // Just in case the component was already registered, let's leave a log that we're overriding it.
344
+ NSLog(@"Overriding ComponentData for view %@", className);
345
+ }
346
+
347
+ EXComponentData *componentData = [[EXComponentData alloc] initWithViewModule:viewModule
348
+ managerClass:wrappedViewModuleClass
349
+ bridge:bridge];
350
+ componentDataByName[className] = componentData;
351
+ return wrappedViewModuleClass;
352
+ }
353
+
354
+ /**
355
+ Bridge's `registerAdditionalModuleClasses:` method doesn't register
356
+ components in UIManager — we need to register them on our own.
357
+ */
358
+ - (void)registerLegacyComponentData:(Class)moduleClass inBridge:(RCTBridge *)bridge
359
+ {
360
+ // Hacky way to get a dictionary with `RCTComponentData` from UIManager.
361
+ NSMutableDictionary<NSString *, RCTComponentData *> *componentDataByName = [bridge.uiManager valueForKey:@"_componentDataByName"];
362
+ NSString *className = NSStringFromClass(moduleClass);
363
+
364
+ if ([moduleClass isSubclassOfClass:[RCTViewManager class]] && !componentDataByName[className]) {
365
+ RCTComponentData *componentData = [[EXComponentDataCompatibleWrapper alloc] initWithManagerClass:moduleClass bridge:bridge eventDispatcher:bridge.eventDispatcher];
366
+ componentDataByName[className] = componentData;
348
367
  }
349
368
  }
350
369
 
@@ -384,10 +403,15 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
384
403
  */
385
404
  - (void)installExpoTurboModules
386
405
  {
387
- facebook::jsi::Runtime *runtime = [_bridge respondsToSelector:@selector(runtime)] ? reinterpret_cast<facebook::jsi::Runtime *>(_bridge.runtime) : NULL;
406
+ facebook::jsi::Runtime *jsiRuntime = [_bridge respondsToSelector:@selector(runtime)] ? reinterpret_cast<facebook::jsi::Runtime *>(_bridge.runtime) : nullptr;
407
+
408
+ if (jsiRuntime) {
409
+ JavaScriptRuntime *runtime = [[JavaScriptRuntime alloc] initWithRuntime:*jsiRuntime callInvoker:_bridge.jsCallInvoker];
410
+
411
+ [JavaScriptRuntimeManager installExpoModulesToRuntime:runtime withSwiftInterop:_swiftInteropBridge];
412
+ [_swiftInteropBridge setRuntime:runtime];
388
413
 
389
- if (runtime) {
390
- expo::installRuntimeObjects(*runtime, _bridge.jsCallInvoker, self);
414
+ expo::installRuntimeObjects(*jsiRuntime, _bridge.jsCallInvoker, self);
391
415
  }
392
416
  }
393
417
 
@@ -0,0 +1,12 @@
1
+ // Copyright 2021-present 650 Industries. All rights reserved.
2
+
3
+ #import <React/RCTComponent.h>
4
+ #import <React/RCTComponentData.h>
5
+
6
+ typedef void (^RCTPropBlockAlias)(id<RCTComponent> _Nonnull view, id _Nullable json);
7
+
8
+ @interface RCTComponentData (Privates)
9
+
10
+ - (nonnull RCTPropBlockAlias)createPropBlock:(nonnull NSString *)name isShadowView:(BOOL)isShadowView;
11
+
12
+ @end
@@ -12,7 +12,7 @@ public class ExpoReactDelegate: NSObject {
12
12
  }
13
13
 
14
14
  @objc
15
- public func createBridge(delegate: RCTBridgeDelegate, launchOptions: [AnyHashable : Any]?) -> RCTBridge {
15
+ public func createBridge(delegate: RCTBridgeDelegate, launchOptions: [AnyHashable: Any]?) -> RCTBridge {
16
16
  self.handlers.forEach { $0.bridgeWillCreate() }
17
17
  let result = self.handlers.lazy
18
18
  .compactMap { $0.createBridge(reactDelegate: self, bridgeDelegate: delegate, launchOptions: launchOptions) }
@@ -22,7 +22,7 @@ public class ExpoReactDelegate: NSObject {
22
22
  }
23
23
 
24
24
  @objc
25
- public func createRootView(bridge: RCTBridge, moduleName: String, initialProperties: [AnyHashable : Any]?) -> RCTRootView {
25
+ public func createRootView(bridge: RCTBridge, moduleName: String, initialProperties: [AnyHashable: Any]?) -> RCTRootView {
26
26
  return self.handlers.lazy
27
27
  .compactMap { $0.createRootView(reactDelegate: self, bridge: bridge, moduleName: moduleName, initialProperties: initialProperties) }
28
28
  .first(where: { _ in true }) ?? RCTRootView(bridge: bridge, moduleName: moduleName, initialProperties: initialProperties)
@@ -14,7 +14,7 @@ open class ExpoReactDelegateHandler: NSObject {
14
14
  Otherwise return nil.
15
15
  */
16
16
  @objc
17
- open func createBridge(reactDelegate: ExpoReactDelegate, bridgeDelegate: RCTBridgeDelegate, launchOptions: [AnyHashable : Any]?) -> RCTBridge? {
17
+ open func createBridge(reactDelegate: ExpoReactDelegate, bridgeDelegate: RCTBridgeDelegate, launchOptions: [AnyHashable: Any]?) -> RCTBridge? {
18
18
  return nil
19
19
  }
20
20
 
@@ -23,7 +23,7 @@ open class ExpoReactDelegateHandler: NSObject {
23
23
  Otherwise return nil.
24
24
  */
25
25
  @objc
26
- open func createRootView(reactDelegate: ExpoReactDelegate, bridge: RCTBridge, moduleName: String, initialProperties: [AnyHashable : Any]?) -> RCTRootView? {
26
+ open func createRootView(reactDelegate: ExpoReactDelegate, bridge: RCTBridge, moduleName: String, initialProperties: [AnyHashable: Any]?) -> RCTRootView? {
27
27
  return nil
28
28
  }
29
29
 
@@ -36,7 +36,7 @@ open class ExpoReactDelegateHandler: NSObject {
36
36
  return nil
37
37
  }
38
38
 
39
- // MARK - event callbacks
39
+ // MARK: - event callbacks
40
40
 
41
41
  /**
42
42
  Callback before bridge creation
@@ -11,7 +11,7 @@ internal struct ModulePriorities {
11
11
  // key: node package name
12
12
  // value: priority value, the higher value takes precedence
13
13
  "expo-screen-orientation": 10,
14
- "expo-updates": 5,
14
+ "expo-updates": 5
15
15
  ]
16
16
 
17
17
  static func get(_ packageName: String) -> Int {
@@ -13,6 +13,25 @@ public final class AppContext {
13
13
  */
14
14
  public private(set) var legacyModuleRegistry: EXModuleRegistry?
15
15
 
16
+ /**
17
+ React bridge of the context's app.
18
+ */
19
+ public internal(set) weak var reactBridge: RCTBridge?
20
+
21
+ /**
22
+ JSI runtime of the running app.
23
+ */
24
+ public internal(set) var runtime: JavaScriptRuntime? {
25
+ didSet {
26
+ // When the runtime is unpinned from the context (e.g. deallocated),
27
+ // we should make sure to release all JS objects from the memory.
28
+ // Otherwise the JSCRuntime asserts may fail on deallocation.
29
+ if runtime == nil {
30
+ releaseRuntimeObjects()
31
+ }
32
+ }
33
+ }
34
+
16
35
  /**
17
36
  Designated initializer without modules provider.
18
37
  */
@@ -85,7 +104,7 @@ public final class AppContext {
85
104
  [
86
105
  UIApplication.willEnterForegroundNotification,
87
106
  UIApplication.didBecomeActiveNotification,
88
- UIApplication.didEnterBackgroundNotification,
107
+ UIApplication.didEnterBackgroundNotification
89
108
  ].forEach { name in
90
109
  NotificationCenter.default.addObserver(self, selector: #selector(handleClientAppNotification(_:)), name: name, object: nil)
91
110
  }
@@ -108,6 +127,19 @@ public final class AppContext {
108
127
  }
109
128
  }
110
129
 
130
+ // MARK: - Runtime
131
+
132
+ /**
133
+ Unsets runtime objects that we hold for each module.
134
+ */
135
+ private func releaseRuntimeObjects() {
136
+ for module in moduleRegistry {
137
+ module.javaScriptObject = nil
138
+ }
139
+ }
140
+
141
+ // MARK: - Deallocation
142
+
111
143
  /**
112
144
  Cleans things up before deallocation.
113
145
  */
@@ -116,9 +148,11 @@ public final class AppContext {
116
148
  moduleRegistry.post(event: .appContextDestroys)
117
149
  }
118
150
 
119
- // MARK: Errors
151
+ // MARK: - Exceptions
120
152
 
121
- struct DeallocatedAppContextError: CodedError {
122
- var description: String = "The app context has been deallocated."
153
+ class DeallocatedAppContextException: Exception {
154
+ override var reason: String {
155
+ "The app context has been deallocated"
156
+ }
123
157
  }
124
158
  }
@@ -1,5 +1,9 @@
1
1
  // Copyright 2021-present 650 Industries. All rights reserved.
2
2
 
3
+ // Function names should start with a lowercase character, but in this one case
4
+ // we want it to be uppercase as we treat it more like a generic class.
5
+ // swiftlint:disable identifier_name
6
+
3
7
  /**
4
8
  Factory creating an instance of the argument type wrapper conforming to `AnyArgumentType`.
5
9
  Depending on the given type, it may return one of `ArrayArgumentType`, `OptionalArgumentType`, `ConvertibleArgumentType`, etc.