expo-modules-core 0.7.0 → 0.8.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 (124) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +1 -1
  3. package/android/ExpoModulesCorePlugin.gradle +15 -0
  4. package/android/build.gradle +46 -32
  5. package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +5 -5
  6. package/android/src/main/java/expo/modules/adapters/react/services/UIManagerModuleWrapper.java +13 -0
  7. package/android/src/main/java/expo/modules/core/ViewManager.java +9 -0
  8. package/android/src/main/java/expo/modules/core/interfaces/JavaScriptContextProvider.java +4 -0
  9. package/android/src/main/java/expo/modules/core/interfaces/ReactActivityHandler.java +37 -1
  10. package/android/src/main/java/expo/modules/core/interfaces/ReactNativeHostHandler.java +19 -0
  11. package/android/src/main/java/expo/modules/core/interfaces/services/UIManager.java +2 -0
  12. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +13 -5
  13. package/android/src/main/java/expo/modules/kotlin/KPromiseWrapper.kt +2 -13
  14. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +11 -5
  15. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +5 -1
  16. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +17 -0
  17. package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallback.kt +14 -3
  18. package/android/src/main/java/expo/modules/kotlin/events/EventEmitter.kt +13 -0
  19. package/android/src/main/java/expo/modules/kotlin/events/KModuleEventEmitterWrapper.kt +102 -0
  20. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +25 -1
  21. package/android/src/main/java/expo/modules/kotlin/{methods/AnyMethod.kt → functions/AnyFunction.kt} +6 -5
  22. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +15 -0
  23. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +61 -0
  24. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromise.kt +15 -0
  25. package/android/src/main/java/expo/modules/kotlin/functions/AsyncSuspendFunction.kt +36 -0
  26. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +14 -0
  27. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +176 -27
  28. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +2 -2
  29. package/android/src/main/java/expo/modules/kotlin/records/FieldValidator.kt +139 -0
  30. package/android/src/main/java/expo/modules/kotlin/records/Record.kt +0 -39
  31. package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +59 -10
  32. package/android/src/main/java/expo/modules/kotlin/records/Required.kt +5 -0
  33. package/android/src/main/java/expo/modules/kotlin/records/ValidationBinder.kt +110 -0
  34. package/android/src/main/java/expo/modules/kotlin/records/Validators.kt +61 -0
  35. package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverter.kt +35 -0
  36. package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverterHelper.kt +148 -0
  37. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +9 -1
  38. package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +49 -0
  39. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinition.kt +18 -0
  40. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +64 -0
  41. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +4 -1
  42. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +15 -2
  43. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +3 -0
  44. package/build/NativeModulesProxy.native.d.ts +0 -4
  45. package/build/NativeModulesProxy.native.d.ts.map +1 -1
  46. package/build/NativeModulesProxy.native.js +1 -14
  47. package/build/NativeModulesProxy.native.js.map +1 -1
  48. package/build/NativeModulesProxy.types.d.ts +0 -3
  49. package/build/NativeModulesProxy.types.d.ts.map +1 -1
  50. package/build/NativeModulesProxy.types.js.map +1 -1
  51. package/build/NativeViewManagerAdapter.native.d.ts.map +1 -1
  52. package/build/NativeViewManagerAdapter.native.js +9 -33
  53. package/build/NativeViewManagerAdapter.native.js.map +1 -1
  54. package/build/sweet/NativeErrorManager.js +1 -1
  55. package/build/sweet/NativeErrorManager.js.map +1 -1
  56. package/ios/AppDelegates/EXAppDelegatesLoader.m +4 -8
  57. package/ios/AppDelegates/ExpoAppDelegate.swift +4 -10
  58. package/ios/EXAppDefines.h +1 -0
  59. package/ios/EXAppDefines.m +6 -0
  60. package/ios/EXUtilities.h +2 -0
  61. package/ios/EXUtilities.m +12 -0
  62. package/ios/ExpoModulesCore.h +4 -0
  63. package/ios/ExpoModulesCore.podspec +4 -2
  64. package/ios/Interfaces/FileSystem/EXFileSystemInterface.h +1 -1
  65. package/ios/Interfaces/TaskManager/EXTaskServiceInterface.h +1 -0
  66. package/ios/JSI/{JSIConversions.h → EXJSIConversions.h} +4 -1
  67. package/ios/JSI/{JSIConversions.mm → EXJSIConversions.mm} +16 -5
  68. package/ios/JSI/{JSIInstaller.h → EXJSIInstaller.h} +3 -3
  69. package/ios/JSI/EXJSIInstaller.mm +17 -0
  70. package/ios/JSI/{ExpoModulesProxySpec.h → EXJSIUtils.h} +0 -9
  71. package/ios/JSI/{ExpoModulesProxySpec.mm → EXJSIUtils.mm} +4 -48
  72. package/ios/JSI/EXJavaScriptObject.h +97 -0
  73. package/ios/JSI/EXJavaScriptObject.mm +121 -0
  74. package/ios/JSI/{JavaScriptRuntime.h → EXJavaScriptRuntime.h} +27 -8
  75. package/ios/JSI/EXJavaScriptRuntime.mm +153 -0
  76. package/ios/JSI/EXJavaScriptValue.h +57 -0
  77. package/ios/JSI/EXJavaScriptValue.mm +166 -0
  78. package/ios/JSI/ExpoModulesHostObject.mm +2 -1
  79. package/ios/JSI/JavaScriptRuntime.swift +32 -0
  80. package/ios/JSI/JavaScriptValue.swift +94 -0
  81. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +1 -11
  82. package/ios/NativeModulesProxy/EXNativeModulesProxy.h +2 -2
  83. package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +24 -22
  84. package/ios/ReactDelegates/EXReactCompatibleHelpers.h +18 -0
  85. package/ios/ReactDelegates/EXReactCompatibleHelpers.m +19 -0
  86. package/ios/ReactDelegates/ExpoReactDelegate.swift +2 -2
  87. package/ios/ReactDelegates/ExpoReactDelegateHandler.swift +1 -1
  88. package/ios/Swift/AppContext.swift +27 -1
  89. package/ios/Swift/Functions/AsyncFunction.swift +17 -0
  90. package/ios/Swift/Functions/ConcreteFunction.swift +6 -1
  91. package/ios/Swift/JavaScriptUtils.swift +11 -0
  92. package/ios/Swift/ModuleHolder.swift +14 -3
  93. package/ios/Swift/ModulesProvider.swift +3 -10
  94. package/ios/Swift/Objects/ObjectDefinitionComponents.swift +176 -0
  95. package/ios/Swift/SwiftInteropBridge.swift +14 -5
  96. package/ios/Swift/Views/ComponentData.swift +2 -1
  97. package/ios/Swift/Views/ExpoView.swift +8 -0
  98. package/ios/Swift.h +5 -0
  99. package/ios/Tests/ArgumentTypeSpec.swift +2 -3
  100. package/ios/Tests/ConstantsSpec.swift +2 -3
  101. package/ios/Tests/ConvertiblesSpec.swift +2 -3
  102. package/ios/Tests/ExceptionsSpec.swift +2 -3
  103. package/ios/Tests/ExpoModulesSpec.swift +76 -0
  104. package/ios/Tests/FunctionSpec.swift +2 -3
  105. package/ios/Tests/FunctionWithConvertiblesSpec.swift +2 -3
  106. package/ios/Tests/JavaScriptObjectSpec.swift +97 -0
  107. package/ios/Tests/JavaScriptRuntimeSpec.swift +94 -0
  108. package/ios/Tests/ModuleEventListenersSpec.swift +2 -3
  109. package/ios/Tests/ModuleRegistrySpec.swift +2 -3
  110. package/ios/Tests/RecordSpec.swift +2 -3
  111. package/package.json +2 -2
  112. package/src/NativeModulesProxy.native.ts +2 -22
  113. package/src/NativeModulesProxy.types.ts +0 -8
  114. package/src/NativeViewManagerAdapter.native.tsx +12 -28
  115. package/src/sweet/NativeErrorManager.ts +1 -1
  116. package/android/src/main/java/expo/modules/kotlin/events/KEventEmitterWrapper.kt +0 -26
  117. package/android/src/main/java/expo/modules/kotlin/methods/Method.kt +0 -14
  118. package/android/src/main/java/expo/modules/kotlin/methods/PromiseMethod.kt +0 -15
  119. package/ios/JSI/JSIInstaller.mm +0 -34
  120. package/ios/JSI/JavaScriptObject.h +0 -60
  121. package/ios/JSI/JavaScriptObject.mm +0 -93
  122. package/ios/JSI/JavaScriptRuntime.mm +0 -102
  123. package/ios/NativeModulesProxy/EXComponentDataCompatibleWrapper.h +0 -16
  124. package/ios/NativeModulesProxy/EXComponentDataCompatibleWrapper.m +0 -28
