expo-modules-core 0.4.8 → 0.6.1

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 (149) hide show
  1. package/CHANGELOG.md +32 -1
  2. package/android/build.gradle +30 -2
  3. package/android/src/main/java/expo/modules/adapters/react/ModuleRegistryAdapter.java +42 -5
  4. package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +49 -5
  5. package/android/src/main/java/expo/modules/core/BasePackage.java +6 -0
  6. package/android/src/main/java/expo/modules/core/ModulePriorities.kt +25 -0
  7. package/android/src/main/java/expo/modules/core/interfaces/ActivityEventListener.java +3 -1
  8. package/android/src/main/java/expo/modules/core/interfaces/ApplicationLifecycleListener.java +10 -0
  9. package/android/src/main/java/expo/modules/core/interfaces/Package.java +4 -0
  10. package/android/src/main/java/expo/modules/core/interfaces/ReactActivityHandler.java +21 -0
  11. package/android/src/main/java/expo/modules/core/interfaces/ReactActivityLifecycleListener.java +14 -0
  12. package/android/src/main/java/expo/modules/core/interfaces/ReactNativeHostHandler.java +70 -0
  13. package/android/src/main/java/expo/modules/core/utilities/KotlinUtilities.kt +23 -0
  14. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +166 -0
  15. package/android/src/main/java/expo/modules/kotlin/DynamicExtenstions.kt +9 -0
  16. package/android/src/main/java/expo/modules/kotlin/ExpoModulesHelper.kt +18 -0
  17. package/android/src/main/java/expo/modules/kotlin/KPromiseWrapper.kt +24 -0
  18. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +98 -0
  19. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +41 -0
  20. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +56 -0
  21. package/android/src/main/java/expo/modules/kotlin/ModulesProvider.kt +7 -0
  22. package/android/src/main/java/expo/modules/kotlin/Promise.kt +13 -0
  23. package/android/src/main/java/expo/modules/kotlin/ReactLifecycleDelegate.kt +39 -0
  24. package/android/src/main/java/expo/modules/kotlin/ReadableArrayIterator.kt +14 -0
  25. package/android/src/main/java/expo/modules/kotlin/ReadableTypeExtensions.kt +18 -0
  26. package/android/src/main/java/expo/modules/kotlin/allocators/ObjectConstructor.kt +5 -0
  27. package/android/src/main/java/expo/modules/kotlin/allocators/ObjectConstructorFactory.kt +31 -0
  28. package/android/src/main/java/expo/modules/kotlin/allocators/UnsafeAllocator.kt +49 -0
  29. package/android/src/main/java/expo/modules/kotlin/events/EventListener.kt +39 -0
  30. package/android/src/main/java/expo/modules/kotlin/events/EventName.kt +31 -0
  31. package/android/src/main/java/expo/modules/kotlin/events/EventsDefinition.kt +3 -0
  32. package/android/src/main/java/expo/modules/kotlin/events/KEventEmitterWrapper.kt +26 -0
  33. package/android/src/main/java/expo/modules/kotlin/events/OnActivityResultPayload.kt +8 -0
  34. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +70 -0
  35. package/android/src/main/java/expo/modules/kotlin/methods/AnyMethod.kt +50 -0
  36. package/android/src/main/java/expo/modules/kotlin/methods/Method.kt +14 -0
  37. package/android/src/main/java/expo/modules/kotlin/methods/PromiseMethod.kt +15 -0
  38. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +24 -0
  39. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +227 -0
  40. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +16 -0
  41. package/android/src/main/java/expo/modules/kotlin/records/Field.kt +5 -0
  42. package/android/src/main/java/expo/modules/kotlin/records/Record.kt +3 -0
  43. package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +55 -0
  44. package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +14 -0
  45. package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +44 -0
  46. package/android/src/main/java/expo/modules/kotlin/types/BasicTypeConverters.kt +60 -0
  47. package/android/src/main/java/expo/modules/kotlin/types/EnumTypeConverter.kt +84 -0
  48. package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +25 -0
  49. package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +39 -0
  50. package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +28 -0
  51. package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +19 -0
  52. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +107 -0
  53. package/android/src/main/java/expo/modules/kotlin/views/AnyViewProp.kt +10 -0
  54. package/android/src/main/java/expo/modules/kotlin/views/ConcreteViewProp.kt +17 -0
  55. package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +22 -0
  56. package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +21 -0
  57. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +41 -0
  58. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +40 -0
  59. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +21 -0
  60. package/android/src/main/java/expo/modules/kotlin/views/ViewWrapperDelegateHolder.kt +5 -0
  61. package/build/NativeModulesProxy.native.d.ts +4 -0
  62. package/build/NativeModulesProxy.native.js +14 -1
  63. package/build/NativeModulesProxy.native.js.map +1 -1
  64. package/build/NativeModulesProxy.types.d.ts +3 -0
  65. package/build/NativeModulesProxy.types.js.map +1 -1
  66. package/build/NativeViewManagerAdapter.native.js +1 -1
  67. package/build/NativeViewManagerAdapter.native.js.map +1 -1
  68. package/ios/AppDelegates/EXAppDelegateWrapper.h +19 -0
  69. package/ios/AppDelegates/EXAppDelegateWrapper.m +45 -0
  70. package/ios/AppDelegates/EXAppDelegatesLoader.h +15 -0
  71. package/ios/AppDelegates/EXAppDelegatesLoader.m +30 -0
  72. package/ios/AppDelegates/EXLegacyAppDelegateWrapper.h +16 -0
  73. package/ios/{EXAppDelegateWrapper.m → AppDelegates/EXLegacyAppDelegateWrapper.m} +2 -2
  74. package/ios/AppDelegates/ExpoAppDelegate.swift +282 -0
  75. package/ios/AppDelegates/ExpoAppDelegateSubscriber.swift +24 -0
  76. package/ios/EXAppDefines.h +26 -0
  77. package/ios/EXAppDefines.m +61 -0
  78. package/ios/ExpoModulesCore.podspec +8 -3
  79. package/ios/JSI/ExpoModulesProxySpec.h +24 -0
  80. package/ios/JSI/ExpoModulesProxySpec.mm +135 -0
  81. package/ios/JSI/JSIConversions.h +42 -0
  82. package/ios/JSI/JSIConversions.mm +164 -0
  83. package/ios/JSI/JSIInstaller.h +19 -0
  84. package/ios/JSI/JSIInstaller.mm +22 -0
  85. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +1 -6
  86. package/ios/NativeModulesProxy/EXNativeModulesProxy.h +6 -0
  87. package/ios/NativeModulesProxy/{EXNativeModulesProxy.m → EXNativeModulesProxy.mm} +63 -17
  88. package/ios/ReactDelegates/EXRCTBridgeDelegateInterceptor.h +16 -0
  89. package/ios/ReactDelegates/EXRCTBridgeDelegateInterceptor.m +49 -0
  90. package/ios/ReactDelegates/EXReactDelegateWrapper+Private.h +18 -0
  91. package/ios/ReactDelegates/EXReactDelegateWrapper.h +25 -0
  92. package/ios/ReactDelegates/EXReactDelegateWrapper.m +40 -0
  93. package/ios/ReactDelegates/ExpoReactDelegate.swift +37 -0
  94. package/ios/ReactDelegates/ExpoReactDelegateHandler.swift +52 -0
  95. package/ios/ReactDelegates/ModulePriorities.swift +20 -0
  96. package/ios/Services/EXReactNativeEventEmitter.h +6 -0
  97. package/ios/Services/EXReactNativeEventEmitter.m +15 -0
  98. package/ios/Swift/AppContext.swift +14 -1
  99. package/ios/Swift/Arguments/AnyArgument.swift +14 -0
  100. package/ios/Swift/Arguments/AnyArgumentType.swift +13 -0
  101. package/ios/Swift/Arguments/ArgumentType.swift +24 -0
  102. package/ios/Swift/Arguments/ConvertibleArgument.swift +15 -0
  103. package/ios/Swift/Arguments/Convertibles.swift +107 -0
  104. package/ios/Swift/Arguments/Types/ArrayArgumentType.swift +42 -0
  105. package/ios/Swift/Arguments/Types/ConvertibleArgumentType.swift +16 -0
  106. package/ios/Swift/Arguments/Types/EnumArgumentType.swift +105 -0
  107. package/ios/Swift/Arguments/Types/OptionalArgumentType.swift +49 -0
  108. package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +15 -0
  109. package/ios/Swift/Arguments/Types/RawArgumentType.swift +25 -0
  110. package/ios/Swift/Conversions.swift +199 -7
  111. package/ios/Swift/EventListener.swift +37 -5
  112. package/ios/Swift/Functions/AnyFunction.swift +42 -0
  113. package/ios/Swift/{Methods/ConcreteMethod.swift → Functions/ConcreteFunction.swift} +32 -34
  114. package/ios/Swift/ModuleHolder.swift +86 -20
  115. package/ios/Swift/ModuleRegistry.swift +19 -8
  116. package/ios/Swift/Modules/AnyModule.swift +8 -8
  117. package/ios/Swift/Modules/Module.swift +11 -0
  118. package/ios/Swift/Modules/ModuleDefinition.swift +55 -15
  119. package/ios/Swift/Modules/ModuleDefinitionBuilder.swift +1 -1
  120. package/ios/Swift/Modules/ModuleDefinitionComponents.swift +149 -54
  121. package/ios/Swift/ModulesProvider.swift +19 -0
  122. package/ios/Swift/Promise.swift +1 -1
  123. package/ios/Swift/Records/Field.swift +1 -1
  124. package/ios/Swift/Records/Record.swift +8 -1
  125. package/ios/Swift/SwiftInteropBridge.swift +46 -17
  126. package/ios/Swift/Views/AnyViewProp.swift +2 -2
  127. package/ios/Swift/Views/ConcreteViewProp.swift +37 -10
  128. package/ios/Swift/Views/ViewModuleWrapper.swift +9 -4
  129. package/ios/Swift.h +9 -0
  130. package/ios/Tests/ArgumentTypeSpec.swift +145 -0
  131. package/ios/Tests/ConstantsSpec.swift +36 -0
  132. package/ios/Tests/ConvertiblesSpec.swift +265 -0
  133. package/ios/Tests/EXAppDefinesTest.m +99 -0
  134. package/ios/Tests/{MethodSpec.swift → FunctionSpec.swift} +69 -54
  135. package/ios/Tests/FunctionWithConvertiblesSpec.swift +66 -0
  136. package/ios/Tests/Mocks/ModuleMocks.swift +21 -7
  137. package/ios/Tests/ModuleEventListenersSpec.swift +17 -16
  138. package/ios/Tests/ModuleRegistrySpec.swift +4 -7
  139. package/package.json +3 -3
  140. package/src/NativeModulesProxy.native.ts +22 -2
  141. package/src/NativeModulesProxy.types.ts +8 -0
  142. package/src/NativeViewManagerAdapter.native.tsx +1 -1
  143. package/android/src/main/java/expo/modules/core/interfaces/ApplicationLifecycleListener.kt +0 -9
  144. package/android/src/main/java/expo/modules/core/interfaces/ReactActivityLifecycleListener.kt +0 -11
  145. package/android/src/main/java/expo/modules/core/interfaces/ReactNativeHostHandler.kt +0 -51
  146. package/ios/EXAppDelegateWrapper.h +0 -13
  147. package/ios/Swift/Methods/AnyArgumentType.swift +0 -48
  148. package/ios/Swift/Methods/AnyMethod.swift +0 -31
  149. package/ios/Swift/Methods/AnyMethodArgument.swift +0 -13
