expo-modules-core 0.4.6 → 0.6.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.
- package/CHANGELOG.md +39 -0
- package/README.md +6 -6
- package/android/build.gradle +30 -2
- package/android/src/main/java/expo/modules/adapters/react/ModuleRegistryAdapter.java +27 -5
- package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +49 -5
- package/android/src/main/java/expo/modules/core/BasePackage.java +6 -0
- package/android/src/main/java/expo/modules/core/ModulePriorities.kt +25 -0
- package/android/src/main/java/expo/modules/core/interfaces/ActivityEventListener.java +3 -1
- package/android/src/main/java/expo/modules/core/interfaces/ApplicationLifecycleListener.java +10 -0
- package/android/src/main/java/expo/modules/core/interfaces/Package.java +4 -0
- package/android/src/main/java/expo/modules/core/interfaces/ReactActivityHandler.java +21 -0
- package/android/src/main/java/expo/modules/core/interfaces/ReactActivityLifecycleListener.java +14 -0
- package/android/src/main/java/expo/modules/core/interfaces/ReactNativeHostHandler.java +70 -0
- package/android/src/main/java/expo/modules/core/utilities/KotlinUtilities.kt +23 -0
- package/android/src/main/java/expo/modules/kotlin/AppContext.kt +166 -0
- package/android/src/main/java/expo/modules/kotlin/DynamicExtenstions.kt +9 -0
- package/android/src/main/java/expo/modules/kotlin/ExpoModulesHelper.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/KPromiseWrapper.kt +24 -0
- package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +98 -0
- package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +41 -0
- package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +56 -0
- package/android/src/main/java/expo/modules/kotlin/ModulesProvider.kt +7 -0
- package/android/src/main/java/expo/modules/kotlin/Promise.kt +13 -0
- package/android/src/main/java/expo/modules/kotlin/ReactLifecycleDelegate.kt +39 -0
- package/android/src/main/java/expo/modules/kotlin/ReadableArrayIterator.kt +14 -0
- package/android/src/main/java/expo/modules/kotlin/ReadableTypeExtensions.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/allocators/ObjectConstructor.kt +5 -0
- package/android/src/main/java/expo/modules/kotlin/allocators/ObjectConstructorFactory.kt +31 -0
- package/android/src/main/java/expo/modules/kotlin/allocators/UnsafeAllocator.kt +49 -0
- package/android/src/main/java/expo/modules/kotlin/events/EventListener.kt +39 -0
- package/android/src/main/java/expo/modules/kotlin/events/EventName.kt +31 -0
- package/android/src/main/java/expo/modules/kotlin/events/EventsDefinition.kt +3 -0
- package/android/src/main/java/expo/modules/kotlin/events/KEventEmitterWrapper.kt +26 -0
- package/android/src/main/java/expo/modules/kotlin/events/OnActivityResultPayload.kt +8 -0
- package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +70 -0
- package/android/src/main/java/expo/modules/kotlin/methods/AnyMethod.kt +50 -0
- package/android/src/main/java/expo/modules/kotlin/methods/Method.kt +14 -0
- package/android/src/main/java/expo/modules/kotlin/methods/PromiseMethod.kt +15 -0
- package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +24 -0
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +227 -0
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +16 -0
- package/android/src/main/java/expo/modules/kotlin/records/Field.kt +5 -0
- package/android/src/main/java/expo/modules/kotlin/records/Record.kt +3 -0
- package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +55 -0
- package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +14 -0
- package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +44 -0
- package/android/src/main/java/expo/modules/kotlin/types/BasicTypeConverters.kt +60 -0
- package/android/src/main/java/expo/modules/kotlin/types/EnumTypeConverter.kt +84 -0
- package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +25 -0
- package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +39 -0
- package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +28 -0
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +19 -0
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +107 -0
- package/android/src/main/java/expo/modules/kotlin/views/AnyViewProp.kt +10 -0
- package/android/src/main/java/expo/modules/kotlin/views/ConcreteViewProp.kt +17 -0
- package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +22 -0
- package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +21 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +41 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +40 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +21 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewWrapperDelegateHolder.kt +5 -0
- package/build/NativeModulesProxy.native.d.ts +4 -0
- package/build/NativeModulesProxy.native.js +14 -1
- package/build/NativeModulesProxy.native.js.map +1 -1
- package/build/NativeModulesProxy.types.d.ts +3 -0
- package/build/NativeModulesProxy.types.js.map +1 -1
- package/build/NativeViewManagerAdapter.native.js +1 -1
- package/build/NativeViewManagerAdapter.native.js.map +1 -1
- package/ios/AppDelegates/EXAppDelegateWrapper.h +19 -0
- package/ios/AppDelegates/EXAppDelegateWrapper.m +45 -0
- package/ios/AppDelegates/EXAppDelegatesLoader.h +15 -0
- package/ios/AppDelegates/EXAppDelegatesLoader.m +30 -0
- package/ios/AppDelegates/EXLegacyAppDelegateWrapper.h +16 -0
- package/ios/{EXAppDelegateWrapper.m → AppDelegates/EXLegacyAppDelegateWrapper.m} +2 -2
- package/ios/AppDelegates/ExpoAppDelegate.swift +282 -0
- package/ios/AppDelegates/ExpoAppDelegateSubscriber.swift +24 -0
- package/ios/EXAppDefines.h +26 -0
- package/ios/EXAppDefines.m +61 -0
- package/ios/ExpoModulesCore.podspec +8 -3
- package/ios/JSI/ExpoModulesProxySpec.h +24 -0
- package/ios/JSI/ExpoModulesProxySpec.mm +135 -0
- package/ios/JSI/JSIConversions.h +42 -0
- package/ios/JSI/JSIConversions.mm +164 -0
- package/ios/JSI/JSIInstaller.h +19 -0
- package/ios/JSI/JSIInstaller.mm +22 -0
- package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +1 -6
- package/ios/NativeModulesProxy/EXNativeModulesProxy.h +6 -0
- package/ios/NativeModulesProxy/{EXNativeModulesProxy.m → EXNativeModulesProxy.mm} +91 -18
- package/ios/ReactDelegates/EXRCTBridgeDelegateInterceptor.h +16 -0
- package/ios/ReactDelegates/EXRCTBridgeDelegateInterceptor.m +49 -0
- package/ios/ReactDelegates/EXReactDelegateWrapper+Private.h +18 -0
- package/ios/ReactDelegates/EXReactDelegateWrapper.h +25 -0
- package/ios/ReactDelegates/EXReactDelegateWrapper.m +40 -0
- package/ios/ReactDelegates/ExpoReactDelegate.swift +37 -0
- package/ios/ReactDelegates/ExpoReactDelegateHandler.swift +52 -0
- package/ios/ReactDelegates/ModulePriorities.swift +20 -0
- package/ios/Services/EXReactNativeEventEmitter.h +6 -0
- package/ios/Services/EXReactNativeEventEmitter.m +15 -0
- package/ios/Swift/AppContext.swift +14 -1
- package/ios/Swift/Arguments/AnyArgument.swift +14 -0
- package/ios/Swift/Arguments/AnyArgumentType.swift +13 -0
- package/ios/Swift/Arguments/ArgumentType.swift +24 -0
- package/ios/Swift/Arguments/ConvertibleArgument.swift +15 -0
- package/ios/Swift/Arguments/Convertibles.swift +107 -0
- package/ios/Swift/Arguments/Types/ArrayArgumentType.swift +42 -0
- package/ios/Swift/Arguments/Types/ConvertibleArgumentType.swift +16 -0
- package/ios/Swift/Arguments/Types/EnumArgumentType.swift +105 -0
- package/ios/Swift/Arguments/Types/OptionalArgumentType.swift +49 -0
- package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +15 -0
- package/ios/Swift/Arguments/Types/RawArgumentType.swift +25 -0
- package/ios/Swift/Conversions.swift +199 -7
- package/ios/Swift/EventListener.swift +37 -5
- package/ios/Swift/Functions/AnyFunction.swift +42 -0
- package/ios/Swift/{Methods/ConcreteMethod.swift → Functions/ConcreteFunction.swift} +32 -34
- package/ios/Swift/ModuleHolder.swift +86 -20
- package/ios/Swift/ModuleRegistry.swift +19 -8
- package/ios/Swift/Modules/AnyModule.swift +8 -8
- package/ios/Swift/Modules/Module.swift +11 -0
- package/ios/Swift/Modules/ModuleDefinition.swift +55 -15
- package/ios/Swift/Modules/ModuleDefinitionBuilder.swift +1 -1
- package/ios/Swift/Modules/ModuleDefinitionComponents.swift +149 -54
- package/ios/Swift/ModulesProvider.swift +19 -0
- package/ios/Swift/Promise.swift +1 -1
- package/ios/Swift/Records/Field.swift +1 -1
- package/ios/Swift/Records/Record.swift +8 -1
- package/ios/Swift/SwiftInteropBridge.swift +46 -17
- package/ios/Swift/Views/AnyViewProp.swift +2 -2
- package/ios/Swift/Views/ConcreteViewProp.swift +37 -10
- package/ios/Swift/Views/ViewModuleWrapper.swift +9 -4
- package/ios/Swift.h +9 -0
- package/ios/Tests/ArgumentTypeSpec.swift +145 -0
- package/ios/Tests/ConstantsSpec.swift +36 -0
- package/ios/Tests/ConvertiblesSpec.swift +265 -0
- package/ios/Tests/EXAppDefinesTest.m +99 -0
- package/ios/Tests/{MethodSpec.swift → FunctionSpec.swift} +69 -54
- package/ios/Tests/FunctionWithConvertiblesSpec.swift +66 -0
- package/ios/Tests/Mocks/ModuleMocks.swift +21 -7
- package/ios/Tests/ModuleEventListenersSpec.swift +17 -16
- package/ios/Tests/ModuleRegistrySpec.swift +4 -7
- package/package.json +3 -3
- package/src/NativeModulesProxy.native.ts +22 -2
- package/src/NativeModulesProxy.types.ts +8 -0
- package/src/NativeViewManagerAdapter.native.tsx +1 -1
- package/android/src/main/java/expo/modules/core/interfaces/ApplicationLifecycleListener.kt +0 -9
- package/android/src/main/java/expo/modules/core/interfaces/ReactActivityLifecycleListener.kt +0 -11
- package/android/src/main/java/expo/modules/core/interfaces/ReactNativeHostHandler.kt +0 -51
- package/ios/EXAppDelegateWrapper.h +0 -13
- package/ios/Swift/Methods/AnyArgumentType.swift +0 -48
- package/ios/Swift/Methods/AnyMethod.swift +0 -31
- 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
|
-
#
|
|
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
|
-
#
|
|
19
|
-
|
|
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";
|
|
@@ -32,10 +30,17 @@ static const NSString *methodInfoArgumentsCountKey = @"argumentsCount";
|
|
|
32
30
|
|
|
33
31
|
@interface RCTBridge (RegisterAdditionalModuleClasses)
|
|
34
32
|
|
|
33
|
+
- (NSArray<RCTModuleData *> *)registerModulesForClasses:(NSArray<Class> *)moduleClasses;
|
|
35
34
|
- (void)registerAdditionalModuleClasses:(NSArray<Class> *)modules;
|
|
36
35
|
|
|
37
36
|
@end
|
|
38
37
|
|
|
38
|
+
@interface RCTBridge (JSIRuntime)
|
|
39
|
+
|
|
40
|
+
- (void *)runtime;
|
|
41
|
+
|
|
42
|
+
@end
|
|
43
|
+
|
|
39
44
|
@interface RCTComponentData (EXNativeModulesProxy)
|
|
40
45
|
|
|
41
46
|
- (instancetype)initWithManagerClass:(Class)managerClass bridge:(RCTBridge *)bridge eventDispatcher:(id<RCTEventDispatcherProtocol>) eventDispatcher; // available in RN 0.65+
|
|
@@ -67,7 +72,7 @@ RCT_EXPORT_MODULE(NativeUnimoduleProxy)
|
|
|
67
72
|
{
|
|
68
73
|
if (self = [super init]) {
|
|
69
74
|
_exModuleRegistry = moduleRegistry != nil ? moduleRegistry : [[EXModuleRegistryProvider new] moduleRegistry];
|
|
70
|
-
_swiftInteropBridge = [[SwiftInteropBridge alloc] initWithModulesProvider:[
|
|
75
|
+
_swiftInteropBridge = [[SwiftInteropBridge alloc] initWithModulesProvider:[EXNativeModulesProxy getExpoModulesProvider] legacyModuleRegistry:_exModuleRegistry];
|
|
71
76
|
_exportedMethodsKeys = [NSMutableDictionary dictionary];
|
|
72
77
|
_exportedMethodsReverseKeys = [NSMutableDictionary dictionary];
|
|
73
78
|
_ownsModuleRegistry = moduleRegistry == nil;
|
|
@@ -92,6 +97,9 @@ RCT_EXPORT_MODULE(NativeUnimoduleProxy)
|
|
|
92
97
|
|
|
93
98
|
- (NSDictionary *)constantsToExport
|
|
94
99
|
{
|
|
100
|
+
// Install the TurboModule implementation of the proxy.
|
|
101
|
+
[self installExpoTurboModules];
|
|
102
|
+
|
|
95
103
|
NSMutableDictionary <NSString *, id> *exportedModulesConstants = [NSMutableDictionary dictionary];
|
|
96
104
|
// Grab all the constants exported by modules
|
|
97
105
|
for (EXExportedModule *exportedModule in [_exModuleRegistry getAllExportedModules]) {
|
|
@@ -120,7 +128,7 @@ RCT_EXPORT_MODULE(NativeUnimoduleProxy)
|
|
|
120
128
|
}
|
|
121
129
|
|
|
122
130
|
// Add entries from Swift modules
|
|
123
|
-
[exportedMethodsNamesAccumulator addEntriesFromDictionary:[_swiftInteropBridge
|
|
131
|
+
[exportedMethodsNamesAccumulator addEntriesFromDictionary:[_swiftInteropBridge exportedFunctionNames]];
|
|
124
132
|
|
|
125
133
|
// Also, add `viewManagersNames` for sanity check and testing purposes -- with names we know what managers to mock on UIManager
|
|
126
134
|
NSArray<EXViewManager *> *viewManagers = [_exModuleRegistry getAllViewManagers];
|
|
@@ -150,7 +158,7 @@ RCT_EXPORT_MODULE(NativeUnimoduleProxy)
|
|
|
150
158
|
RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNameOrKey arguments:(NSArray *)arguments resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
151
159
|
{
|
|
152
160
|
if ([_swiftInteropBridge hasModule:moduleName]) {
|
|
153
|
-
[_swiftInteropBridge
|
|
161
|
+
[_swiftInteropBridge callFunction:methodNameOrKey onModule:moduleName withArgs:arguments resolve:resolve reject:reject];
|
|
154
162
|
return;
|
|
155
163
|
}
|
|
156
164
|
EXExportedModule *module = [_exModuleRegistry getExportedModuleForName:moduleName];
|
|
@@ -185,19 +193,44 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
|
|
|
185
193
|
});
|
|
186
194
|
}
|
|
187
195
|
|
|
188
|
-
|
|
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
|
|
189
205
|
|
|
190
|
-
|
|
206
|
+
+ (id<ModulesProviderObjCProtocol>)getExpoModulesProvider
|
|
191
207
|
{
|
|
192
|
-
|
|
193
|
-
//
|
|
194
|
-
|
|
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) {
|
|
195
225
|
return [generatedExpoModulesProvider new];
|
|
196
|
-
} else {
|
|
197
|
-
return [ModulesProvider new];
|
|
198
226
|
}
|
|
227
|
+
|
|
228
|
+
// [2] Fallback to load `ModulesProvider` if `ExpoModulesProvider` was not generated
|
|
229
|
+
return [ModulesProvider new];
|
|
199
230
|
}
|
|
200
231
|
|
|
232
|
+
#pragma mark - Privates
|
|
233
|
+
|
|
201
234
|
- (void)registerExpoModulesInBridge:(RCTBridge *)bridge
|
|
202
235
|
{
|
|
203
236
|
// Registering expo modules in bridge is needed only when the proxy module owns the registry
|
|
@@ -248,14 +281,16 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
|
|
|
248
281
|
[bridge uiManager];
|
|
249
282
|
|
|
250
283
|
// Register the view managers as additional modules.
|
|
251
|
-
[
|
|
284
|
+
[self registerAdditionalModuleClasses:additionalModuleClasses inBridge:bridge];
|
|
252
285
|
|
|
253
286
|
// Bridge's `registerAdditionalModuleClasses:` method doesn't register
|
|
254
287
|
// components in UIManager — we need to register them on our own.
|
|
255
288
|
[self registerComponentDataForModuleClasses:additionalModuleClasses inBridge:bridge];
|
|
256
289
|
|
|
257
|
-
// Get the newly created instance of `EXReactEventEmitter` bridge module
|
|
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.
|
|
258
292
|
EXReactNativeEventEmitter *eventEmitter = [bridge moduleForClass:[EXReactNativeEventEmitter class]];
|
|
293
|
+
[eventEmitter setSwiftInteropBridge:_swiftInteropBridge];
|
|
259
294
|
[_exModuleRegistry registerInternalModule:eventEmitter];
|
|
260
295
|
|
|
261
296
|
// Let the modules consume the registry :)
|
|
@@ -263,6 +298,32 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
|
|
|
263
298
|
[_exModuleRegistry initialize];
|
|
264
299
|
}
|
|
265
300
|
|
|
301
|
+
- (void)registerAdditionalModuleClasses:(NSArray<Class> *)moduleClasses inBridge:(RCTBridge *)bridge
|
|
302
|
+
{
|
|
303
|
+
// In remote debugging mode, i.e. executorClass is `RCTWebSocketExecutor`,
|
|
304
|
+
// there is a deadlock issue in `registerAdditionalModuleClasses:` and causes app freezed.
|
|
305
|
+
// - The JS thread acquired the `RCTCxxBridge._moduleRegistryLock` lock in `RCTCxxBridge._initializeBridgeLocked`
|
|
306
|
+
// = it further goes into RCTObjcExecutor and tries to get module config from main thread
|
|
307
|
+
// - The main thread is pending in `RCTCxxBridge.registerAdditionalModuleClasses` where trying to acquire the same lock.
|
|
308
|
+
// To workaround the deadlock, we tend to use the non-locked registration and mutate the bridge internal module data.
|
|
309
|
+
// Since JS thread in this situation is waiting for main thread, it's safe to mutate module data without lock.
|
|
310
|
+
// The only risk should be the internal `_moduleRegistryCreated` flag without lock protection.
|
|
311
|
+
// As we just workaround in `RCTWebSocketExecutor` case, the risk of `_moduleRegistryCreated` race condition should be lower.
|
|
312
|
+
//
|
|
313
|
+
// Learn more about the non-locked initialization:
|
|
314
|
+
// https://github.com/facebook/react-native/blob/757bb75fbf837714725d7b2af62149e8e2a7ee51/React/CxxBridge/RCTCxxBridge.mm#L922-L935
|
|
315
|
+
// See the `_moduleRegistryCreated` false case
|
|
316
|
+
if ([NSStringFromClass([bridge executorClass]) isEqualToString:@"RCTWebSocketExecutor"]) {
|
|
317
|
+
NSNumber *moduleRegistryCreated = [bridge valueForKey:@"_moduleRegistryCreated"];
|
|
318
|
+
if (![moduleRegistryCreated boolValue]) {
|
|
319
|
+
[bridge registerModulesForClasses:moduleClasses];
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
[bridge registerAdditionalModuleClasses:moduleClasses];
|
|
325
|
+
}
|
|
326
|
+
|
|
266
327
|
- (void)registerComponentDataForModuleClasses:(NSArray<Class> *)moduleClasses inBridge:(RCTBridge *)bridge
|
|
267
328
|
{
|
|
268
329
|
// Hacky way to get a dictionary with `RCTComponentData` from UIManager.
|
|
@@ -318,4 +379,16 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
|
|
|
318
379
|
}
|
|
319
380
|
}
|
|
320
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
|
+
|
|
321
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
|