@@ -0,0 +1,94 @@
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ Enum with available kinds of values. It's almost the same as a result of "typeof"
5
+ in JavaScript, however `null` has its own kind (typeof null == "object").
6
+ */
7
+ public enum JavaScriptValueKind: String {
8
+ case undefined
9
+ case null
10
+ case bool
11
+ case number
12
+ case symbol
13
+ case string
14
+ case function
15
+ case object
16
+ }
17
+
18
+ public extension JavaScriptValue {
19
+ var kind: JavaScriptValueKind {
20
+ switch true {
21
+ case isUndefined():
22
+ return .undefined
23
+ case isNull():
24
+ return .null
25
+ case isBool():
26
+ return .bool
27
+ case isNumber():
28
+ return .number
29
+ case isSymbol():
30
+ return .symbol
31
+ case isString():
32
+ return .string
33
+ case isFunction():
34
+ return .function
35
+ default:
36
+ return .object
37
+ }
38
+ }
39
+
40
+ func asBool() throws -> Bool {
41
+ if isBool() {
42
+ return getBool()
43
+ }
44
+ throw JavaScriptValueConversionException((kind: kind, target: "Bool"))
45
+ }
46
+
47
+ func asInt() throws -> Int {
48
+ if isNumber() {
49
+ return getInt()
50
+ }
51
+ throw JavaScriptValueConversionException((kind: kind, target: "Int"))
52
+ }
53
+
54
+ func asDouble() throws -> Double {
55
+ if isNumber() {
56
+ return getDouble()
57
+ }
58
+ throw JavaScriptValueConversionException((kind: kind, target: "Double"))
59
+ }
60
+
61
+ func asString() throws -> String {
62
+ if isString() {
63
+ return getString()
64
+ }
65
+ throw JavaScriptValueConversionException((kind: kind, target: "String"))
66
+ }
67
+
68
+ func asArray() throws -> [JavaScriptValue?] {
69
+ if isObject() {
70
+ return getArray()
71
+ }
72
+ throw JavaScriptValueConversionException((kind: kind, target: "Array"))
73
+ }
74
+
75
+ func asDict() throws -> [String: Any] {
76
+ if isObject() {
77
+ return getDictionary()
78
+ }
79
+ throw JavaScriptValueConversionException((kind: kind, target: "Dict"))
80
+ }
81
+
82
+ func asObject() throws -> JavaScriptObject {
83
+ if isObject() {
84
+ return getObject()
85
+ }
86
+ throw JavaScriptValueConversionException((kind: kind, target: "Object"))
87
+ }
88
+ }
89
+
90
+ internal final class JavaScriptValueConversionException: GenericException<(kind: JavaScriptValueKind, target: String)> {
91
+ override var reason: String {
92
+ "Cannot represent a value of kind '\(param.kind)' as \(param.target)"
93
+ }
94
+ }
@@ -13,7 +13,7 @@
13
13
 