@@ -0,0 +1,135 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ #import <React/RCTUtils.h>
4
+
5
+ #import <ExpoModulesCore/JSIConversions.h>
6
+ #import <ExpoModulesCore/ExpoModulesProxySpec.h>
7
+
8
+ namespace expo {
9
+
10
+ using PromiseInvocationBlock = void (^)(RCTPromiseResolveBlock resolveWrapper, RCTPromiseRejectBlock rejectWrapper);
11
+
12
+ static void callPromiseSetupWithBlock(jsi::Runtime &runtime, std::shared_ptr<CallInvoker> jsInvoker, std::shared_ptr<Promise> promise, PromiseInvocationBlock setupBlock)
13
+ {
14
+ auto weakResolveWrapper = CallbackWrapper::createWeak(promise->resolve_.getFunction(runtime), runtime, jsInvoker);
15
+ auto weakRejectWrapper = CallbackWrapper::createWeak(promise->reject_.getFunction(runtime), runtime, jsInvoker);
16
+
17
+ __block BOOL resolveWasCalled = NO;
18
+ __block BOOL rejectWasCalled = NO;
19
+
20
+ RCTPromiseResolveBlock resolveBlock = ^(id result) {
21
+ if (rejectWasCalled) {
22
+ throw std::runtime_error("Tried to resolve a promise after it's already been rejected.");
23
+ }
24
+
25
+ if (resolveWasCalled) {
26
+ throw std::runtime_error("Tried to resolve a promise more than once.");
27
+ }
28
+
29
+ auto strongResolveWrapper = weakResolveWrapper.lock();
30
+ auto strongRejectWrapper = weakRejectWrapper.lock();
31
+ if (!strongResolveWrapper || !strongRejectWrapper) {
32
+ return;
33
+ }
34
+
35
+ strongResolveWrapper->jsInvoker().invokeAsync([weakResolveWrapper, weakRejectWrapper, result]() {
36
+ auto strongResolveWrapper2 = weakResolveWrapper.lock();
37
+ auto strongRejectWrapper2 = weakRejectWrapper.lock();
38
+ if (!strongResolveWrapper2 || !strongRejectWrapper2) {
39
+ return;
40
+ }
41
+
42
+ jsi::Runtime &rt = strongResolveWrapper2->runtime();
43
+ jsi::Value arg = convertObjCObjectToJSIValue(rt, result);
44
+ strongResolveWrapper2->callback().call(rt, arg);
45
+
46
+ strongResolveWrapper2->destroy();
47
+ strongRejectWrapper2->destroy();
48
+ });
49
+
50
+ resolveWasCalled = YES;
51
+ };
52
+
53
+ RCTPromiseRejectBlock rejectBlock = ^(NSString *code, NSString *message, NSError *error) {
54
+ if (resolveWasCalled) {
55
+ throw std::runtime_error("Tried to reject a promise after it's already been resolved.");
56
+ }
57
+
58
+ if (rejectWasCalled) {
59
+ throw std::runtime_error("Tried to reject a promise more than once.");
60
+ }
61
+
62
+ auto strongResolveWrapper = weakResolveWrapper.lock();
63
+ auto strongRejectWrapper = weakRejectWrapper.lock();
64
+ if (!strongResolveWrapper || !strongRejectWrapper) {
65
+ return;
66
+ }
67
+
68
+ NSDictionary *jsError = RCTJSErrorFromCodeMessageAndNSError(code, message, error);
69
+ strongRejectWrapper->jsInvoker().invokeAsync([weakResolveWrapper, weakRejectWrapper, jsError]() {
70
+ auto strongResolveWrapper2 = weakResolveWrapper.lock();
71
+ auto strongRejectWrapper2 = weakRejectWrapper.lock();
72
+ if (!strongResolveWrapper2 || !strongRejectWrapper2) {
73
+ return;
74
+ }
75
+
76
+ jsi::Runtime &rt = strongRejectWrapper2->runtime();
77
+ jsi::Value arg = convertNSDictionaryToJSIObject(rt, jsError);
78
+ strongRejectWrapper2->callback().call(rt, arg);
79
+
80
+ strongResolveWrapper2->destroy();
81
+ strongRejectWrapper2->destroy();
82
+ });
83
+
84
+ rejectWasCalled = YES;
85
+ };
86
+
87
+ setupBlock(resolveBlock, rejectBlock);
88
+ }
89
+
90
+ static jsi::Value __hostFunction_ExpoModulesProxySpec_callMethodAsync(jsi::Runtime &runtime, TurboModule &turboModule, const jsi::Value *args, size_t count)
91
+ {
92
+ auto expoModulesProxy = static_cast<ExpoModulesProxySpec *>(&turboModule);
93
+
94
+ // The function that is invoked as a setup of the JS `Promise`.
95
+ auto promiseSetupFunc = [expoModulesProxy, args](jsi::Runtime &runtime, std::shared_ptr<Promise> promise) {
96
+ callPromiseSetupWithBlock(runtime, expoModulesProxy->jsInvoker_, promise, ^(RCTPromiseResolveBlock resolver, RCTPromiseRejectBlock rejecter) {
97
+ NSString *moduleName = convertJSIStringToNSString(runtime, args[0].getString(runtime));
98
+ NSString *methodName = convertJSIStringToNSString(runtime, args[1].getString(runtime));
99
+ NSArray *arguments = convertJSIArrayToNSArray(runtime, args[2].getObject(runtime).asArray(runtime), expoModulesProxy->jsInvoker_);
100
+
101
+ [expoModulesProxy->nativeModulesProxy callMethod:moduleName
102
+ methodNameOrKey:methodName
103
+ arguments:arguments
104
+ resolver:resolver
105
+ rejecter:rejecter];
106
+ });
107
+ };
108
+
109
+ return createPromiseAsJSIValue(runtime, promiseSetupFunc);
110
+ }
111
+
112
+ static jsi::Value __hostFunction_ExpoModulesProxySpec_callMethodSync(jsi::Runtime &runtime, TurboModule &turboModule, const jsi::Value *args, size_t count)
113
+ {
114
+ auto expoModulesProxy = static_cast<ExpoModulesProxySpec *>(&turboModule);
115
+ NSString *moduleName = convertJSIStringToNSString(runtime, args[0].getString(runtime));
116
+ NSString *methodName = convertJSIStringToNSString(runtime, args[1].getString(runtime));
117
+ NSArray *arguments = convertJSIArrayToNSArray(runtime, args[2].getObject(runtime).asArray(runtime), expoModulesProxy->jsInvoker_);
118
+
119
+ id result = [expoModulesProxy->nativeModulesProxy callMethodSync:moduleName
120
+ methodName:methodName
121
+ arguments:arguments];
122
+
123
+ return convertObjCObjectToJSIValue(runtime, result);
124
+ }
125
+
126
+ ExpoModulesProxySpec::ExpoModulesProxySpec(std::shared_ptr<CallInvoker> callInvoker, EXNativeModulesProxy *nativeModulesProxy) :
127
+ TurboModule("ExpoModulesProxy", callInvoker),
128
+ nativeModulesProxy(nativeModulesProxy)
129
+ {
130
+ methodMap_["callMethodAsync"] = MethodMetadata {3, __hostFunction_ExpoModulesProxySpec_callMethodAsync};
131
+
132
+ methodMap_["callMethodSync"] = MethodMetadata {3, __hostFunction_ExpoModulesProxySpec_callMethodSync};
133
+ }
134
+
135
+ } // namespace expo
@@ -0,0 +1,42 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ #ifdef __cplusplus
4
+
5
+ #import <Foundation/Foundation.h>
6
+
7
+ #import <jsi/jsi.h>
8
+ #import <React/RCTBridgeModule.h>
9
+ #import <ReactCommon/CallInvoker.h>
10
+
11
+ using namespace facebook;
12
+ using namespace react;
13
+
14
+ namespace expo {
15
+
16
+ jsi::Value convertNSNumberToJSIBoolean(jsi::Runtime &runtime, NSNumber *value);
17
+
18
+ jsi::Value convertNSNumberToJSINumber(jsi::Runtime &runtime, NSNumber *value);
19
+
20
+ jsi::String convertNSStringToJSIString(jsi::Runtime &runtime, NSString *value);
21
+
22
+ jsi::Object convertNSDictionaryToJSIObject(jsi::Runtime &runtime, NSDictionary *value);
23
+
24
+ jsi::Array convertNSArrayToJSIArray(jsi::Runtime &runtime, NSArray *value);
25
+
26
+ std::vector<jsi::Value> convertNSArrayToStdVector(jsi::Runtime &runtime, NSArray *value);
27
+
28
+ jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value);
29
+
30
+ NSString *convertJSIStringToNSString(jsi::Runtime &runtime, const jsi::String &value);
31
+
32
+ NSArray *convertJSIArrayToNSArray(jsi::Runtime &runtime, const jsi::Array &value, std::shared_ptr<CallInvoker> jsInvoker);
33
+
34
+ NSDictionary *convertJSIObjectToNSDictionary(jsi::Runtime &runtime, const jsi::Object &value, std::shared_ptr<CallInvoker> jsInvoker);
35
+
36
+ id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value, std::shared_ptr<CallInvoker> jsInvoker);
37
+
38
+ RCTResponseSenderBlock convertJSIFunctionToCallback(jsi::Runtime &runtime, const jsi::Function &value, std::shared_ptr<CallInvoker> jsInvoker);
39
+
40
+ } // namespace expo
41
+
42
+ #endif
@@ -0,0 +1,164 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ #import <ReactCommon/TurboModuleUtils.h>
4
+ #import <ExpoModulesCore/JSIConversions.h>
5
+
6
+ namespace expo {
7
+
8
+ /**
9
+ * All static helper functions are ObjC++ specific.
10
+ */
11
+ jsi::Value convertNSNumberToJSIBoolean(jsi::Runtime &runtime, NSNumber *value)
12
+ {
13
+ return jsi::Value((bool)[value boolValue]);
14
+ }
15
+
16
+ jsi::Value convertNSNumberToJSINumber(jsi::Runtime &runtime, NSNumber *value)
17
+ {
18
+ return jsi::Value([value doubleValue]);
19
+ }
20
+
21
+ jsi::String convertNSStringToJSIString(jsi::Runtime &runtime, NSString *value)
22
+ {
23
+ return jsi::String::createFromUtf8(runtime, [value UTF8String] ?: "");
24
+ }
25
+
26
+ jsi::Object convertNSDictionaryToJSIObject(jsi::Runtime &runtime, NSDictionary *value)
27
+ {
28
+ jsi::Object result = jsi::Object(runtime);
29
+ for (NSString *k in value) {
30
+ result.setProperty(runtime, [k UTF8String], convertObjCObjectToJSIValue(runtime, value[k]));
31
+ }
32
+ return result;
33
+ }
34
+
35
+ jsi::Array convertNSArrayToJSIArray(jsi::Runtime &runtime, NSArray *value)
36
+ {
37
+ jsi::Array result = jsi::Array(runtime, value.count);
38
+ for (size_t i = 0; i < value.count; i++) {
39
+ result.setValueAtIndex(runtime, i, convertObjCObjectToJSIValue(runtime, value[i]));
40
+ }
41
+ return result;
42
+ }
43
+
44
+ std::vector<jsi::Value> convertNSArrayToStdVector(jsi::Runtime &runtime, NSArray *value)
45
+ {
46
+ std::vector<jsi::Value> result;
47
+ for (size_t i = 0; i < value.count; i++) {
48
+ result.emplace_back(convertObjCObjectToJSIValue(runtime, value[i]));
49
+ }
50
+ return result;
51
+ }
52
+
53
+ jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value)
54
+ {
55
+ if ([value isKindOfClass:[NSString class]]) {
56
+ return convertNSStringToJSIString(runtime, (NSString *)value);
57
+ } else if ([value isKindOfClass:[NSNumber class]]) {
58
+ if ([value isKindOfClass:[@YES class]]) {
59
+ return convertNSNumberToJSIBoolean(runtime, (NSNumber *)value);
60
+ }
61
+ return convertNSNumberToJSINumber(runtime, (NSNumber *)value);
62
+ } else if ([value isKindOfClass:[NSDictionary class]]) {
63
+ return convertNSDictionaryToJSIObject(runtime, (NSDictionary *)value);
64
+ } else if ([value isKindOfClass:[NSArray class]]) {
65
+ return convertNSArrayToJSIArray(runtime, (NSArray *)value);
66
+ } else if (value == (id)kCFNull) {
67
+ return jsi::Value::null();
68
+ }
69
+ return jsi::Value::undefined();
70
+ }
71
+
72
+ NSString *convertJSIStringToNSString(jsi::Runtime &runtime, const jsi::String &value)
73
+ {
74
+ return [NSString stringWithUTF8String:value.utf8(runtime).c_str()];
75
+ }
76
+
77
+ NSArray *convertJSIArrayToNSArray(jsi::Runtime &runtime, const jsi::Array &value, std::shared_ptr<CallInvoker> jsInvoker)
78
+ {
79
+ size_t size = value.size(runtime);
80
+ NSMutableArray *result = [NSMutableArray new];
81
+ for (size_t i = 0; i < size; i++) {
82
+ // Insert kCFNull when it's `undefined` value to preserve the indices.
83
+ [result
84
+ addObject:convertJSIValueToObjCObject(runtime, value.getValueAtIndex(runtime, i), jsInvoker) ?: (id)kCFNull];
85
+ }
86
+ return [result copy];
87
+ }
88
+
89
+ NSDictionary *convertJSIObjectToNSDictionary(jsi::Runtime &runtime, const jsi::Object &value, std::shared_ptr<CallInvoker> jsInvoker)
90
+ {
91
+ jsi::Array propertyNames = value.getPropertyNames(runtime);
92
+ size_t size = propertyNames.size(runtime);
93
+ NSMutableDictionary *result = [NSMutableDictionary new];
94
+ for (size_t i = 0; i < size; i++) {
95
+ jsi::String name = propertyNames.getValueAtIndex(runtime, i).getString(runtime);
96
+ NSString *k = convertJSIStringToNSString(runtime, name);
97
+ id v = convertJSIValueToObjCObject(runtime, value.getProperty(runtime, name), jsInvoker);
98
+ if (v) {
99
+ result[k] = v;
100
+ }
101
+ }
102
+ return [result copy];
103
+ }
104
+
105
+ id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value, std::shared_ptr<CallInvoker> jsInvoker)
106
+ {
107
+ if (value.isUndefined() || value.isNull()) {
108
+ return nil;
109
+ }
110
+ if (value.isBool()) {
111
+ return @(value.getBool());
112
+ }
113
+ if (value.isNumber()) {
114
+ return @(value.getNumber());
115
+ }
116
+ if (value.isString()) {
117
+ return convertJSIStringToNSString(runtime, value.getString(runtime));
118
+ }
119
+ if (value.isObject()) {
120
+ jsi::Object o = value.getObject(runtime);
121
+ if (o.isArray(runtime)) {
122
+ return convertJSIArrayToNSArray(runtime, o.getArray(runtime), jsInvoker);
123
+ }
124
+ if (o.isFunction(runtime)) {
125
+ return convertJSIFunctionToCallback(runtime, std::move(o.getFunction(runtime)), jsInvoker);
126
+ }
127
+ return convertJSIObjectToNSDictionary(runtime, o, jsInvoker);
128
+ }
129
+
130
+ throw std::runtime_error("Unsupported jsi::jsi::Value kind");
131
+ }
132
+
133
+ RCTResponseSenderBlock convertJSIFunctionToCallback(jsi::Runtime &runtime, const jsi::Function &value, std::shared_ptr<CallInvoker> jsInvoker)
134
+ {
135
+ auto weakWrapper = CallbackWrapper::createWeak(value.getFunction(runtime), runtime, jsInvoker);
136
+ BOOL __block wrapperWasCalled = NO;
137
+ RCTResponseSenderBlock callback = ^(NSArray *responses) {
138
+ if (wrapperWasCalled) {
139
+ throw std::runtime_error("callback arg cannot be called more than once");
140
+ }
141
+
142
+ auto strongWrapper = weakWrapper.lock();
143
+ if (!strongWrapper) {
144
+ return;
145
+ }
146
+
147
+ strongWrapper->jsInvoker().invokeAsync([weakWrapper, responses]() {
148
+ auto strongWrapper2 = weakWrapper.lock();
149
+ if (!strongWrapper2) {
150
+ return;
151
+ }
152
+
153
+ std::vector<jsi::Value> args = convertNSArrayToStdVector(strongWrapper2->runtime(), responses);
154
+ strongWrapper2->callback().call(strongWrapper2->runtime(), (const jsi::Value *)args.data(), args.size());
155
+ strongWrapper2->destroy();
156
+ });
157
+
158
+ wrapperWasCalled = YES;
159
+ };
160
+
161
+ return callback;
162
+ }
163
+
164
+ } // namespace expo
@@ -0,0 +1,19 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ #ifdef __cplusplus
4
+
5
+ #import <jsi/jsi.h>
6
+ #import <ReactCommon/RCTTurboModule.h>
7
+
8
+ #import <ExpoModulesCore/EXNativeModulesProxy.h>
9
+
10
+ using namespace facebook;
11
+ using namespace react;
12
+
13
+ namespace expo {
14
+
15
+ void installRuntimeObjects(jsi::Runtime &runtime, std::shared_ptr<CallInvoker> callInvoker, EXNativeModulesProxy *nativeModulesProxy);
16
+
17
+ } // namespace expo
18
+
19
+ #endif
@@ -0,0 +1,22 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoModulesCore/JSIInstaller.h>
4
+ #import <ExpoModulesCore/ExpoModulesProxySpec.h>
5
+
6
+ using namespace facebook;
7
+ using namespace react;
8
+
9
+ //using PromiseInvocationBlock = void (^)(RCTPromiseResolveBlock resolveWrapper, RCTPromiseRejectBlock rejectWrapper);
10
+
11
+ namespace expo {
12
+
13
+ void installRuntimeObjects(jsi::Runtime &runtime, std::shared_ptr<CallInvoker> callInvoker, EXNativeModulesProxy *nativeModulesProxy)
14
+ {
15
+ auto expoModulesProxyModule = std::make_shared<ExpoModulesProxySpec>(callInvoker, nativeModulesProxy);
16
+
17
+ runtime
18
+ .global()
19
+ .setProperty(runtime, "ExpoModulesProxy", jsi::Object::createFromHostObject(runtime, expoModulesProxyModule));
20
+ }
21
+
22
+ } // namespace expo
@@ -7,12 +7,7 @@
7
7
  #import <ExpoModulesCore/EXViewManagerAdapterClassesRegistry.h>
