expo-modules-core 0.6.1 → 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 (161) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +1 -1
  3. package/android/build.gradle +5 -5
  4. package/android/src/main/java/expo/modules/adapters/react/apploader/RNHeadlessAppLoader.kt +7 -1
  5. package/android/src/main/java/expo/modules/core/interfaces/ReactActivityLifecycleListener.java +23 -0
  6. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +11 -1
  7. package/android/src/main/java/expo/modules/kotlin/DynamicExtenstions.kt +5 -3
  8. package/android/src/main/java/expo/modules/kotlin/KPromiseWrapper.kt +8 -2
  9. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +13 -4
  10. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +7 -6
  11. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +6 -1
  12. package/android/src/main/java/expo/modules/kotlin/Promise.kt +1 -1
  13. package/android/src/main/java/expo/modules/kotlin/callbacks/Callback.kt +5 -0
  14. package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallback.kt +28 -0
  15. package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallbackDelegate.kt +27 -0
  16. package/android/src/main/java/expo/modules/kotlin/defaultmodules/ErrorManagerModule.kt +25 -0
  17. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +68 -8
  18. package/android/src/main/java/expo/modules/kotlin/exception/ExceptionDecorator.kt +11 -0
  19. package/android/src/main/java/expo/modules/kotlin/methods/AnyMethod.kt +13 -14
  20. package/android/src/main/java/expo/modules/kotlin/modules/DefinitionMarker.kt +4 -0
  21. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +3 -2
  22. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +44 -4
  23. package/android/src/main/java/expo/modules/kotlin/records/Record.kt +39 -0
  24. package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +14 -7
  25. package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +11 -5
  26. package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +10 -4
  27. package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +12 -6
  28. package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +29 -13
  29. package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +2 -1
  30. package/android/src/main/java/expo/modules/kotlin/views/CallbacksDefinition.kt +3 -0
  31. package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +22 -0
  32. package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +22 -0
  33. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +27 -2
  34. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +29 -1
  35. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +59 -2
  36. package/build/EventEmitter.d.ts +1 -0
  37. package/build/EventEmitter.d.ts.map +1 -0
  38. package/build/NativeModulesProxy.d.ts +1 -0
  39. package/build/NativeModulesProxy.d.ts.map +1 -0
  40. package/build/NativeModulesProxy.native.d.ts +1 -0
  41. package/build/NativeModulesProxy.native.d.ts.map +1 -0
  42. package/build/NativeModulesProxy.types.d.ts +1 -0
  43. package/build/NativeModulesProxy.types.d.ts.map +1 -0
  44. package/build/NativeViewManagerAdapter.d.ts +1 -0
  45. package/build/NativeViewManagerAdapter.d.ts.map +1 -0
  46. package/build/NativeViewManagerAdapter.native.d.ts +1 -0
  47. package/build/NativeViewManagerAdapter.native.d.ts.map +1 -0
  48. package/build/PermissionsHook.d.ts +1 -0
  49. package/build/PermissionsHook.d.ts.map +1 -0
  50. package/build/PermissionsInterface.d.ts +1 -0
  51. package/build/PermissionsInterface.d.ts.map +1 -0
  52. package/build/Platform.d.ts +1 -0
  53. package/build/Platform.d.ts.map +1 -0
  54. package/build/SyntheticPlatformEmitter.d.ts +1 -0
  55. package/build/SyntheticPlatformEmitter.d.ts.map +1 -0
  56. package/build/SyntheticPlatformEmitter.web.d.ts +1 -0
  57. package/build/SyntheticPlatformEmitter.web.d.ts.map +1 -0
  58. package/build/deprecate.d.ts +1 -0
  59. package/build/deprecate.d.ts.map +1 -0
  60. package/build/environment/browser.d.ts +1 -0
  61. package/build/environment/browser.d.ts.map +1 -0
  62. package/build/environment/browser.web.d.ts +1 -0
  63. package/build/environment/browser.web.d.ts.map +1 -0
  64. package/build/errors/CodedError.d.ts +1 -0
  65. package/build/errors/CodedError.d.ts.map +1 -0
  66. package/build/errors/UnavailabilityError.d.ts +1 -0
  67. package/build/errors/UnavailabilityError.d.ts.map +1 -0
  68. package/build/index.d.ts +3 -0
  69. package/build/index.d.ts.map +1 -0
  70. package/build/index.js +2 -0
  71. package/build/index.js.map +1 -1
  72. package/build/requireNativeModule.d.ts +16 -0
  73. package/build/requireNativeModule.d.ts.map +1 -0
  74. package/build/requireNativeModule.js +18 -0
  75. package/build/requireNativeModule.js.map +1 -0
  76. package/build/sweet/NativeErrorManager.d.ts +3 -0
  77. package/build/sweet/NativeErrorManager.d.ts.map +1 -0
  78. package/build/sweet/NativeErrorManager.js +3 -0
  79. package/build/sweet/NativeErrorManager.js.map +1 -0
  80. package/build/sweet/setUpErrorManager.fx.d.ts +2 -0
  81. package/build/sweet/setUpErrorManager.fx.d.ts.map +1 -0
  82. package/build/sweet/setUpErrorManager.fx.js +11 -0
  83. package/build/sweet/setUpErrorManager.fx.js.map +1 -0
  84. package/ios/AppDelegates/ExpoAppDelegate.swift +27 -8
  85. package/ios/JSI/ExpoModulesHostObject.h +33 -0
  86. package/ios/JSI/ExpoModulesHostObject.mm +40 -0
  87. package/ios/JSI/ExpoModulesProxySpec.h +4 -0
  88. package/ios/JSI/ExpoModulesProxySpec.mm +1 -3
  89. package/ios/JSI/JSIConversions.h +2 -0
  90. package/ios/JSI/JSIConversions.mm +9 -0
  91. package/ios/JSI/JSIInstaller.h +10 -0
  92. package/ios/JSI/JSIInstaller.mm +14 -2
  93. package/ios/JSI/JavaScriptObject.h +60 -0
  94. package/ios/JSI/JavaScriptObject.mm +93 -0
  95. package/ios/JSI/JavaScriptRuntime.h +54 -0
  96. package/ios/JSI/JavaScriptRuntime.mm +102 -0
  97. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +2 -12
  98. package/ios/NativeModulesProxy/EXComponentDataCompatibleWrapper.h +16 -0
  99. package/ios/NativeModulesProxy/EXComponentDataCompatibleWrapper.m +28 -0
  100. package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +90 -66
  101. package/ios/RCTComponentData+Privates.h +12 -0
  102. package/ios/ReactDelegates/ExpoReactDelegate.swift +2 -2
  103. package/ios/ReactDelegates/ExpoReactDelegateHandler.swift +3 -3
  104. package/ios/ReactDelegates/ModulePriorities.swift +1 -1
  105. package/ios/Swift/AppContext.swift +38 -4
  106. package/ios/Swift/Arguments/ArgumentType.swift +4 -0
  107. package/ios/Swift/Arguments/Convertibles.swift +13 -13
  108. package/ios/Swift/Arguments/Types/EnumArgumentType.swift +11 -17
  109. package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +1 -1
  110. package/ios/Swift/Arguments/Types/RawArgumentType.swift +2 -2
  111. package/ios/Swift/Conversions.swift +51 -56
  112. package/ios/Swift/EventListener.swift +8 -10
  113. package/ios/Swift/Events/Callback.swift +66 -0
  114. package/ios/Swift/Events/Event.swift +43 -0
  115. package/ios/Swift/Exceptions/ChainableException.swift +51 -0
  116. package/ios/Swift/{CodedError.swift → Exceptions/CodedError.swift} +1 -12
  117. package/ios/Swift/Exceptions/Exception.swift +62 -0
  118. package/ios/Swift/Exceptions/ExceptionOrigin.swift +28 -0
  119. package/ios/Swift/Exceptions/GenericException.swift +20 -0
  120. package/ios/Swift/Exceptions/UnexpectedException.swift +16 -0
  121. package/ios/Swift/Functions/AnyFunction.swift +11 -1
  122. package/ios/Swift/Functions/ConcreteFunction.swift +37 -16
  123. package/ios/Swift/JavaScriptUtils.swift +43 -0
  124. package/ios/Swift/ModuleHolder.swift +53 -14
  125. package/ios/Swift/ModuleRegistry.swift +4 -1
  126. package/ios/Swift/Modules/AnyModule.swift +0 -1
  127. package/ios/Swift/Modules/ModuleDefinition.swift +4 -13
  128. package/ios/Swift/Modules/ModuleDefinitionBuilder.swift +0 -1
  129. package/ios/Swift/Modules/ModuleDefinitionComponents.swift +0 -188
  130. package/ios/Swift/ModulesProvider.swift +0 -1
  131. package/ios/Swift/Objects/ObjectDefinition.swift +30 -0
  132. package/ios/Swift/Objects/ObjectDefinitionComponents.swift +208 -0
  133. package/ios/Swift/Promise.swift +8 -3
  134. package/ios/Swift/Records/AnyField.swift +7 -0
  135. package/ios/Swift/Records/Field.swift +24 -19
  136. package/ios/Swift/Records/FieldOption.swift +1 -1
  137. package/ios/Swift/Records/Record.swift +12 -4
  138. package/ios/Swift/SwiftInteropBridge.swift +39 -10
  139. package/ios/Swift/Views/AnyViewProp.swift +1 -1
  140. package/ios/Swift/Views/ComponentData.swift +95 -0
  141. package/ios/Swift/Views/ConcreteViewProp.swift +6 -8
  142. package/ios/Swift/Views/ViewFactory.swift +1 -1
  143. package/ios/Swift/Views/ViewManagerDefinition.swift +23 -2
  144. package/ios/Swift/Views/ViewManagerDefinitionBuilder.swift +0 -1
  145. package/ios/Swift/Views/ViewManagerDefinitionComponents.swift +26 -0
  146. package/ios/Swift/Views/ViewModuleWrapper.swift +5 -2
  147. package/ios/Tests/ArgumentTypeSpec.swift +3 -4
  148. package/ios/Tests/ConstantsSpec.swift +4 -4
  149. package/ios/Tests/ConvertiblesSpec.swift +33 -33
  150. package/ios/Tests/ExceptionsSpec.swift +112 -0
  151. package/ios/Tests/FunctionSpec.swift +20 -22
  152. package/ios/Tests/FunctionWithConvertiblesSpec.swift +2 -2
  153. package/ios/Tests/Mocks/ModuleMocks.swift +1 -1
  154. package/ios/Tests/Mocks/ModulesProviderMock.swift +0 -1
  155. package/ios/Tests/ModuleEventListenersSpec.swift +1 -1
  156. package/ios/Tests/RecordSpec.swift +7 -17
  157. package/package.json +3 -3
  158. package/src/index.ts +4 -0
  159. package/src/requireNativeModule.ts +29 -0
  160. package/src/sweet/NativeErrorManager.ts +2 -0
  161. package/src/sweet/setUpErrorManager.fx.ts +12 -0