14
14
  @property (nonatomic, strong) EXModuleRegistryProvider *moduleRegistryProvider;
15
15
  @property (nonatomic, strong) EXViewManagerAdapterClassesRegistry *viewManagersClassesRegistry;
16
- @property (nonatomic, strong, nullable) id<ModulesProviderObjCProtocol> swiftModulesProvider;
16
+ @property (nonatomic, strong, nullable) ModulesProvider *swiftModulesProvider;
17
17
 
18
18
  @end
19
19
 
@@ -28,16 +28,6 @@
28
28
  return self;
29
29
  }
30
30
 
31
- - (instancetype)initWithModuleRegistryProvider:(EXModuleRegistryProvider *)moduleRegistryProvider swiftModulesProviderClass:(nullable Class)swiftModulesProviderClass
32
- {
33
- if (self = [self initWithModuleRegistryProvider:moduleRegistryProvider]) {
34
- if ([swiftModulesProviderClass conformsToProtocol:@protocol(ModulesProviderObjCProtocol)]) {
35
- _swiftModulesProvider = [swiftModulesProviderClass new];
36
- }
37
- }
38
- return self;
39
- }
40
-
41
31
  - (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge
42
32
  {
43
33
  return [self extraModulesForModuleRegistry:[_moduleRegistryProvider moduleRegistry]];
@@ -12,7 +12,7 @@
12
12
  // Swift compatibility headers (e.g. `ExpoModulesCore-Swift.h`) are not available in headers,
13
13
  // so we use class forward declaration here. Swift header must be imported in the `.m` file.
14
14
  @class SwiftInteropBridge;
15
- @protocol ModulesProviderObjCProtocol;
15
+ @class ModulesProvider;
16
16
 
17
17
  NS_SWIFT_NAME(NativeModulesProxy)
18
18
  @interface EXNativeModulesProxy : NSObject <RCTBridgeModule>
@@ -25,6 +25,6 @@ NS_SWIFT_NAME(NativeModulesProxy)
25
25
  - (void)callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNameOrKey arguments:(NSArray *)arguments resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject;
26
26
  - (id)callMethodSync:(NSString *)moduleName methodName:(NSString *)methodName arguments:(NSArray *)arguments;
27
27
 
28
- + (id<ModulesProviderObjCProtocol>)getExpoModulesProvider;
28
+ + (ModulesProvider *)getExpoModulesProvider;
29
29
 
30
30
  @end
@@ -10,7 +10,6 @@
10
10
 
11
11
  #import <jsi/jsi.h>
12
12
 
13
- #import <ExpoModulesCore/EXComponentDataCompatibleWrapper.h>
14
13
  #import <ExpoModulesCore/EXNativeModulesProxy.h>
15
14
  #import <ExpoModulesCore/EXEventEmitter.h>
16
15
  #import <ExpoModulesCore/EXViewManager.h>
@@ -18,11 +17,11 @@
18
17
  #import <ExpoModulesCore/EXViewManagerAdapterClassesRegistry.h>
19
18
  #import <ExpoModulesCore/EXModuleRegistryProvider.h>
20
19
  #import <ExpoModulesCore/EXReactNativeEventEmitter.h>
21
- #import <ExpoModulesCore/JSIInstaller.h>
20
+ #import <ExpoModulesCore/EXJSIInstaller.h>
22
21
  #import <ExpoModulesCore/Swift.h>
23
22
 
24
23
  static const NSString *exportedMethodsNamesKeyPath = @"exportedMethods";
25
- static const NSString *viewManagersNamesKeyPath = @"viewManagersNames";
24
+ static const NSString *viewManagersMetadataKeyPath = @"viewManagersMetadata";
26
25
  static const NSString *exportedConstantsKeyPath = @"modulesConstants";
27
26
 
28
27
  static const NSString *methodInfoKeyKey = @"key";
@@ -91,8 +90,9 @@ RCT_EXPORT_MODULE(NativeUnimoduleProxy)
91
90
 
92
91
  - (NSDictionary *)constantsToExport
93
92
  {
94
- // Install the TurboModule implementation of the proxy.
95
- [self installExpoTurboModules];
93
+ // Install ExpoModules host object in the runtime. It's probably not the right place,
94
+ // but it's the earliest moment in bridge's lifecycle when we have access to the runtime.
95
+ [self installExpoModulesHostObject];
96
96
 
97
97
  NSMutableDictionary <NSString *, id> *exportedModulesConstants = [NSMutableDictionary dictionary];
98
98
  // Grab all the constants exported by modules
@@ -124,17 +124,21 @@ RCT_EXPORT_MODULE(NativeUnimoduleProxy)
124
124
  // Add entries from Swift modules
125
125
  [exportedMethodsNamesAccumulator addEntriesFromDictionary:[_swiftInteropBridge exportedFunctionNames]];
126
126
 
127
- // Also, add `viewManagersNames` for sanity check and testing purposes -- with names we know what managers to mock on UIManager
127
+ // Also, add `viewManagersMetadata` for sanity check and testing purposes -- with names we know what managers to mock on UIManager
128
128
  NSArray<EXViewManager *> *viewManagers = [_exModuleRegistry getAllViewManagers];
129
- NSMutableArray<NSString *> *viewManagersNames = [NSMutableArray arrayWithCapacity:[viewManagers count]];
129
+ NSMutableDictionary<NSString *, NSDictionary *> *viewManagersMetadata = [[NSMutableDictionary alloc] initWithCapacity:[viewManagers count]];
130
+
130
131
  for (EXViewManager *viewManager in viewManagers) {
131
- [viewManagersNames addObject:[viewManager viewName]];
132
+ viewManagersMetadata[viewManager.viewName] = @{
133
+ @"propsNames": [[viewManager getPropsNames] allKeys]
134
+ };
132
135
  }
133
136
 
134
- [viewManagersNames addObjectsFromArray:[_swiftInteropBridge exportedViewManagersNames]];
137
+ // Add entries from Swift view managers
138
+ [viewManagersMetadata addEntriesFromDictionary:[_swiftInteropBridge viewManagersMetadata]];
135
139
 
136
140
  NSMutableDictionary <NSString *, id> *constantsAccumulator = [NSMutableDictionary dictionary];
137
- constantsAccumulator[viewManagersNamesKeyPath] = viewManagersNames;
141
+ constantsAccumulator[viewManagersMetadataKeyPath] = viewManagersMetadata;
138
142
  constantsAccumulator[exportedConstantsKeyPath] = exportedModulesConstants;
139
143
  constantsAccumulator[exportedMethodsNamesKeyPath] = exportedMethodsNamesAccumulator;
140
144
 
@@ -207,7 +211,7 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
207
211
 
208
212
  #pragma mark - Statics
209
213
 
210
- + (id<ModulesProviderObjCProtocol>)getExpoModulesProvider
214
+ + (ModulesProvider *)getExpoModulesProvider
211
215
  {
212
216
  // Dynamically gets the modules provider class.
213
217
  // NOTE: This needs to be versioned in Expo Go.
@@ -291,13 +295,13 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
291
295
  // Register the view managers as additional modules.
292
296
  [self registerAdditionalModuleClasses:additionalModuleClasses inBridge:bridge];
293
297
 
298
+ // Get the instance of `EXReactEventEmitter` bridge module and give it access to the interop bridge.
299
+ EXReactNativeEventEmitter *eventEmitter = [bridge moduleForClass:[EXReactNativeEventEmitter class]];
300
+ [eventEmitter setSwiftInteropBridge:_swiftInteropBridge];
301
+
294
302
  // As the last step, when the registry is owned,
295
303
  // register the event emitter and initialize the registry.
296
304
  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
305
  [_exModuleRegistry registerInternalModule:eventEmitter];
302
306
 
303
307
  // Let the modules consume the registry :)
@@ -362,7 +366,7 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
362
366
  NSString *className = NSStringFromClass(moduleClass);
363
367
 
364
368
  if ([moduleClass isSubclassOfClass:[RCTViewManager class]] && !componentDataByName[className]) {
365
- RCTComponentData *componentData = [[EXComponentDataCompatibleWrapper alloc] initWithManagerClass:moduleClass bridge:bridge eventDispatcher:bridge.eventDispatcher];
369
+ RCTComponentData *componentData = [[RCTComponentData alloc] initWithManagerClass:moduleClass bridge:bridge eventDispatcher:bridge.eventDispatcher];
366
370
  componentDataByName[className] = componentData;
367
371
  }
368
372
  }
@@ -399,19 +403,17 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
399
403
  }
400
404
 
401
405
  /**
402
- Installs expo modules in JSI runtime.
406
+ Installs ExpoModules host object in the runtime that the current bridge operates on.
403
407
  */
404
- - (void)installExpoTurboModules
408
+ - (void)installExpoModulesHostObject
405
409
  {
406
410
  facebook::jsi::Runtime *jsiRuntime = [_bridge respondsToSelector:@selector(runtime)] ? reinterpret_cast<facebook::jsi::Runtime *>(_bridge.runtime) : nullptr;
407
411
 
408
412
  if (jsiRuntime) {
409
- JavaScriptRuntime *runtime = [[JavaScriptRuntime alloc] initWithRuntime:*jsiRuntime callInvoker:_bridge.jsCallInvoker];
413
+ EXJavaScriptRuntime *runtime = [[EXJavaScriptRuntime alloc] initWithRuntime:jsiRuntime callInvoker:_bridge.jsCallInvoker];
410
414
 
411
- [JavaScriptRuntimeManager installExpoModulesToRuntime:runtime withSwiftInterop:_swiftInteropBridge];
415
+ [EXJavaScriptRuntimeManager installExpoModulesToRuntime:runtime withSwiftInterop:_swiftInteropBridge];
412
416
  [_swiftInteropBridge setRuntime:runtime];
413
-
414
- expo::installRuntimeObjects(*jsiRuntime, _bridge.jsCallInvoker, self);
415
417
  }
416
418
  }
417
419
 
@@ -0,0 +1,18 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ #import <UIKit/UIKit.h>
4
+
5
+ #import <ExpoModulesCore/EXDefines.h>
6
+ #import <React/RCTBridge.h>
7
+
8
+
9
+ EX_EXTERN_C_BEGIN
10
+
11
+ /**
12
+ * Backward compatible version of `RCTAppSetupDefaultRootView`.
13
+ *
14
+ * `RCTAppSetupDefaultRootView` is introduced in react-native 0.68. To make `expo-modules-core` compatible with older react-native, introduces this compatible helper.
15
+ */
16
+ UIView *EXAppSetupDefaultRootView(RCTBridge *bridge, NSString *moduleName, NSDictionary *initialProperties);
17
+
18
+ EX_EXTERN_C_END
@@ -0,0 +1,19 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoModulesCore/EXReactCompatibleHelpers.h>
4
+
5
+ #import <React/RCTRootView.h>
6
+
7
+ #if __has_include(<React/RCTAppSetupUtils.h>)
8
+ #import <React/RCTAppSetupUtils.h>
9
+ #endif
10
+
11
+ UIView *EXAppSetupDefaultRootView(RCTBridge *bridge, NSString *moduleName, NSDictionary *initialProperties)
12
+ {
13
+ #if __has_include(<React/RCTAppSetupUtils.h>)
14
+ return RCTAppSetupDefaultRootView(bridge, moduleName, initialProperties);
15
+ #else
16
+ return [[RCTRootView alloc] initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties];
17
+ #endif
18
+ }
19
+
@@ -22,10 +22,10 @@ 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]?) -> UIView {
26
26
  return self.handlers.lazy
27
27
  .compactMap { $0.createRootView(reactDelegate: self, bridge: bridge, moduleName: moduleName, initialProperties: initialProperties) }
28
- .first(where: { _ in true }) ?? RCTRootView(bridge: bridge, moduleName: moduleName, initialProperties: initialProperties)
28
+ .first(where: { _ in true }) ?? EXAppSetupDefaultRootView(bridge, moduleName, initialProperties)
29
29
  }