8
8
  #import <ExpoModulesCore/EXModuleRegistryHolderReactModule.h>
9
9
  #import <ExpoModulesCore/EXReactNativeEventEmitter.h>
10
- #if __has_include(<ExpoModulesCore/ExpoModulesCore-Swift.h>)
11
- // For cocoapods framework, the generated swift header will be inside ExpoModulesCore module
12
- #import <ExpoModulesCore/ExpoModulesCore-Swift.h>
13
- #else
14
- #import "ExpoModulesCore-Swift.h"
15
- #endif
10
+ #import <ExpoModulesCore/Swift.h>
16
11
 
17
12
  @interface EXModuleRegistryAdapter ()
18
13
 
@@ -12,6 +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
16
 
16
17
  NS_SWIFT_NAME(NativeModulesProxy)
17
18
  @interface EXNativeModulesProxy : NSObject <RCTBridgeModule>
@@ -21,4 +22,9 @@ NS_SWIFT_NAME(NativeModulesProxy)
21
22
  - (nonnull instancetype)init;
22
23
  - (nonnull instancetype)initWithModuleRegistry:(nullable EXModuleRegistry *)moduleRegistry;
23
24
 
25
+ - (void)callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNameOrKey arguments:(NSArray *)arguments resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject;
26
+ - (id)callMethodSync:(NSString *)moduleName methodName:(NSString *)methodName arguments:(NSArray *)arguments;
27
+
28
+ + (id<ModulesProviderObjCProtocol>)getExpoModulesProvider;
29
+
24
30
  @end
