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.
Files changed (129) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/android/build.gradle +30 -2
  3. package/android/src/main/java/expo/modules/adapters/react/ModuleRegistryAdapter.java +27 -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/Package.java +4 -0
  9. package/android/src/main/java/expo/modules/core/interfaces/ReactActivityHandler.kt +18 -0
  10. package/android/src/main/java/expo/modules/core/interfaces/ReactNativeHostHandler.kt +14 -0
  11. package/android/src/main/java/expo/modules/core/utilities/KotlinUtilities.kt +23 -0
  12. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +166 -0
  13. package/android/src/main/java/expo/modules/kotlin/DynamicExtenstions.kt +9 -0
  14. package/android/src/main/java/expo/modules/kotlin/ExpoModulesHelper.kt +18 -0
  15. package/android/src/main/java/expo/modules/kotlin/KPromiseWrapper.kt +23 -0
  16. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +98 -0
  17. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +41 -0
  18. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +56 -0
  19. package/android/src/main/java/expo/modules/kotlin/ModulesProvider.kt +7 -0
  20. package/android/src/main/java/expo/modules/kotlin/Promise.kt +13 -0
  21. package/android/src/main/java/expo/modules/kotlin/ReactLifecycleDelegate.kt +39 -0
  22. package/android/src/main/java/expo/modules/kotlin/ReadableArrayIterator.kt +14 -0
  23. package/android/src/main/java/expo/modules/kotlin/ReadableTypeExtensions.kt +18 -0
  24. package/android/src/main/java/expo/modules/kotlin/allocators/ObjectConstructor.kt +5 -0
  25. package/android/src/main/java/expo/modules/kotlin/allocators/ObjectConstructorFactory.kt +31 -0
  26. package/android/src/main/java/expo/modules/kotlin/allocators/UnsafeAllocator.kt +49 -0
  27. package/android/src/main/java/expo/modules/kotlin/events/EventListener.kt +39 -0
  28. package/android/src/main/java/expo/modules/kotlin/events/EventName.kt +31 -0
  29. package/android/src/main/java/expo/modules/kotlin/events/EventsDefinition.kt +3 -0
  30. package/android/src/main/java/expo/modules/kotlin/events/KEventEmitterWrapper.kt +26 -0
  31. package/android/src/main/java/expo/modules/kotlin/events/OnActivityResultPayload.kt +8 -0
  32. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +70 -0
  33. package/android/src/main/java/expo/modules/kotlin/methods/AnyMethod.kt +50 -0
  34. package/android/src/main/java/expo/modules/kotlin/methods/Method.kt +14 -0
  35. package/android/src/main/java/expo/modules/kotlin/methods/PromiseMethod.kt +15 -0
  36. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +24 -0
  37. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +227 -0
  38. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +16 -0
  39. package/android/src/main/java/expo/modules/kotlin/records/Field.kt +5 -0
  40. package/android/src/main/java/expo/modules/kotlin/records/Record.kt +3 -0
  41. package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +55 -0
  42. package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +14 -0
  43. package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +44 -0
  44. package/android/src/main/java/expo/modules/kotlin/types/BasicTypeConverters.kt +60 -0
  45. package/android/src/main/java/expo/modules/kotlin/types/EnumTypeConverter.kt +84 -0
  46. package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +25 -0
  47. package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +39 -0
  48. package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +28 -0
  49. package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +19 -0
  50. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +107 -0
  51. package/android/src/main/java/expo/modules/kotlin/views/AnyViewProp.kt +10 -0
  52. package/android/src/main/java/expo/modules/kotlin/views/ConcreteViewProp.kt +17 -0
  53. package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +22 -0
  54. package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +21 -0
  55. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +36 -0
  56. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +40 -0
  57. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +21 -0
  58. package/android/src/main/java/expo/modules/kotlin/views/ViewWrapperDelegateHolder.kt +5 -0
  59. package/build/NativeModulesProxy.native.d.ts +4 -0
  60. package/build/NativeModulesProxy.native.js +14 -1
  61. package/build/NativeModulesProxy.native.js.map +1 -1
  62. package/build/NativeModulesProxy.types.d.ts +3 -0
  63. package/build/NativeModulesProxy.types.js.map +1 -1
  64. package/ios/AppDelegates/EXAppDelegateWrapper.h +16 -0
  65. package/ios/AppDelegates/EXAppDelegateWrapper.m +42 -0
  66. package/ios/AppDelegates/EXAppDelegatesLoader.h +15 -0
  67. package/ios/AppDelegates/EXAppDelegatesLoader.m +29 -0
  68. package/ios/AppDelegates/EXLegacyAppDelegateWrapper.h +16 -0
  69. package/ios/{EXAppDelegateWrapper.m → AppDelegates/EXLegacyAppDelegateWrapper.m} +2 -2
  70. package/ios/AppDelegates/ExpoAppDelegate.swift +264 -0
  71. package/ios/AppDelegates/ExpoAppDelegateSubscriber.swift +24 -0
  72. package/ios/ExpoModulesCore.podspec +7 -2
  73. package/ios/JSI/ExpoModulesProxySpec.h +24 -0
  74. package/ios/JSI/ExpoModulesProxySpec.mm +135 -0
  75. package/ios/JSI/JSIConversions.h +42 -0
  76. package/ios/JSI/JSIConversions.mm +164 -0
  77. package/ios/JSI/JSIInstaller.h +19 -0
  78. package/ios/JSI/JSIInstaller.mm +22 -0
  79. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +1 -6
  80. package/ios/NativeModulesProxy/EXNativeModulesProxy.h +6 -0
  81. package/ios/NativeModulesProxy/{EXNativeModulesProxy.m → EXNativeModulesProxy.mm} +45 -12
  82. package/ios/Services/EXReactNativeEventEmitter.h +6 -0
  83. package/ios/Services/EXReactNativeEventEmitter.m +15 -0
  84. package/ios/Swift/AppContext.swift +14 -1
  85. package/ios/Swift/Arguments/AnyArgument.swift +14 -0
  86. package/ios/Swift/Arguments/AnyArgumentType.swift +13 -0
  87. package/ios/Swift/Arguments/ArgumentType.swift +24 -0
  88. package/ios/Swift/Arguments/ConvertibleArgument.swift +15 -0
  89. package/ios/Swift/Arguments/Convertibles.swift +93 -0
  90. package/ios/Swift/Arguments/Types/ArrayArgumentType.swift +42 -0
  91. package/ios/Swift/Arguments/Types/ConvertibleArgumentType.swift +16 -0
  92. package/ios/Swift/Arguments/Types/EnumArgumentType.swift +105 -0
  93. package/ios/Swift/Arguments/Types/OptionalArgumentType.swift +49 -0
  94. package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +15 -0
  95. package/ios/Swift/Arguments/Types/RawArgumentType.swift +25 -0
  96. package/ios/Swift/Conversions.swift +199 -7
  97. package/ios/Swift/EventListener.swift +37 -5
  98. package/ios/Swift/Functions/AnyFunction.swift +42 -0
  99. package/ios/Swift/{Methods/ConcreteMethod.swift → Functions/ConcreteFunction.swift} +32 -34
  100. package/ios/Swift/ModuleHolder.swift +75 -20
  101. package/ios/Swift/ModuleRegistry.swift +19 -8
  102. package/ios/Swift/Modules/AnyModule.swift +8 -8
  103. package/ios/Swift/Modules/Module.swift +7 -0
  104. package/ios/Swift/Modules/ModuleDefinition.swift +52 -8
  105. package/ios/Swift/Modules/ModuleDefinitionBuilder.swift +1 -1
  106. package/ios/Swift/Modules/ModuleDefinitionComponents.swift +140 -52
  107. package/ios/Swift/ModulesProvider.swift +9 -0
  108. package/ios/Swift/Promise.swift +1 -1
  109. package/ios/Swift/Records/Field.swift +1 -1
  110. package/ios/Swift/Records/Record.swift +8 -1
  111. package/ios/Swift/SwiftInteropBridge.swift +45 -16
  112. package/ios/Swift/Views/AnyViewProp.swift +2 -2
  113. package/ios/Swift/Views/ConcreteViewProp.swift +37 -10
  114. package/ios/Swift/Views/ViewModuleWrapper.swift +9 -4
  115. package/ios/Swift.h +9 -0
  116. package/ios/Tests/ArgumentTypeSpec.swift +145 -0
  117. package/ios/Tests/ConvertiblesSpec.swift +231 -0
  118. package/ios/Tests/{MethodSpec.swift → FunctionSpec.swift} +69 -54
  119. package/ios/Tests/FunctionWithConvertiblesSpec.swift +66 -0
  120. package/ios/Tests/Mocks/ModuleMocks.swift +21 -7
  121. package/ios/Tests/ModuleEventListenersSpec.swift +17 -16
  122. package/ios/Tests/ModuleRegistrySpec.swift +4 -7
  123. package/package.json +3 -3
  124. package/src/NativeModulesProxy.native.ts +22 -2
  125. package/src/NativeModulesProxy.types.ts +8 -0
  126. package/ios/EXAppDelegateWrapper.h +0 -13
  127. package/ios/Swift/Methods/AnyArgumentType.swift +0 -48
  128. package/ios/Swift/Methods/AnyMethod.swift +0 -31
  129. 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 MethodSpec: QuickSpec {
6
+ class FunctionSpec: QuickSpec {
7
7
  override func spec() {
8
8
  let appContext = AppContext()
9
- let methodName = "test method name"
9
+ let functionName = "test function name"
10
10
 
11
- func testMethodReturning<T: Equatable>(value returnValue: T) {
11
+ func testFunctionReturning<T: Equatable>(value returnValue: T) {
12
12
  waitUntil { done in
13
- let module = CustomModule(appContext: appContext) {
14
- $0.method(methodName) {
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
- let module = CustomModule(appContext: appContext) {
31
- $0.method(methodName) {
29
+ mockModuleHolder(appContext) {
30
+ $0.function(functionName) {
32
31
  done()
33
32
  }
34
33
  }
35
- ModuleHolder(module: module).call(method: methodName, args: [])
34
+ .call(function: functionName, args: [])
36
35
  }
37
36
  }
38
37
 
39
38
  it("returns bool values") {
40
- testMethodReturning(value: true)
41
- testMethodReturning(value: false)
42
- testMethodReturning(value: [true, false])
39
+ testFunctionReturning(value: true)
40
+ testFunctionReturning(value: false)
41
+ testFunctionReturning(value: [true, false])
43
42
  }
44
43
 
45
44
  it("returns int values") {
46
- testMethodReturning(value: 1234)
47
- testMethodReturning(value: [2, 1, 3, 7])
45
+ testFunctionReturning(value: 1234)
46
+ testFunctionReturning(value: [2, 1, 3, 7])
48
47
  }
49
48
 
50
49
  it("returns double values") {
51
- testMethodReturning(value: 3.14)
52
- testMethodReturning(value: [0, 1.1, 2.2])
50
+ testFunctionReturning(value: 3.14)
51
+ testFunctionReturning(value: [0, 1.1, 2.2])
53
52
  }
54
53
 
55
54
  it("returns string values") {
56
- testMethodReturning(value: "a string")
57
- testMethodReturning(value: ["expo", "modules", "core"])
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
- ModuleHolder(module: module).call(method: methodName, args: [dict]) { value, error in
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
- ModuleHolder(module: module).call(method: methodName, args: [dict]) { value, error in
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
- ModuleHolder(module: module).call(method: methodName, args: [dict]) { value, error in
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
- let module = CustomModule(appContext: appContext) {
130
- $0.method(methodName) { (a: Int) in
147
+ mockModuleHolder(appContext) {
148
+ $0.function(functionName) { (a: Int) in
131
149
  return "something"
132
150
  }
133
151
  }
134
-
135
- // Method expects one argument, let's give it more.
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
- let module = CustomModule(appContext: appContext) {
149
- $0.method(methodName) { (a: String) in
165
+ mockModuleHolder(appContext) {
166
+ $0.function(functionName) { (a: String) in
150
167
  return "something"
151
168
  }
152
169
  }
153
-
154
- // Method expects a string, let's give it a number.
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(IncompatibleArgTypeError<Any?>.self))
158
- expect(error?.code).to(equal("ERR_INCOMPATIBLE_ARG_TYPE"))
159
- // TODO: (@tsapeta) The descriptions may not equal yet, due to internal type-erasing. Fix it and uncomment this test.
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
- var customDefinition: ((CustomModule) -> ModuleDefinition)!
16
+ let body: MockedDefinitionFunc
17
17
 
18
- convenience init(appContext: AppContext, @ModuleDefinitionBuilder _ customDefinition: @escaping (CustomModule) -> ModuleDefinition) {
19
- self.init(appContext: appContext)
20
- self.customDefinition = customDefinition
18
+ func definition() -> ModuleDefinition {
19
+ return body(self)
21
20
  }
22
21
 
23
- func definition() -> ModuleDefinition {
24
- return customDefinition(self)
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 registered") {
22
+ it("calls onCreate once the module instance is created") {
23
23
  waitUntil { done in
24
- let module = CustomModule(appContext: appContext) {
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 module = CustomModule(appContext: appContext) {
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(module: module)
41
+ appContext.moduleRegistry.register(holder: holder)
41
42
  // Unregister the module to deallocate its holder
42
- appContext.moduleRegistry.unregister(module: module)
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 module = CustomModule(appContext: appContext) {
50
+ let holder = mockModuleHolder(appContext) {
50
51
  $0.onAppContextDestroys {
51
52
  done()
52
53
  }
53
54
  }
54
- appContext.moduleRegistry.register(module: module)
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 module = CustomModule(appContext: appContext) { _ in
63
+ let holder = mockModuleHolder(appContext) {
63
64
  EventListener(event) {
64
65
  done()
65
66
  }
66
67
  }
67
- appContext.moduleRegistry.register(module: module)
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 module = CustomModule(appContext: appContext) {
75
+ let holder = mockModuleHolder(appContext) {
75
76
  $0.onAppEntersForeground {
76
77
  done()
77
78
  }
78
79
  }
79
- appContext.moduleRegistry.register(module: module)
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 module = CustomModule(appContext: appContext) {
87
+ let holder = mockModuleHolder(appContext) {
87
88
  $0.onAppBecomesActive {
88
89
  done()
89
90
  }
90
91
  }
91
- appContext.moduleRegistry.register(module: module)
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 module = CustomModule(appContext: appContext) {
99
+ let holder = mockModuleHolder(appContext) {
99
100
  $0.onAppEntersBackground {
100
101
  done()
101
102
  }
102
103
  }
103
- appContext.moduleRegistry.register(module: module)
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(module: UnnamedModule(appContext: appContext), name: String(describing: UnnamedModule.self))
11
+ testRegister(moduleType: UnnamedModule.self, name: String(describing: UnnamedModule.self))
12
12
  }
13
13
 
14
14
  it("registers named module") {
15
- testRegister(module: NamedModule(appContext: appContext), name: NamedModule.namedModuleName)
15
+ testRegister(moduleType: NamedModule.self, name: NamedModule.namedModuleName)
16
16
  }
17
17
 
18
- func testRegister(module: Module, name: String) {
18
+ func testRegister<ModuleType: AnyModule>(moduleType: ModuleType.Type, name: String) {
19
19
  let moduleRegistry = appContext.moduleRegistry
20
20
 
21
- moduleRegistry.register(module: module)
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.4.8",
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/ios"
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": "f93456e96091501a9b9f99246846cee29336a964"
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
- return NativeProxy.callMethod(moduleName, key, args);
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 {}