30
30
 
31
31
  @objc
@@ -1,6 +1,6 @@
1
1
  // Copyright 2018-present 650 Industries. All rights reserved.
2
2
 
3
- import Foundation
3
+ import React
4
4
 
5
5
  /**
6
6
  The handler for `ExpoReactDelegate`. A module can implement a handler to process react instance creation.
@@ -3,6 +3,13 @@ import UIKit
3
3
  The app context is an interface to a single Expo app.
4
4
  */
5
5
  public final class AppContext {
6
+ internal static func create() -> AppContext {
7
+ let appContext = AppContext()
8
+
9
+ appContext.runtime = JavaScriptRuntime()
10
+ return appContext
11
+ }
12
+
6
13
  /**
7
14
  The module registry for the app context.
8
15
  */
@@ -97,6 +104,13 @@ public final class AppContext {
97
104
  return legacyModule(implementing: EXEventEmitterService.self)
98
105
  }
99
106
 
107
+ /**
108
+ Provides access to the logger from legacy module registry.
109
+ */
110
+ public var logger: EXLogManager? {
111
+ return legacyModuleRegistry?.getSingletonModule(forName: EXLogManager.name()) as? EXLogManager
112
+ }
113
+
100
114
  /**
101
115
  Starts listening to `UIApplication` notifications.
102
116
  */
@@ -129,6 +143,12 @@ public final class AppContext {
129
143
 
130
144
  // MARK: - Runtime
131
145
 
146
+ internal func installExpoModulesHostObject(_ interopBridge: SwiftInteropBridge) throws {
147
+ guard let runtime = runtime else {
148
+ throw UndefinedRuntimeException()
149
+ }
150
+ EXJavaScriptRuntimeManager.installExpoModules(to: runtime, withSwiftInterop: interopBridge)
151
+ }
132
152
  /**
133
153
  Unsets runtime objects that we hold for each module.
134
154
  */
@@ -152,7 +172,13 @@ public final class AppContext {
152
172
 
153
173
  class DeallocatedAppContextException: Exception {
154
174
  override var reason: String {
155
- "The app context has been deallocated"
175
+ "The AppContext has been deallocated"
176
+ }
177
+ }
178
+
179
+ class UndefinedRuntimeException: Exception {
180
+ override var reason: String {
181
+ "The AppContext has undefined runtime"
156
182
  }
157
183
  }
158
184
  }
@@ -0,0 +1,17 @@
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ Represents a function that can only be called asynchronously, thus its JavaScript equivalent returns a Promise.
5
+
6
+ - ToDo: Move some asynchronous logic from `ConcreteFunction` (like `call(args:promise:)`) to this class and drop the `isAsync` property.
7
+ */
8
+ public final class AsyncFunction<Args, ReturnType>: ConcreteFunction<Args, ReturnType> {
9
+ override init(
10
+ _ name: String,
11
+ argTypes: [AnyArgumentType],
12
+ _ closure: @escaping ConcreteFunction<Args, ReturnType>.ClosureType
13
+ ) {
14
+ super.init(name, argTypes: argTypes, closure)
15
+ self.isAsync = true
16
+ }
17
+ }
@@ -1,6 +1,6 @@
1
1
  import Dispatch
2
2
 
3
- public final class ConcreteFunction<Args, ReturnType>: AnyFunction {
3
+ public class ConcreteFunction<Args, ReturnType>: AnyFunction {
4
4
  public typealias ClosureType = (Args) throws -> ReturnType
5
5
 
6
6
  public let name: String
@@ -29,6 +29,11 @@ public final class ConcreteFunction<Args, ReturnType>: AnyFunction {
29
29
  self.name = name
30
30
  self.argTypes = argTypes
31
31
  self.closure = closure
32
+
33
+ // This is temporary solution to keep backwards compatibility for existing functions — they all end with "Async".
34
+ // `function` component that we've used so far was async by default, but we decided to replace it with `asyncFunction`
35
+ // and make `function`s synchronous. Introduced in SDK45, can be removed in SDK46 after migrating all modules.
36
+ self.isAsync = name.hasSuffix("Async")
32
37
  }
33
38
 
34
39
  public func call(args: [Any], promise: Promise) {
@@ -36,6 +36,17 @@ internal func createSyncFunctionBlock(holder: ModuleHolder, name functionName: S
36
36
  }
37
37
  }
38
38
 
39
+ /**
40
+ If given argument is a JavaScriptValue, it's unpacked and converted to corresponding Foundation type.
41
+ Otherwise, the argument is returned as is.
42
+ */
43
+ internal func unpackIfJavaScriptValue(_ value: Any) -> Any {
44
+ if let value = value as? JavaScriptValue {
45
+ return value.getRaw() as Any
46
+ }
47
+ return value
48
+ }
49
+
39
50
  private class ModuleUnavailableException: GenericException<String> {
40
51
  override var reason: String {
41
52
  "Module '\(param)' is no longer available"
@@ -70,8 +70,16 @@ public final class ModuleHolder {
70
70
  }
71
71
  let queue = function.queue ?? DispatchQueue.global(qos: .default)
72
72
 
73
+ // Given arguments can be:
74
+ // - Swift primitives when invoked through the bridge and in unit tests
75
+ // - `JavaScriptValue`s when the function is called through the JSI
76
+ // The latter need to be unpacked to Swift primitives on the JS thread,
77
+ // so before the function call is scheduled on the queue.
78
+ // TODO: Move arguments conversion mechanism to JS thread and allow JS types as function arguments.
79
+ let unpackedArgs = args.map { arg in unpackIfJavaScriptValue(arg) }
80
+
73
81
  queue.async {
74
- function.call(args: args, promise: promise)
82
+ function.call(args: unpackedArgs, promise: promise)
75
83
  }
76
84
  } catch let error as CodedError {
77
85
  promise.reject(error)
@@ -92,7 +100,10 @@ public final class ModuleHolder {
92
100
  @discardableResult
93
101
  func callSync(function functionName: String, args: [Any]) -> Any? {
94
102
  if let function = definition.functions[functionName] {
95
- return function.callSync(args: args)
103
+ // The comment in `call(function:args:promise)` is partially applicable here as well.
104
+ // TODO: Move unpacking JS values to `callSync` in function's instance
105
+ let unpackedArgs = args.map { arg in unpackIfJavaScriptValue(arg) }
106
+ return function.callSync(args: unpackedArgs)
96
107
  }
97
108
  return nil
98
109
  }
@@ -113,7 +124,7 @@ public final class ModuleHolder {
113
124
 
114
125
  // Fill in with constants
115
126
  for (key, value) in getConstants() {
116
- object[key] = value
127
+ object.setProperty(key, value: value)
117
128
  }
118
129
 
119
130
  // Fill in with functions
@@ -1,16 +1,9 @@
1
1
  import Foundation
2
2
 
3
3
  /**
4
- An empty protocol that Objective-C can refer to as a type of the modules provider.
5
- In Objective-C code we do not do anything with it except passing it back to the Swift light side.
4
+ Swift protocol defining the requirements for modules providers.
6
5
  */
7
- @objc
8
- public protocol ModulesProviderObjCProtocol {}
9
-
10
- /**
11
- Swift protocol defining the requirements for modules providers. Extends its Objective-C counterpart `ModulesProviderObjCProtocol`.
12
- */
13
- public protocol ModulesProviderProtocol: ModulesProviderObjCProtocol {
6
+ public protocol ModulesProviderProtocol {
14
7
  func getModuleClasses() -> [AnyModule.Type]
15
8
 
16
9
  /**
@@ -30,7 +23,7 @@ public protocol ModulesProviderProtocol: ModulesProviderObjCProtocol {
30
23
  The proper implementation is generated by autolinking as part of `pod install` command.
31
24
  */
32
25
  @objc
33
- open class ModulesProvider: NSObject, ModulesProviderProtocol, ModulesProviderObjCProtocol {
26
+ open class ModulesProvider: NSObject, ModulesProviderProtocol {
34
27
  open func getModuleClasses() -> [AnyModule.Type] {
35
28
  return []
36
29
  }