@@ -8,6 +8,8 @@
8
8
  #import <React/RCTModuleData.h>
9
9
  #import <React/RCTEventDispatcherProtocol.h>
10
10
 
11
+ #import <jsi/jsi.h>
12
+
11
13
  #import <ExpoModulesCore/EXNativeModulesProxy.h>
12
14
  #import <ExpoModulesCore/EXEventEmitter.h>
13
15
  #import <ExpoModulesCore/EXViewManager.h>
@@ -15,12 +17,8 @@
15
17
  #import <ExpoModulesCore/EXViewManagerAdapterClassesRegistry.h>
16
18
  #import <ExpoModulesCore/EXModuleRegistryProvider.h>
17
19
  #import <ExpoModulesCore/EXReactNativeEventEmitter.h>
18
- #if __has_include(<ExpoModulesCore/ExpoModulesCore-Swift.h>)
19
- // For cocoapods framework, the generated swift header will be inside ExpoModulesCore module
20
- #import <ExpoModulesCore/ExpoModulesCore-Swift.h>
21
- #else
22
- #import "ExpoModulesCore-Swift.h"
23
- #endif
20
+ #import <ExpoModulesCore/JSIInstaller.h>
21
+ #import <ExpoModulesCore/Swift.h>
24
22
 
25
23
  static const NSString *exportedMethodsNamesKeyPath = @"exportedMethods";
