expo-modules-core 0.4.8 → 0.5.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 +14 -1
- 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/Package.java +4 -0
- package/android/src/main/java/expo/modules/core/interfaces/ReactActivityHandler.kt +18 -0
- package/android/src/main/java/expo/modules/core/interfaces/ReactNativeHostHandler.kt +14 -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 +23 -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 +36 -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/ios/AppDelegates/EXAppDelegateWrapper.h +16 -0
- package/ios/AppDelegates/EXAppDelegateWrapper.m +42 -0
- package/ios/AppDelegates/EXAppDelegatesLoader.h +15 -0
- package/ios/AppDelegates/EXAppDelegatesLoader.m +29 -0
- package/ios/AppDelegates/EXLegacyAppDelegateWrapper.h +16 -0
- package/ios/{EXAppDelegateWrapper.m → AppDelegates/EXLegacyAppDelegateWrapper.m} +2 -2
- package/ios/AppDelegates/ExpoAppDelegate.swift +264 -0
- package/ios/AppDelegates/ExpoAppDelegateSubscriber.swift +24 -0
- package/ios/ExpoModulesCore.podspec +7 -2
- 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} +45 -12
- 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 +93 -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 +75 -20
- package/ios/Swift/ModuleRegistry.swift +19 -8
- package/ios/Swift/Modules/AnyModule.swift +8 -8
- package/ios/Swift/Modules/Module.swift +7 -0
- package/ios/Swift/Modules/ModuleDefinition.swift +52 -8
- package/ios/Swift/Modules/ModuleDefinitionBuilder.swift +1 -1
- package/ios/Swift/Modules/ModuleDefinitionComponents.swift +140 -52
- package/ios/Swift/ModulesProvider.swift +9 -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 +45 -16
- 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/ConvertiblesSpec.swift +231 -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/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
|
@@ -3,20 +3,19 @@ import Nimble
|
|
|
3
3
|
|
|
4
4
|
@testable import ExpoModulesCore
|
|
5
5
|
|
|
6
|
-
class
|
|
6
|
+
class FunctionSpec: QuickSpec {
|
|
7
7
|
override func spec() {
|
|
8
8
|
let appContext = AppContext()
|
|
9
|
-
let
|
|
9
|
+
let functionName = "test function name"
|
|
10
10
|
|
|
11
|
-
func
|
|
11
|
+
func testFunctionReturning<T: Equatable>(value returnValue: T) {
|
|
12
12
|
waitUntil { done in
|
|
13
|
-
|
|
14
|
-
$0.
|
|
13
|
+
mockModuleHolder(appContext) {
|
|
14
|
+
$0.function(functionName) {
|
|
15
15
|
return returnValue
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
ModuleHolder(module: module).call(method: methodName, args: []) { value, error in
|
|
18
|
+
.call(function: functionName, args: []) { value, error in
|
|
20
19
|
expect(value).notTo(beNil())
|
|
21
20
|
expect(value).to(beAKindOf(T.self))
|
|
22
21
|
expect(value as? T).to(equal(returnValue))
|
|
@@ -27,34 +26,56 @@ class MethodSpec: QuickSpec {
|
|
|
27
26
|
|
|
28
27
|
it("is called") {
|
|
29
28
|
waitUntil { done in
|
|
30
|
-
|
|
31
|
-
$0.
|
|
29
|
+
mockModuleHolder(appContext) {
|
|
30
|
+
$0.function(functionName) {
|
|
32
31
|
done()
|
|
33
32
|
}
|
|
34
33
|
}
|
|
35
|
-
|
|
34
|
+
.call(function: functionName, args: [])
|
|
36
35
|
}
|
|
37
36
|
}
|
|
38
37
|
|
|
39
38
|
it("returns bool values") {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
testFunctionReturning(value: true)
|
|
40
|
+
testFunctionReturning(value: false)
|
|
41
|
+
testFunctionReturning(value: [true, false])
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
it("returns int values") {
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
testFunctionReturning(value: 1234)
|
|
46
|
+
testFunctionReturning(value: [2, 1, 3, 7])
|
|
48
47
|
}
|
|
49
48
|
|
|
50
49
|
it("returns double values") {
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
testFunctionReturning(value: 3.14)
|
|
51
|
+
testFunctionReturning(value: [0, 1.1, 2.2])
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
it("returns string values") {
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
testFunctionReturning(value: "a string")
|
|
56
|
+
testFunctionReturning(value: ["expo", "modules", "core"])
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
it("is called with nil value") {
|
|
60
|
+
let str: String? = nil
|
|
61
|
+
|
|
62
|
+
mockModuleHolder(appContext) {
|
|
63
|
+
$0.function(functionName) { (a: String?) in
|
|
64
|
+
expect(a == nil) == true
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
.callSync(function: functionName, args: [str as Any])
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
it("is called with an array of arrays") {
|
|
71
|
+
let array: [[String]] = [["expo"]]
|
|
72
|
+
|
|
73
|
+
mockModuleHolder(appContext) {
|
|
74
|
+
$0.function(functionName) { (a: [[String]]) in
|
|
75
|
+
expect(a.first!.first) == array.first!.first
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
.callSync(function: functionName, args: [array])
|
|
58
79
|
}
|
|
59
80
|
|
|
60
81
|
describe("converting dicts to records") {
|
|
@@ -69,14 +90,13 @@ class MethodSpec: QuickSpec {
|
|
|
69
90
|
]
|
|
70
91
|
|
|
71
92
|
it("converts to simple record when passed as an argument") {
|
|
72
|
-
let module = CustomModule(appContext: appContext) {
|
|
73
|
-
$0.method(methodName) { (a: TestRecord) in
|
|
74
|
-
return a.property
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
93
|
waitUntil { done in
|
|
79
|
-
|
|
94
|
+
mockModuleHolder(appContext) {
|
|
95
|
+
$0.function(functionName) { (a: TestRecord) in
|
|
96
|
+
return a.property
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
.call(function: functionName, args: [dict]) { value, error in
|
|
80
100
|
expect(value).notTo(beNil())
|
|
81
101
|
expect(value).to(beAKindOf(String.self))
|
|
82
102
|
expect(value).to(be(dict["property"]))
|
|
@@ -86,14 +106,13 @@ class MethodSpec: QuickSpec {
|
|
|
86
106
|
}
|
|
87
107
|
|
|
88
108
|
it("converts to record with custom key") {
|
|
89
|
-
let module = CustomModule(appContext: appContext) {
|
|
90
|
-
$0.method(methodName) { (a: TestRecord) in
|
|
91
|
-
return a.customKeyProperty
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
109
|
waitUntil { done in
|
|
96
|
-
|
|
110
|
+
mockModuleHolder(appContext) {
|
|
111
|
+
$0.function(functionName) { (a: TestRecord) in
|
|
112
|
+
return a.customKeyProperty
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
.call(function: functionName, args: [dict]) { value, error in
|
|
97
116
|
expect(value).notTo(beNil())
|
|
98
117
|
expect(value).to(beAKindOf(String.self))
|
|
99
118
|
expect(value).to(be(dict["propertyWithCustomKey"]))
|
|
@@ -103,14 +122,13 @@ class MethodSpec: QuickSpec {
|
|
|
103
122
|
}
|
|
104
123
|
|
|
105
124
|
it("returns the record back") {
|
|
106
|
-
let module = CustomModule(appContext: appContext) {
|
|
107
|
-
$0.method(methodName) { (a: TestRecord) in
|
|
108
|
-
return a.toDictionary()
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
125
|
waitUntil { done in
|
|
113
|
-
|
|
126
|
+
mockModuleHolder(appContext) {
|
|
127
|
+
$0.function(functionName) { (a: TestRecord) in
|
|
128
|
+
return a.toDictionary()
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
.call(function: functionName, args: [dict]) { value, error in
|
|
114
132
|
expect(value).notTo(beNil())
|
|
115
133
|
expect(value).to(beAKindOf(Record.Dict.self))
|
|
116
134
|
|
|
@@ -126,14 +144,13 @@ class MethodSpec: QuickSpec {
|
|
|
126
144
|
|
|
127
145
|
it("throws when called with more arguments than expected") {
|
|
128
146
|
waitUntil { done in
|
|
129
|
-
|
|
130
|
-
$0.
|
|
147
|
+
mockModuleHolder(appContext) {
|
|
148
|
+
$0.function(functionName) { (a: Int) in
|
|
131
149
|
return "something"
|
|
132
150
|
}
|
|
133
151
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
ModuleHolder(module: module).call(method: methodName, args: [1, 2]) { value, error in
|
|
152
|
+
// Function expects one argument, let's give it more.
|
|
153
|
+
.call(function: functionName, args: [1, 2]) { value, error in
|
|
137
154
|
expect(error).notTo(beNil())
|
|
138
155
|
expect(error).to(beAKindOf(InvalidArgsNumberError.self))
|
|
139
156
|
expect(error?.code).to(equal("ERR_INVALID_ARGS_NUMBER"))
|
|
@@ -145,19 +162,17 @@ class MethodSpec: QuickSpec {
|
|
|
145
162
|
|
|
146
163
|
it("throws when called with arguments of incompatible types") {
|
|
147
164
|
waitUntil { done in
|
|
148
|
-
|
|
149
|
-
$0.
|
|
165
|
+
mockModuleHolder(appContext) {
|
|
166
|
+
$0.function(functionName) { (a: String) in
|
|
150
167
|
return "something"
|
|
151
168
|
}
|
|
152
169
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
ModuleHolder(module: module).call(method: methodName, args: [1]) { value, error in
|
|
170
|
+
// Function expects a string, let's give it a number.
|
|
171
|
+
.call(function: functionName, args: [1]) { value, error in
|
|
156
172
|
expect(error).notTo(beNil())
|
|
157
|
-
expect(error).to(beAKindOf(
|
|
158
|
-
expect(error?.code).to(equal("
|
|
159
|
-
|
|
160
|
-
// expect(error?.description).to(equal(IncompatibleArgTypeError(argument: 1, atIndex: 0, desiredType: String.self).description))
|
|
173
|
+
expect(error).to(beAKindOf(Conversions.CastingError<String>.self))
|
|
174
|
+
expect(error?.code).to(equal("ERR_CASTING_FAILED"))
|
|
175
|
+
expect(error?.description).to(equal(Conversions.CastingError<String>(value: 1).description))
|
|
161
176
|
done()
|
|
162
177
|
}
|
|
163
178
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Copyright 2018-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
import CoreGraphics
|
|
4
|
+
import Quick
|
|
5
|
+
import Nimble
|
|
6
|
+
|
|
7
|
+
@testable import ExpoModulesCore
|
|
8
|
+
|
|
9
|
+
class FunctionWithConvertiblesSpec: QuickSpec {
|
|
10
|
+
override func spec() {
|
|
11
|
+
let appContext = AppContext()
|
|
12
|
+
let functionName = "function"
|
|
13
|
+
|
|
14
|
+
it("converts arguments to CoreGraphics types") {
|
|
15
|
+
let x = 18.3
|
|
16
|
+
let y = -4.1
|
|
17
|
+
let width = 734.6
|
|
18
|
+
let height = 592.1
|
|
19
|
+
|
|
20
|
+
mockModuleHolder(appContext) {
|
|
21
|
+
$0.function(functionName) { (point: CGPoint, size: CGSize, vector: CGVector, rect: CGRect) in
|
|
22
|
+
expect(point.x) == x
|
|
23
|
+
expect(point.y) == y
|
|
24
|
+
expect(size.width) == width
|
|
25
|
+
expect(size.height) == height
|
|
26
|
+
expect(vector.dx) == x
|
|
27
|
+
expect(vector.dy) == y
|
|
28
|
+
expect(rect.origin.x) == x
|
|
29
|
+
expect(rect.origin.y) == y
|
|
30
|
+
expect(rect.width) == width
|
|
31
|
+
expect(rect.height) == height
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
.callSync(function: functionName, args: [
|
|
35
|
+
[x, y], // point
|
|
36
|
+
["width": width, "height": height], // size
|
|
37
|
+
["dx": x, "dy": y], // vector
|
|
38
|
+
[x, y, width, height] // rect
|
|
39
|
+
])
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
it("converts arguments to CGColor") {
|
|
43
|
+
func testColorComponents(_ color: CGColor, _ red: CGFloat, _ green: CGFloat, _ blue: CGFloat, _ alpha: CGFloat) {
|
|
44
|
+
expect(color.components?[0]) == red / 255.0
|
|
45
|
+
expect(color.components?[1]) == green / 255.0
|
|
46
|
+
expect(color.components?[2]) == blue / 255.0
|
|
47
|
+
expect(color.components?[3]) == alpha / 255.0
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
mockModuleHolder(appContext) {
|
|
51
|
+
$0.function(functionName) { (color1: CGColor, color2: CGColor, color3: CGColor, color4: CGColor) in
|
|
52
|
+
testColorComponents(color1, 0x2A, 0x4B, 0x5D, 0xFF)
|
|
53
|
+
testColorComponents(color2, 0x11, 0xFF, 0x00, 0xDD)
|
|
54
|
+
testColorComponents(color3, 0x66, 0x00, 0xCC, 0xAA)
|
|
55
|
+
testColorComponents(color4, 0x00, 0x00, 0x00, 0x00)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
.callSync(function: functionName, args: [
|
|
59
|
+
"#2A4B5D",
|
|
60
|
+
0xDD11FF00,
|
|
61
|
+
"60CA",
|
|
62
|
+
0
|
|
63
|
+
])
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import ExpoModulesCore
|
|
1
|
+
@testable import ExpoModulesCore
|
|
2
2
|
|
|
3
3
|
class UnnamedModule: Module {
|
|
4
4
|
func definition() -> ModuleDefinition {}
|
|
@@ -13,14 +13,28 @@ class NamedModule: Module {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
class CustomModule: Module {
|
|
16
|
-
|
|
16
|
+
let body: MockedDefinitionFunc
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
self
|
|
20
|
-
self.customDefinition = customDefinition
|
|
18
|
+
func definition() -> ModuleDefinition {
|
|
19
|
+
return body(self)
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
init(appContext: AppContext, _ body: @escaping MockedDefinitionFunc) {
|
|
23
|
+
self.body = body
|
|
24
|
+
super.init(appContext: appContext)
|
|
25
25
|
}
|
|
26
|
+
|
|
27
|
+
required init(appContext: AppContext) {
|
|
28
|
+
fatalError("`init(appContext:)` is unavailable in mocked module class.")
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
typealias MockedDefinitionFunc = (CustomModule) -> ModuleDefinition
|
|
33
|
+
|
|
34
|
+
func mockModuleHolder(_ appContext: AppContext, @ModuleDefinitionBuilder _ definitionBody: @escaping () -> ModuleDefinition) -> ModuleHolder {
|
|
35
|
+
return ModuleHolder(appContext: appContext, module: CustomModule(appContext: appContext, { module in definitionBody() }))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
func mockModuleHolder(_ appContext: AppContext, @ModuleDefinitionBuilder _ definitionBody: @escaping (CustomModule) -> ModuleDefinition) -> ModuleHolder {
|
|
39
|
+
return ModuleHolder(appContext: appContext, module: CustomModule(appContext: appContext, { module in definitionBody(module) }))
|
|
26
40
|
}
|
|
@@ -19,39 +19,40 @@ class ModuleEventListenersSpec: QuickSpec {
|
|
|
19
19
|
appContext = AppContext()
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
it("calls onCreate once the module is
|
|
22
|
+
it("calls onCreate once the module instance is created") {
|
|
23
23
|
waitUntil { done in
|
|
24
|
-
let
|
|
24
|
+
let _ = mockModuleHolder(appContext) {
|
|
25
25
|
$0.onCreate {
|
|
26
26
|
done()
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
appContext.moduleRegistry.register(module: module)
|
|
30
29
|
}
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
it("calls onDestroy once the module is about to be deallocated") {
|
|
34
33
|
waitUntil { done in
|
|
35
|
-
let
|
|
34
|
+
let moduleName = "mockedModule"
|
|
35
|
+
let holder = mockModuleHolder(appContext) {
|
|
36
|
+
$0.name(moduleName)
|
|
36
37
|
$0.onDestroy {
|
|
37
38
|
done()
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
|
-
appContext.moduleRegistry.register(
|
|
41
|
+
appContext.moduleRegistry.register(holder: holder)
|
|
41
42
|
// Unregister the module to deallocate its holder
|
|
42
|
-
appContext.moduleRegistry.unregister(
|
|
43
|
+
appContext.moduleRegistry.unregister(moduleName: holder.name)
|
|
43
44
|
// The `module` object is actually still alive, but its holder is dead
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
it("calls onAppContextDestroys once the context destroys") {
|
|
48
49
|
waitUntil { done in
|
|
49
|
-
let
|
|
50
|
+
let holder = mockModuleHolder(appContext) {
|
|
50
51
|
$0.onAppContextDestroys {
|
|
51
52
|
done()
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
|
-
appContext.moduleRegistry.register(
|
|
55
|
+
appContext.moduleRegistry.register(holder: holder)
|
|
55
56
|
appContext = nil // This must deallocate the app context
|
|
56
57
|
}
|
|
57
58
|
}
|
|
@@ -59,48 +60,48 @@ class ModuleEventListenersSpec: QuickSpec {
|
|
|
59
60
|
it("calls custom event listener when the event is sent to the registry") {
|
|
60
61
|
waitUntil { done in
|
|
61
62
|
let event = EventName.custom("custom event name")
|
|
62
|
-
let
|
|
63
|
+
let holder = mockModuleHolder(appContext) {
|
|
63
64
|
EventListener(event) {
|
|
64
65
|
done()
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
|
-
appContext.moduleRegistry.register(
|
|
68
|
+
appContext.moduleRegistry.register(holder: holder)
|
|
68
69
|
appContext.moduleRegistry.post(event: event)
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
it("calls onAppEntersForeground when system's willEnterForegroundNotification is sent") {
|
|
73
74
|
waitUntil { done in
|
|
74
|
-
let
|
|
75
|
+
let holder = mockModuleHolder(appContext) {
|
|
75
76
|
$0.onAppEntersForeground {
|
|
76
77
|
done()
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
|
-
appContext.moduleRegistry.register(
|
|
80
|
+
appContext.moduleRegistry.register(holder: holder)
|
|
80
81
|
NotificationCenter.default.post(name: UIApplication.willEnterForegroundNotification, object: nil)
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
it("calls onAppBecomesActive when system's didBecomeActiveNotification is sent") {
|
|
85
86
|
waitUntil { done in
|
|
86
|
-
let
|
|
87
|
+
let holder = mockModuleHolder(appContext) {
|
|
87
88
|
$0.onAppBecomesActive {
|
|
88
89
|
done()
|
|
89
90
|
}
|
|
90
91
|
}
|
|
91
|
-
appContext.moduleRegistry.register(
|
|
92
|
+
appContext.moduleRegistry.register(holder: holder)
|
|
92
93
|
NotificationCenter.default.post(name: UIApplication.didBecomeActiveNotification, object: nil)
|
|
93
94
|
}
|
|
94
95
|
}
|
|
95
96
|
|
|
96
97
|
it("calls onAppEntersBackground when system's didEnterBackgroundNotification is sent") {
|
|
97
98
|
waitUntil { done in
|
|
98
|
-
let
|
|
99
|
+
let holder = mockModuleHolder(appContext) {
|
|
99
100
|
$0.onAppEntersBackground {
|
|
100
101
|
done()
|
|
101
102
|
}
|
|
102
103
|
}
|
|
103
|
-
appContext.moduleRegistry.register(
|
|
104
|
+
appContext.moduleRegistry.register(holder: holder)
|
|
104
105
|
NotificationCenter.default.post(name: UIApplication.didEnterBackgroundNotification, object: nil)
|
|
105
106
|
}
|
|
106
107
|
}
|
|
@@ -8,22 +8,19 @@ class ModuleRegistrySpec: QuickSpec {
|
|
|
8
8
|
let appContext = AppContext()
|
|
9
9
|
|
|
10
10
|
it("registers unnamed module") {
|
|
11
|
-
testRegister(
|
|
11
|
+
testRegister(moduleType: UnnamedModule.self, name: String(describing: UnnamedModule.self))
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
it("registers named module") {
|
|
15
|
-
testRegister(
|
|
15
|
+
testRegister(moduleType: NamedModule.self, name: NamedModule.namedModuleName)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
func testRegister(
|
|
18
|
+
func testRegister<ModuleType: AnyModule>(moduleType: ModuleType.Type, name: String) {
|
|
19
19
|
let moduleRegistry = appContext.moduleRegistry
|
|
20
20
|
|
|
21
|
-
moduleRegistry.register(
|
|
21
|
+
moduleRegistry.register(moduleType: moduleType)
|
|
22
22
|
|
|
23
23
|
expect(moduleRegistry.has(moduleWithName: name)).to(beTrue())
|
|
24
|
-
expect(moduleRegistry.get(moduleWithName: name)).to(beIdenticalTo(module))
|
|
25
|
-
expect(moduleRegistry.contains { $0.module === module }).to(beTrue())
|
|
26
|
-
expect(moduleRegistry.get(moduleHolderForName: name)?.module).to(beIdenticalTo(module))
|
|
27
24
|
}
|
|
28
25
|
}
|
|
29
26
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-modules-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "The core of Expo Modules architecture",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"license": "MIT",
|
|
33
33
|
"homepage": "https://github.com/expo/expo/tree/master/packages/expo-modules-core",
|
|
34
34
|
"jest": {
|
|
35
|
-
"preset": "expo-module-scripts
|
|
35
|
+
"preset": "expo-module-scripts"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"compare-versions": "^3.4.0",
|
|
@@ -42,5 +42,5 @@
|
|
|
42
42
|
"@testing-library/react-hooks": "^7.0.1",
|
|
43
43
|
"expo-module-scripts": "^2.0.0"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "9faa58818454ba59dbff95077b9025a1c1cbd9fd"
|
|
46
46
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { NativeModules } from 'react-native';
|
|
2
2
|
|
|
3
|
-
import { ProxyNativeModule } from './NativeModulesProxy.types';
|
|
3
|
+
import { ProxyNativeModule, TurboNativeModuleProxy } from './NativeModulesProxy.types';
|
|
4
|
+
|
|
5
|
+
// `ExpoModulesProxy` is not declared in TypeScript yet. It's installed via JSI.
|
|
6
|
+
declare namespace global {
|
|
7
|
+
const ExpoModulesProxy: TurboNativeModuleProxy;
|
|
8
|
+
}
|
|
4
9
|
|
|
5
10
|
const NativeProxy = NativeModules.NativeUnimoduleProxy;
|
|
6
11
|
const modulesConstantsKey = 'modulesConstants';
|
|
@@ -8,6 +13,16 @@ const exportedMethodsKey = 'exportedMethods';
|
|
|
8
13
|
|
|
9
14
|
const NativeModulesProxy: { [moduleName: string]: ProxyNativeModule } = {};
|
|
10
15
|
|
|
16
|
+
// Keep it opt-in for now. It's too risky without proper and thorough testing.
|
|
17
|
+
let canUseExpoTurboModules = false;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Sets whether to use a TurboModule version of the proxy.
|
|
21
|
+
*/
|
|
22
|
+
export function useExpoTurboModules(state: boolean = true) {
|
|
23
|
+
canUseExpoTurboModules = state;
|
|
24
|
+
}
|
|
25
|
+
|
|
11
26
|
if (NativeProxy) {
|
|
12
27
|
Object.keys(NativeProxy[exportedMethodsKey]).forEach((moduleName) => {
|
|
13
28
|
NativeModulesProxy[moduleName] = NativeProxy[modulesConstantsKey][moduleName] || {};
|
|
@@ -23,7 +38,12 @@ if (NativeProxy) {
|
|
|
23
38
|
)
|
|
24
39
|
);
|
|
25
40
|
}
|
|
26
|
-
|
|
41
|
+
|
|
42
|
+
if (canUseExpoTurboModules && global.ExpoModulesProxy) {
|
|
43
|
+
return global.ExpoModulesProxy.callMethodAsync(moduleName, methodInfo.name, args);
|
|
44
|
+
} else {
|
|
45
|
+
return NativeProxy.callMethod(moduleName, key, args);
|
|
46
|
+
}
|
|
27
47
|
};
|
|
28
48
|
});
|
|
29
49
|
|
|
@@ -3,3 +3,11 @@ export type ProxyNativeModule = {
|
|
|
3
3
|
addListener: (eventName: string) => void;
|
|
4
4
|
removeListeners: (count: number) => void;
|
|
5
5
|
};
|
|
6
|
+
|
|
7
|
+
export type TurboNativeModuleProxy = {
|
|
8
|
+
callMethodAsync: <ReturnType>(
|
|
9
|
+
moduleName: string,
|
|
10
|
+
methodName: string,
|
|
11
|
+
args: any[]
|
|
12
|
+
) => Promise<ReturnType>;
|
|
13
|
+
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// Copyright © 2018 650 Industries. All rights reserved.
|
|
2
|
-
|
|
3
|
-
#import <Foundation/Foundation.h>
|
|
4
|
-
#import <UIKit/UIKit.h>
|
|
5
|
-
|
|
6
|
-
NS_ASSUME_NONNULL_BEGIN
|
|
7
|
-
|
|
8
|
-
NS_SWIFT_NAME(AppDelegateWrapper)
|
|
9
|
-
@interface EXAppDelegateWrapper : UIResponder <UIApplicationDelegate>
|
|
10
|
-
|
|
11
|
-
@end
|
|
12
|
-
|
|
13
|
-
NS_ASSUME_NONNULL_END
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
struct AnyArgumentType: CustomDebugStringConvertible {
|
|
3
|
-
let baseType: Any.Type
|
|
4
|
-
let typeName: String
|
|
5
|
-
|
|
6
|
-
private let castHelper: (Any) -> AnyMethodArgument?
|
|
7
|
-
private let canCastHelper: (Any) -> Bool
|
|
8
|
-
|
|
9
|
-
init<T: AnyMethodArgument>(_ baseType: T.Type) {
|
|
10
|
-
self.baseType = baseType
|
|
11
|
-
self.typeName = String(describing: baseType)
|
|
12
|
-
self.castHelper = { $0 as? T }
|
|
13
|
-
|
|
14
|
-
// handle class metatypes separately in order to allow T.self != base.
|
|
15
|
-
if baseType is AnyClass {
|
|
16
|
-
self.canCastHelper = { x in
|
|
17
|
-
sequence(
|
|
18
|
-
first: Mirror(reflecting: x), next: { $0.superclassMirror }
|
|
19
|
-
)
|
|
20
|
-
.contains { $0.subjectType == baseType }
|
|
21
|
-
}
|
|
22
|
-
} else {
|
|
23
|
-
self.canCastHelper = { $0 is T }
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
func cast<T>(_ object: T) -> AnyMethodArgument? {
|
|
28
|
-
return castHelper(object)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
func canCast<T>(_ object: T) -> Bool {
|
|
32
|
-
return canCastHelper(object)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
func canCastToType<T>(_ type: T.Type) -> Bool {
|
|
36
|
-
return baseType is T.Type
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
func castWrappedType<T>(_ type: T.Type) -> T? {
|
|
40
|
-
return baseType as? T
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// MARK: CustomDebugStringConvertible
|
|
44
|
-
|
|
45
|
-
var debugDescription: String {
|
|
46
|
-
return String(describing: baseType)
|
|
47
|
-
}
|
|
48
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import Dispatch
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
A protocol for any type-erased module's method.
|
|
5
|
-
*/
|
|
6
|
-
public protocol AnyMethod: AnyDefinition {
|
|
7
|
-
/**
|
|
8
|
-
Name of the exported method. JavaScript refers to the method by this name.
|
|
9
|
-
*/
|
|
10
|
-
var name: String { get }
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
A number of arguments the method takes. If the last argument is of type `Promise`, it is not counted.
|
|
14
|
-
*/
|
|
15
|
-
var argumentsCount: Int { get }
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
Dispatch queue on which each method's call is run.
|
|
19
|
-
*/
|
|
20
|
-
var queue: DispatchQueue? { get }
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
Calls the method with given arguments and a promise.
|
|
24
|
-
*/
|
|
25
|
-
func call(args: [Any?], promise: Promise) -> Void
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
Specifies on which queue the method should run.
|
|
29
|
-
*/
|
|
30
|
-
func runOnQueue(_ queue: DispatchQueue?) -> Self
|
|
31
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
A protocol for classes/structs accepted as an argument of exported methods.
|
|
4
|
-
*/
|
|
5
|
-
public protocol AnyMethodArgument {}
|
|
6
|
-
|
|
7
|
-
// Extend the primitive types — these may come from React Native bridge.
|
|
8
|
-
extension Bool: AnyMethodArgument {}
|
|
9
|
-
extension Int: AnyMethodArgument {}
|
|
10
|
-
extension Double: AnyMethodArgument {}
|
|
11
|
-
extension String: AnyMethodArgument {}
|
|
12
|
-
extension Array: AnyMethodArgument {}
|
|
13
|
-
extension Dictionary: AnyMethodArgument {}
|