@@ -0,0 +1,93 @@
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoModulesCore/JSIConversions.h>
4
+ #import <ExpoModulesCore/JavaScriptObject.h>
5
+ #import <ExpoModulesCore/JavaScriptRuntime.h>
6
+ #import <ExpoModulesCore/ExpoModulesProxySpec.h>
7
+
8
+ @implementation JavaScriptObject {
9
+ /**
10
+ Pointer to the `JavaScriptRuntime` wrapper.
11
+
12
+ \note It must be weak because only then the original runtime can be safely deallocated
13
+ when the JS engine wants to without unsetting it on each created object.
14
+ */
15
+ __weak JavaScriptRuntime *_runtime;
16
+
17
+ /**
18
+ Shared pointer to the original JSI object that is being wrapped by `JavaScriptObject` class.
19
+ */
20
+ std::shared_ptr<jsi::Object> _jsObjectPtr;
21
+ }
22
+
23
+ - (nonnull instancetype)initWith:(std::shared_ptr<jsi::Object>)jsObjectPtr
24
+ runtime:(nonnull JavaScriptRuntime *)runtime
25
+ {
26
+ if (self = [super init]) {
27
+ _runtime = runtime;
28
+ _jsObjectPtr = jsObjectPtr;
29
+ }
30
+ return self;
31
+ }
32
+
33
+ - (nonnull jsi::Object *)get
34
+ {
35
+ return _jsObjectPtr.get();
36
+ }
37
+
38
+ #pragma mark - Subscripting
39
+
40
+ - (nullable id)objectForKeyedSubscript:(nonnull NSString *)key
41
+ {
42
+ auto runtime = [_runtime get];
43
+ auto callInvoker = [_runtime callInvoker];
44
+
45
+ if (runtime && callInvoker) {
46
+ auto value = _jsObjectPtr->getProperty(*runtime, [key UTF8String]);
47
+ return expo::convertJSIValueToObjCObject(*runtime, value, callInvoker);
48
+ }
49
+ return nil;
50
+ }
51
+
52
+ - (void)setObject:(nullable id)obj forKeyedSubscript:(nonnull NSString *)key
53
+ {
54
+ auto runtime = [_runtime get];
55
+
56
+ if (!runtime) {
57
+ NSLog(@"Cannot set '%@' property when the JavaScript runtime is no longer available.", key);
58
+ return;
59
+ }
60
+ if ([obj isKindOfClass:[JavaScriptObject class]]) {
61
+ _jsObjectPtr->setProperty(*runtime, [key UTF8String], *[obj get]);
62
+ } else {
63
+ _jsObjectPtr->setProperty(*runtime, [key UTF8String], expo::convertObjCObjectToJSIValue(*runtime, obj));
64
+ }
65
+ }
66
+
67
+ #pragma mark - Functions
68
+
69
+ - (void)setAsyncFunction:(nonnull NSString *)name
70
+ argsCount:(NSInteger)argsCount
71
+ block:(nonnull JSAsyncFunctionBlock)block
72
+ {
73
+ if (!_runtime) {
74
+ NSLog(@"Cannot set '%@' async function when the JavaScript runtime is no longer available.", name);
75
+ return;
76
+ }
77
+ jsi::Function function = [_runtime createAsyncFunction:name argsCount:argsCount block:block];
78
+ _jsObjectPtr->setProperty(*[_runtime get], [name UTF8String], function);
79
+ }
80
+
81
+ - (void)setSyncFunction:(nonnull NSString *)name
82
+ argsCount:(NSInteger)argsCount
83
+ block:(nonnull JSSyncFunctionBlock)block
84
+ {
85
+ if (!_runtime) {
86
+ NSLog(@"Cannot set '%@' sync function when the JavaScript runtime is no longer available.", name);
87
+ return;
88
+ }
89
+ jsi::Function function = [_runtime createSyncFunction:name argsCount:argsCount block:block];
90
+ _jsObjectPtr->setProperty(*[_runtime get], [name UTF8String], function);
91
+ }
92
+
93
+ @end
@@ -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 {