26
24
  static const NSString *viewManagersNamesKeyPath = @"viewManagersNames";
@@ -37,6 +35,12 @@ static const NSString *methodInfoArgumentsCountKey = @"argumentsCount";
37
35
 
38
36
  @end
39
37
 
38
+ @interface RCTBridge (JSIRuntime)
39
+
40
+ - (void *)runtime;
41
+
42
+ @end
43
+
40
44
  @interface RCTComponentData (EXNativeModulesProxy)
41
45
 
42
46
  - (instancetype)initWithManagerClass:(Class)managerClass bridge:(RCTBridge *)bridge eventDispatcher:(id<RCTEventDispatcherProtocol>) eventDispatcher; // available in RN 0.65+
@@ -68,7 +72,7 @@ RCT_EXPORT_MODULE(NativeUnimoduleProxy)
68
72
  {
69
73
  if (self = [super init]) {
70
74
  _exModuleRegistry = moduleRegistry != nil ? moduleRegistry : [[EXModuleRegistryProvider new] moduleRegistry];
71
- _swiftInteropBridge = [[SwiftInteropBridge alloc] initWithModulesProvider:[self getExpoModulesProvider] legacyModuleRegistry:_exModuleRegistry];
75
+ _swiftInteropBridge = [[SwiftInteropBridge alloc] initWithModulesProvider:[EXNativeModulesProxy getExpoModulesProvider] legacyModuleRegistry:_exModuleRegistry];
72
76
  _exportedMethodsKeys = [NSMutableDictionary dictionary];
73
77
  _exportedMethodsReverseKeys = [NSMutableDictionary dictionary];
74
78
  _ownsModuleRegistry = moduleRegistry == nil;
@@ -93,6 +97,9 @@ RCT_EXPORT_MODULE(NativeUnimoduleProxy)
93
97
 
94
98
  - (NSDictionary *)constantsToExport
95
99
  {
100
+ // Install the TurboModule implementation of the proxy.
101
+ [self installExpoTurboModules];
102
+
96
103
  NSMutableDictionary <NSString *, id> *exportedModulesConstants = [NSMutableDictionary dictionary];
97
104
  // Grab all the constants exported by modules
98
105
  for (EXExportedModule *exportedModule in [_exModuleRegistry getAllExportedModules]) {
@@ -121,7 +128,7 @@ RCT_EXPORT_MODULE(NativeUnimoduleProxy)
121
128
  }
122
129
 
123
130
  // Add entries from Swift modules
124
- [exportedMethodsNamesAccumulator addEntriesFromDictionary:[_swiftInteropBridge exportedMethodNames]];
131
+ [exportedMethodsNamesAccumulator addEntriesFromDictionary:[_swiftInteropBridge exportedFunctionNames]];
125
132
 
126
133
  // Also, add `viewManagersNames` for sanity check and testing purposes -- with names we know what managers to mock on UIManager
127
134
  NSArray<EXViewManager *> *viewManagers = [_exModuleRegistry getAllViewManagers];
@@ -151,7 +158,7 @@ RCT_EXPORT_MODULE(NativeUnimoduleProxy)
151
158
  RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNameOrKey arguments:(NSArray *)arguments resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
152
159
  {
153
160
  if ([_swiftInteropBridge hasModule:moduleName]) {
154
- [_swiftInteropBridge callMethod:methodNameOrKey onModule:moduleName withArgs:arguments resolve:resolve reject:reject];
161
+ [_swiftInteropBridge callFunction:methodNameOrKey onModule:moduleName withArgs:arguments resolve:resolve reject:reject];
155
162
  return;
156
163
  }
157
164
  EXExportedModule *module = [_exModuleRegistry getExportedModuleForName:moduleName];
@@ -186,19 +193,44 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
186
193
  });
187
194
  }
188
195
 
189
- #pragma mark - Privates
196
+ - (id)callMethodSync:(NSString *)moduleName methodName:(NSString *)methodName arguments:(NSArray *)arguments
197
+ {
198
+ if ([_swiftInteropBridge hasModule:moduleName]) {
199
+ return [_swiftInteropBridge callFunctionSync:methodName onModule:moduleName withArgs:arguments];
200
+ }
201
+ return (id)kCFNull;
202
+ }
203
+
204
+ #pragma mark - Statics
190
205
 
191
- - (id<ModulesProviderObjCProtocol>)getExpoModulesProvider
206
+ + (id<ModulesProviderObjCProtocol>)getExpoModulesProvider
192
207
  {
193
- Class generatedExpoModulesProvider = NSClassFromString(@"ExpoModulesProvider");
194
- // Checks if `ExpoModulesProvider` was generated
195
- if (generatedExpoModulesProvider) {
208
+ // Dynamically gets the modules provider class.
209
+ // NOTE: This needs to be versioned in Expo Go.
210
+ Class generatedExpoModulesProvider;
211
+
212
+ // [0] When ExpoModulesCore is built as separated framework/module,
213
+ // we should explicitly load main bundle's `ExpoModulesProvider` class.
214
+ NSString *bundleName = NSBundle.mainBundle.infoDictionary[@"CFBundleName"];
215
+ if (bundleName != nil) {
216
+ generatedExpoModulesProvider = NSClassFromString([NSString stringWithFormat:@"%@.ExpoModulesProvider", bundleName]);
217
+ if (generatedExpoModulesProvider != nil) {
218
+ return [generatedExpoModulesProvider new];
219
+ }
220
+ }
221
+
222
+ // [1] Fallback to load `ExpoModulesProvider` class from the current module.
223
+ generatedExpoModulesProvider = NSClassFromString(@"ExpoModulesProvider");
224
+ if (generatedExpoModulesProvider != nil) {
196
225
  return [generatedExpoModulesProvider new];
197
- } else {
198
- return [ModulesProvider new];
199
226
  }
227
+
228
+ // [2] Fallback to load `ModulesProvider` if `ExpoModulesProvider` was not generated
229
+ return [ModulesProvider new];
200
230
  }
201
231
 
232
+ #pragma mark - Privates
233
+
202
234
  - (void)registerExpoModulesInBridge:(RCTBridge *)bridge
203
235
  {
204
236
  // Registering expo modules in bridge is needed only when the proxy module owns the registry
@@ -255,8 +287,10 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
255
287
  // components in UIManager — we need to register them on our own.
256
288
  [self registerComponentDataForModuleClasses:additionalModuleClasses inBridge:bridge];
257
289
 
258
- // Get the newly created instance of `EXReactEventEmitter` bridge module and register it in expo modules registry.
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.
259
292
  EXReactNativeEventEmitter *eventEmitter = [bridge moduleForClass:[EXReactNativeEventEmitter class]];
293
+ [eventEmitter setSwiftInteropBridge:_swiftInteropBridge];
260
294
  [_exModuleRegistry registerInternalModule:eventEmitter];
261
295
 
262
296
  // Let the modules consume the registry :)
@@ -345,4 +379,16 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
345
379
  }
346
380
  }
347
381
 
382
+ /**
383
+ Installs expo modules in JSI runtime.
384
+ */
385
+ - (void)installExpoTurboModules
386
+ {
387
+ facebook::jsi::Runtime *runtime = [_bridge respondsToSelector:@selector(runtime)] ? reinterpret_cast<facebook::jsi::Runtime *>(_bridge.runtime) : NULL;
388
+
389
+ if (runtime) {
390
+ expo::installRuntimeObjects(*runtime, _bridge.jsCallInvoker, self);
391
+ }
392
+ }
393
+
348
394
  @end
@@ -0,0 +1,16 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ #import <React/RCTBridgeDelegate.h>
4
+
5
+ NS_ASSUME_NONNULL_BEGIN
6
+
7
+ @interface EXRCTBridgeDelegateInterceptor : NSObject<RCTBridgeDelegate>
8
+
9
+ @property (nonatomic, weak) id<RCTBridgeDelegate> bridgeDelegate;
10
+ @property (nonatomic, weak) id<RCTBridgeDelegate> interceptor;
11
+
12
+ - (instancetype)initWithBridgeDelegate:(id<RCTBridgeDelegate>)bridgeDelegate interceptor:(id<RCTBridgeDelegate>)interceptor;
13
+
14
+ @end
15
+
16
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,49 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoModulesCore/EXRCTBridgeDelegateInterceptor.h>
4
+
5
+ @implementation EXRCTBridgeDelegateInterceptor
6
+
7
+ - (instancetype)initWithBridgeDelegate:(id<RCTBridgeDelegate>)bridgeDelegate interceptor:(id<RCTBridgeDelegate>)interceptor
8
+ {
9
+ if (self = [super init]) {
10
+ self.bridgeDelegate = bridgeDelegate;
11
+ self.interceptor = interceptor;
12
+ }
13
+ return self;
14
+ }
15
+
16
+ - (BOOL)conformsToProtocol:(Protocol *)protocol
17
+ {
18
+ return [self.bridgeDelegate conformsToProtocol:protocol];
19
+ }
20
+
21
+ - (id)forwardingTargetForSelector:(SEL)selector
22
+ {
23
+ if ([self isInterceptedSelector:selector]) {
24
+ return self;
25
+ }
26
+ return self.bridgeDelegate;
27
+ }
28
+
29
+ - (BOOL)respondsToSelector:(SEL)selector
30
+ {
31
+ if ([self isInterceptedSelector:selector]) {
32
+ return YES;
33
+ }
34
+ return [self.bridgeDelegate respondsToSelector:selector];
35
+ }
36
+
37
+ - (BOOL)isInterceptedSelector:(SEL)selector
38
+ {
39
+ if ([self.interceptor respondsToSelector:selector]) {
40
+ return YES;
41
+ }
42
+ return NO;
43
+ }
44
+
45
+ - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
46
+ return [self.interceptor sourceURLForBridge:bridge];
47
+ }
48
+
49
+ @end
@@ -0,0 +1,18 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoModulesCore/Swift.h>
4
+
5
+ NS_ASSUME_NONNULL_BEGIN
6
+
7
+ /**
8
+ Internal `EXReactDelegateWrapper` interface for the designated initializer with `ExpoReactDelegate`.
9
+ Since `ExpoReactDelegate` implements in swift and requires the generated `ExpoModulesCore-Swift.h` header,
10
+ this header file should ONLY be imported from *.m or *.mm files.
11
+ */
12
+ @interface EXReactDelegateWrapper(Private)
13
+
14
+ - (instancetype)initWithExpoReactDelegate:(ExpoReactDelegate *)expoReactDelegate;
15
+
16
+ @end
17
+
18
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,25 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ #import <UIKit/UIKit.h>
4
+ #import <React/RCTBridge.h>
5
+ #import <React/RCTRootView.h>
6
+
7
+ NS_ASSUME_NONNULL_BEGIN
8
+
9
+ /**
10
+ A wrapper of `ExpoReactDelegate` for Objective-C bindings.
11
+ */
12
+ @interface EXReactDelegateWrapper : NSObject
13
+
14
+ - (RCTBridge *)createBridgeWithDelegate:(id<RCTBridgeDelegate>)delegate
15
+ launchOptions:(nullable NSDictionary *)launchOptions;
16
+
17
+ - (RCTRootView *)createRootViewWithBridge:(RCTBridge *)bridge
18
+ moduleName:(NSString *)moduleName
19
+ initialProperties:(nullable NSDictionary *)initialProperties;
20
+
21
+ - (UIViewController *)createRootViewController;
22
+
23
+ @end
24
+
25
+ NS_ASSUME_NONNULL_END