expo-modules-core 0.6.1 → 0.7.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 +38 -0
- package/README.md +1 -1
- package/android/build.gradle +5 -5
- package/android/src/main/java/expo/modules/adapters/react/apploader/RNHeadlessAppLoader.kt +7 -1
- package/android/src/main/java/expo/modules/core/interfaces/ReactActivityLifecycleListener.java +23 -0
- package/android/src/main/java/expo/modules/kotlin/AppContext.kt +11 -1
- package/android/src/main/java/expo/modules/kotlin/DynamicExtenstions.kt +5 -3
- package/android/src/main/java/expo/modules/kotlin/KPromiseWrapper.kt +8 -2
- package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +13 -4
- package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +7 -6
- package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +6 -1
- package/android/src/main/java/expo/modules/kotlin/Promise.kt +1 -1
- package/android/src/main/java/expo/modules/kotlin/callbacks/Callback.kt +5 -0
- package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallback.kt +28 -0
- package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallbackDelegate.kt +27 -0
- package/android/src/main/java/expo/modules/kotlin/defaultmodules/ErrorManagerModule.kt +25 -0
- package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +68 -8
- package/android/src/main/java/expo/modules/kotlin/exception/ExceptionDecorator.kt +11 -0
- package/android/src/main/java/expo/modules/kotlin/methods/AnyMethod.kt +13 -14
- package/android/src/main/java/expo/modules/kotlin/modules/DefinitionMarker.kt +4 -0
- package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +3 -2
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +44 -4
- package/android/src/main/java/expo/modules/kotlin/records/Record.kt +39 -0
- package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +14 -7
- package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +11 -5
- package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +10 -4
- package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +12 -6
- package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +29 -13
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +2 -1
- package/android/src/main/java/expo/modules/kotlin/views/CallbacksDefinition.kt +3 -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 +22 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +27 -2
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +29 -1
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +59 -2
- package/build/EventEmitter.d.ts +1 -0
- package/build/EventEmitter.d.ts.map +1 -0
- package/build/NativeModulesProxy.d.ts +1 -0
- package/build/NativeModulesProxy.d.ts.map +1 -0
- package/build/NativeModulesProxy.native.d.ts +1 -0
- package/build/NativeModulesProxy.native.d.ts.map +1 -0
- package/build/NativeModulesProxy.types.d.ts +1 -0
- package/build/NativeModulesProxy.types.d.ts.map +1 -0
- package/build/NativeViewManagerAdapter.d.ts +1 -0
- package/build/NativeViewManagerAdapter.d.ts.map +1 -0
- package/build/NativeViewManagerAdapter.native.d.ts +1 -0
- package/build/NativeViewManagerAdapter.native.d.ts.map +1 -0
- package/build/PermissionsHook.d.ts +1 -0
- package/build/PermissionsHook.d.ts.map +1 -0
- package/build/PermissionsInterface.d.ts +1 -0
- package/build/PermissionsInterface.d.ts.map +1 -0
- package/build/Platform.d.ts +1 -0
- package/build/Platform.d.ts.map +1 -0
- package/build/SyntheticPlatformEmitter.d.ts +1 -0
- package/build/SyntheticPlatformEmitter.d.ts.map +1 -0
- package/build/SyntheticPlatformEmitter.web.d.ts +1 -0
- package/build/SyntheticPlatformEmitter.web.d.ts.map +1 -0
- package/build/deprecate.d.ts +1 -0
- package/build/deprecate.d.ts.map +1 -0
- package/build/environment/browser.d.ts +1 -0
- package/build/environment/browser.d.ts.map +1 -0
- package/build/environment/browser.web.d.ts +1 -0
- package/build/environment/browser.web.d.ts.map +1 -0
- package/build/errors/CodedError.d.ts +1 -0
- package/build/errors/CodedError.d.ts.map +1 -0
- package/build/errors/UnavailabilityError.d.ts +1 -0
- package/build/errors/UnavailabilityError.d.ts.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +2 -0
- package/build/index.js.map +1 -1
- package/build/requireNativeModule.d.ts +16 -0
- package/build/requireNativeModule.d.ts.map +1 -0
- package/build/requireNativeModule.js +18 -0
- package/build/requireNativeModule.js.map +1 -0
- package/build/sweet/NativeErrorManager.d.ts +3 -0
- package/build/sweet/NativeErrorManager.d.ts.map +1 -0
- package/build/sweet/NativeErrorManager.js +3 -0
- package/build/sweet/NativeErrorManager.js.map +1 -0
- package/build/sweet/setUpErrorManager.fx.d.ts +2 -0
- package/build/sweet/setUpErrorManager.fx.d.ts.map +1 -0
- package/build/sweet/setUpErrorManager.fx.js +11 -0
- package/build/sweet/setUpErrorManager.fx.js.map +1 -0
- package/ios/AppDelegates/ExpoAppDelegate.swift +27 -8
- package/ios/JSI/ExpoModulesHostObject.h +33 -0
- package/ios/JSI/ExpoModulesHostObject.mm +40 -0
- package/ios/JSI/ExpoModulesProxySpec.h +4 -0
- package/ios/JSI/ExpoModulesProxySpec.mm +1 -3
- package/ios/JSI/JSIConversions.h +2 -0
- package/ios/JSI/JSIConversions.mm +9 -0
- package/ios/JSI/JSIInstaller.h +10 -0
- package/ios/JSI/JSIInstaller.mm +14 -2
- package/ios/JSI/JavaScriptObject.h +60 -0
- package/ios/JSI/JavaScriptObject.mm +93 -0
- package/ios/JSI/JavaScriptRuntime.h +54 -0
- package/ios/JSI/JavaScriptRuntime.mm +102 -0
- package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +2 -12
- package/ios/NativeModulesProxy/EXComponentDataCompatibleWrapper.h +16 -0
- package/ios/NativeModulesProxy/EXComponentDataCompatibleWrapper.m +28 -0
- package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +90 -66
- package/ios/RCTComponentData+Privates.h +12 -0
- package/ios/ReactDelegates/ExpoReactDelegate.swift +2 -2
- package/ios/ReactDelegates/ExpoReactDelegateHandler.swift +3 -3
- package/ios/ReactDelegates/ModulePriorities.swift +1 -1
- package/ios/Swift/AppContext.swift +38 -4
- package/ios/Swift/Arguments/ArgumentType.swift +4 -0
- package/ios/Swift/Arguments/Convertibles.swift +13 -13
- package/ios/Swift/Arguments/Types/EnumArgumentType.swift +11 -17
- package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +1 -1
- package/ios/Swift/Arguments/Types/RawArgumentType.swift +2 -2
- package/ios/Swift/Conversions.swift +51 -56
- package/ios/Swift/EventListener.swift +8 -10
- package/ios/Swift/Events/Callback.swift +66 -0
- package/ios/Swift/Events/Event.swift +43 -0
- package/ios/Swift/Exceptions/ChainableException.swift +51 -0
- package/ios/Swift/{CodedError.swift → Exceptions/CodedError.swift} +1 -12
- package/ios/Swift/Exceptions/Exception.swift +62 -0
- package/ios/Swift/Exceptions/ExceptionOrigin.swift +28 -0
- package/ios/Swift/Exceptions/GenericException.swift +20 -0
- package/ios/Swift/Exceptions/UnexpectedException.swift +16 -0
- package/ios/Swift/Functions/AnyFunction.swift +11 -1
- package/ios/Swift/Functions/ConcreteFunction.swift +37 -16
- package/ios/Swift/JavaScriptUtils.swift +43 -0
- package/ios/Swift/ModuleHolder.swift +53 -14
- package/ios/Swift/ModuleRegistry.swift +4 -1
- package/ios/Swift/Modules/AnyModule.swift +0 -1
- package/ios/Swift/Modules/ModuleDefinition.swift +4 -13
- package/ios/Swift/Modules/ModuleDefinitionBuilder.swift +0 -1
- package/ios/Swift/Modules/ModuleDefinitionComponents.swift +0 -188
- package/ios/Swift/ModulesProvider.swift +0 -1
- package/ios/Swift/Objects/ObjectDefinition.swift +30 -0
- package/ios/Swift/Objects/ObjectDefinitionComponents.swift +208 -0
- package/ios/Swift/Promise.swift +8 -3
- package/ios/Swift/Records/AnyField.swift +7 -0
- package/ios/Swift/Records/Field.swift +24 -19
- package/ios/Swift/Records/FieldOption.swift +1 -1
- package/ios/Swift/Records/Record.swift +12 -4
- package/ios/Swift/SwiftInteropBridge.swift +39 -10
- package/ios/Swift/Views/AnyViewProp.swift +1 -1
- package/ios/Swift/Views/ComponentData.swift +95 -0
- package/ios/Swift/Views/ConcreteViewProp.swift +6 -8
- package/ios/Swift/Views/ViewFactory.swift +1 -1
- package/ios/Swift/Views/ViewManagerDefinition.swift +23 -2
- package/ios/Swift/Views/ViewManagerDefinitionBuilder.swift +0 -1
- package/ios/Swift/Views/ViewManagerDefinitionComponents.swift +26 -0
- package/ios/Swift/Views/ViewModuleWrapper.swift +5 -2
- package/ios/Tests/ArgumentTypeSpec.swift +3 -4
- package/ios/Tests/ConstantsSpec.swift +4 -4
- package/ios/Tests/ConvertiblesSpec.swift +33 -33
- package/ios/Tests/ExceptionsSpec.swift +112 -0
- package/ios/Tests/FunctionSpec.swift +20 -22
- package/ios/Tests/FunctionWithConvertiblesSpec.swift +2 -2
- package/ios/Tests/Mocks/ModuleMocks.swift +1 -1
- package/ios/Tests/Mocks/ModulesProviderMock.swift +0 -1
- package/ios/Tests/ModuleEventListenersSpec.swift +1 -1
- package/ios/Tests/RecordSpec.swift +7 -17
- package/package.json +3 -3
- package/src/index.ts +4 -0
- package/src/requireNativeModule.ts +29 -0
- package/src/sweet/NativeErrorManager.ts +2 -0
- package/src/sweet/setUpErrorManager.fx.ts +12 -0
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,44 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 0.7.0 — 2022-01-26
|
|
14
|
+
|
|
15
|
+
### 🎉 New features
|
|
16
|
+
|
|
17
|
+
- Allow accessing `RCTBridge` from the modules on iOS. ([#15816](https://github.com/expo/expo/pull/15816) by [@tsapeta](https://github.com/tsapeta))
|
|
18
|
+
- Added support for native callbacks through the view props in Sweet API on iOS. ([#15731](https://github.com/expo/expo/pull/15731) by [@tsapeta](https://github.com/tsapeta))
|
|
19
|
+
- Added support for native callbacks through the view props in Sweet API on Android. ([#15743](https://github.com/expo/expo/pull/15743) by [@lukmccall](https://github.com/lukmccall))
|
|
20
|
+
- The `ModuleDefinition` will use class name if the `name` component wasn't provided in Sweet API on Android. ([#15738](https://github.com/expo/expo/pull/15738) by [@lukmccall](https://github.com/lukmccall))
|
|
21
|
+
- Added `onViewDestroys` component to the `ViewManager` in Sweet API on Android. ([#15740](https://github.com/expo/expo/pull/15740) by [@lukmccall](https://github.com/lukmccall))
|
|
22
|
+
- Added shortened `constants` component that takes `vargs Pair<String, Any?>` as an argument in Sweet API on Android. ([#15742](https://github.com/expo/expo/pull/15742) by [@lukmccall](https://github.com/lukmccall))
|
|
23
|
+
- Introduced the concept of chainable exceptions in Sweet API on iOS. ([#15813](https://github.com/expo/expo/pull/15813) by [@tsapeta](https://github.com/tsapeta))
|
|
24
|
+
- Sweet function closures can throw errors on iOS. ([#15849](https://github.com/expo/expo/pull/15849) by [@tsapeta](https://github.com/tsapeta))
|
|
25
|
+
- Add `requireNativeModule` function to replace accessing native modules from `NativeModulesProxy`. ([#15848](https://github.com/expo/expo/pull/15848) by [@tsapeta](https://github.com/tsapeta))
|
|
26
|
+
- Implemented basic functionality of JSI host object to replace `NativeModulesProxy` on iOS. ([#15847](https://github.com/expo/expo/pull/15847) by [@tsapeta](https://github.com/tsapeta))
|
|
27
|
+
|
|
28
|
+
### 🐛 Bug fixes
|
|
29
|
+
|
|
30
|
+
- It's no longer possible to directly call methods from the `ModuleDefinition` in the `ViewManagers` on Android. ([#15741](https://github.com/expo/expo/pull/15741) by [@lukmccall](https://github.com/lukmccall))
|
|
31
|
+
- Fix compatibility with react-native 0.66. ([#15914](https://github.com/expo/expo/pull/15914) by [@kudo](https://github.com/kudo))
|
|
32
|
+
|
|
33
|
+
## 0.6.4 — 2022-01-05
|
|
34
|
+
|
|
35
|
+
### 🐛 Bug fixes
|
|
36
|
+
|
|
37
|
+
- Fix `ReactInstanceManager.onHostPause` exception from moving Android apps to background. ([#15748](https://github.com/expo/expo/pull/15748) by [@kudo](https://github.com/kudo))
|
|
38
|
+
|
|
39
|
+
## 0.6.3 — 2021-12-16
|
|
40
|
+
|
|
41
|
+
### 🐛 Bug fixes
|
|
42
|
+
|
|
43
|
+
- Fixed the deep link wasn't passed to the application if the application wasn't running when the deep link was sent. ([#15593](https://github.com/expo/expo/pull/15593) by [@lukmccall](https://github.com/lukmccall))
|
|
44
|
+
|
|
45
|
+
## 0.6.2 — 2021-12-15
|
|
46
|
+
|
|
47
|
+
### 🎉 New features
|
|
48
|
+
|
|
49
|
+
- Add `onNewIntent` and `onBackPressed` support to `ReactActivityLifecycleListener`. ([#15550](https://github.com/expo/expo/pull/15550) by [@Kudo](https://github.com/Kudo))
|
|
50
|
+
|
|
13
51
|
## 0.6.1 — 2021-12-08
|
|
14
52
|
|
|
15
53
|
_This version does not introduce any user-facing changes._
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ The core of Expo Modules architecture.
|
|
|
4
4
|
|
|
5
5
|
# Installation in managed Expo projects
|
|
6
6
|
|
|
7
|
-
For
|
|
7
|
+
For [managed](https://docs.expo.io/versions/latest/introduction/managed-vs-bare/) Expo projects, please follow the installation instructions in the [API documentation for the latest stable release](#api-documentation). If you follow the link and there is no documentation available then this library is not yet usable within managed projects — it is likely to be included in an upcoming Expo SDK release.
|
|
8
8
|
|
|
9
9
|
# Installation in bare React Native projects
|
|
10
10
|
|
package/android/build.gradle
CHANGED
|
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
|
|
|
3
3
|
apply plugin: 'maven'
|
|
4
4
|
|
|
5
5
|
group = 'host.exp.exponent'
|
|
6
|
-
version = '0.
|
|
6
|
+
version = '0.7.0'
|
|
7
7
|
|
|
8
8
|
buildscript {
|
|
9
9
|
// Simple helper that allows the root project to override versions declared by this library.
|
|
@@ -16,7 +16,7 @@ buildscript {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
dependencies {
|
|
19
|
-
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet('kotlinVersion', '1.
|
|
19
|
+
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet('kotlinVersion', '1.6.10')}")
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
@@ -58,7 +58,7 @@ android {
|
|
|
58
58
|
targetSdkVersion safeExtGet("targetSdkVersion", 30)
|
|
59
59
|
consumerProguardFiles 'proguard-rules.pro'
|
|
60
60
|
versionCode 1
|
|
61
|
-
versionName "0.
|
|
61
|
+
versionName "0.7.0"
|
|
62
62
|
}
|
|
63
63
|
lintOptions {
|
|
64
64
|
abortOnError false
|
|
@@ -81,8 +81,8 @@ android {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
dependencies {
|
|
84
|
-
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${safeExtGet('kotlinVersion', '1.
|
|
85
|
-
implementation "org.jetbrains.kotlin:kotlin-reflect:${safeExtGet('kotlinVersion', '1.
|
|
84
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${safeExtGet('kotlinVersion', '1.6.10')}"
|
|
85
|
+
implementation "org.jetbrains.kotlin:kotlin-reflect:${safeExtGet('kotlinVersion', '1.6.10')}"
|
|
86
86
|
implementation 'androidx.annotation:annotation:1.2.0'
|
|
87
87
|
|
|
88
88
|
// used only in `expo.modules.core.errors.ModuleDestroyedException` for API export
|
|
@@ -3,6 +3,7 @@ package expo.modules.adapters.react.apploader
|
|
|
3
3
|
import android.content.Context
|
|
4
4
|
import com.facebook.react.ReactApplication
|
|
5
5
|
import com.facebook.react.ReactInstanceManager
|
|
6
|
+
import com.facebook.react.common.LifecycleState
|
|
6
7
|
import expo.modules.apploader.HeadlessAppLoader
|
|
7
8
|
import expo.modules.core.interfaces.Consumer
|
|
8
9
|
import expo.modules.core.interfaces.DoNotStrip
|
|
@@ -43,7 +44,12 @@ class RNHeadlessAppLoader @DoNotStrip constructor(private val context: Context)
|
|
|
43
44
|
return if (appRecords.containsKey(appScopeKey) && appRecords[appScopeKey] != null) {
|
|
44
45
|
val appRecord: ReactInstanceManager = appRecords[appScopeKey]!!
|
|
45
46
|
android.os.Handler(context.mainLooper).post {
|
|
46
|
-
|
|
47
|
+
// Only destroy the `ReactInstanceManager` if it does not bind with an Activity.
|
|
48
|
+
// And The Activity would take over the ownership of `ReactInstanceManager`.
|
|
49
|
+
// This case happens when a user clicks a background task triggered notification immediately.
|
|
50
|
+
if (appRecord.lifecycleState == LifecycleState.BEFORE_CREATE) {
|
|
51
|
+
appRecord.destroy()
|
|
52
|
+
}
|
|
47
53
|
HeadlessAppLoaderNotifier.notifyAppDestroyed(appScopeKey)
|
|
48
54
|
appRecords.remove(appScopeKey)
|
|
49
55
|
}
|
package/android/src/main/java/expo/modules/core/interfaces/ReactActivityLifecycleListener.java
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package expo.modules.core.interfaces;
|
|
2
2
|
|
|
3
3
|
import android.app.Activity;
|
|
4
|
+
import android.content.Intent;
|
|
4
5
|
import android.os.Bundle;
|
|
5
6
|
|
|
6
7
|
public interface ReactActivityLifecycleListener {
|
|
@@ -11,4 +12,26 @@ public interface ReactActivityLifecycleListener {
|
|
|
11
12
|
default void onPause(Activity activity) {}
|
|
12
13
|
|
|
13
14
|
default void onDestroy(Activity activity) {}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Called when {@link com.facebook.react.ReactActivity} received `onNewIntent`
|
|
18
|
+
* Every listener will receive this callback.
|
|
19
|
+
* `ReactActivityDelegateWrapper.onNewIntent` will get `true` if there's some module returns `true`
|
|
20
|
+
*
|
|
21
|
+
* @return true if this module wants to return `true` from `ReactActivityDelegateWrapper.onNewIntent`
|
|
22
|
+
*/
|
|
23
|
+
default boolean onNewIntent(Intent intent) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Called when {@link com.facebook.react.ReactActivity} received `onBackPressed`
|
|
29
|
+
* Every listener will receive this callback.
|
|
30
|
+
* `ReactActivityDelegateWrapper.onBackPressed` will get `true` if there's some module returns `true`
|
|
31
|
+
*
|
|
32
|
+
* @return true if this module wants to return `true` from `ReactActivityDelegateWrapper.onBackPressed`
|
|
33
|
+
*/
|
|
34
|
+
default boolean onBackPressed() {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
14
37
|
}
|
|
@@ -15,6 +15,7 @@ import expo.modules.interfaces.imageloader.ImageLoaderInterface
|
|
|
15
15
|
import expo.modules.interfaces.permissions.Permissions
|
|
16
16
|
import expo.modules.interfaces.sensors.SensorServiceInterface
|
|
17
17
|
import expo.modules.interfaces.taskManager.TaskManagerInterface
|
|
18
|
+
import expo.modules.kotlin.defaultmodules.ErrorManagerModule
|
|
18
19
|
import expo.modules.kotlin.events.EventName
|
|
19
20
|
import expo.modules.kotlin.events.KEventEmitterWrapper
|
|
20
21
|
import expo.modules.kotlin.events.OnActivityResultPayload
|
|
@@ -26,7 +27,10 @@ class AppContext(
|
|
|
26
27
|
val legacyModuleRegistry: expo.modules.core.ModuleRegistry,
|
|
27
28
|
private val reactContextHolder: WeakReference<ReactApplicationContext>
|
|
28
29
|
) {
|
|
29
|
-
val registry = ModuleRegistry(WeakReference(this)).
|
|
30
|
+
val registry = ModuleRegistry(WeakReference(this)).apply {
|
|
31
|
+
register(ErrorManagerModule())
|
|
32
|
+
register(modulesProvider)
|
|
33
|
+
}
|
|
30
34
|
private val reactLifecycleDelegate = ReactLifecycleDelegate(this)
|
|
31
35
|
|
|
32
36
|
init {
|
|
@@ -128,6 +132,12 @@ class AppContext(
|
|
|
128
132
|
)
|
|
129
133
|
}
|
|
130
134
|
|
|
135
|
+
internal val callbackInvoker: EventEmitter?
|
|
136
|
+
get() = legacyModule()
|
|
137
|
+
|
|
138
|
+
internal val errorManager: ErrorManagerModule?
|
|
139
|
+
get() = registry.getModule()
|
|
140
|
+
|
|
131
141
|
fun onDestroy() {
|
|
132
142
|
reactContextHolder.get()?.removeLifecycleEventListener(reactLifecycleDelegate)
|
|
133
143
|
registry.post(EventName.MODULE_DESTROY)
|
|
@@ -3,7 +3,9 @@ package expo.modules.kotlin
|
|
|
3
3
|
import com.facebook.react.bridge.Dynamic
|
|
4
4
|
|
|
5
5
|
inline fun <T> Dynamic.recycle(block: Dynamic.() -> T): T {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
try {
|
|
7
|
+
return block(this)
|
|
8
|
+
} finally {
|
|
9
|
+
this.recycle()
|
|
10
|
+
}
|
|
9
11
|
}
|
|
@@ -2,17 +2,23 @@ package expo.modules.kotlin
|
|
|
2
2
|
|
|
3
3
|
import android.os.Bundle
|
|
4
4
|
import com.facebook.react.bridge.Arguments
|
|
5
|
+
import expo.modules.kotlin.records.Record
|
|
6
|
+
import expo.modules.kotlin.records.toJSMap
|
|
5
7
|
|
|
6
8
|
class KPromiseWrapper(
|
|
7
9
|
private val bridgePromise: com.facebook.react.bridge.Promise
|
|
8
10
|
) : Promise {
|
|
9
11
|
|
|
12
|
+
@Suppress("UNCHECKED_CAST")
|
|
10
13
|
override fun resolve(value: Any?) {
|
|
11
14
|
bridgePromise.resolve(
|
|
12
15
|
when (value) {
|
|
13
16
|
is Unit -> null
|
|
14
|
-
is Bundle -> Arguments.fromBundle(value
|
|
15
|
-
is List<*> -> Arguments.fromList(value
|
|
17
|
+
is Bundle -> Arguments.fromBundle(value)
|
|
18
|
+
is List<*> -> Arguments.fromList(value)
|
|
19
|
+
is Array<*> -> Arguments.fromArray(value)
|
|
20
|
+
is Map<*, *> -> Arguments.makeNativeMap(value as Map<String, Any?>) // TODO(@lukmccall): add more sophisticated conversion method
|
|
21
|
+
is Record -> value.toJSMap()
|
|
16
22
|
else -> value
|
|
17
23
|
}
|
|
18
24
|
)
|
|
@@ -3,6 +3,8 @@ package expo.modules.kotlin
|
|
|
3
3
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
4
4
|
import com.facebook.react.bridge.ReadableArray
|
|
5
5
|
import com.facebook.react.uimanager.ViewManager
|
|
6
|
+
import expo.modules.kotlin.exception.CodedException
|
|
7
|
+
import expo.modules.kotlin.exception.UnexpectedException
|
|
6
8
|
import expo.modules.kotlin.views.GroupViewManagerWrapper
|
|
7
9
|
import expo.modules.kotlin.views.SimpleViewManagerWrapper
|
|
8
10
|
import expo.modules.kotlin.views.ViewManagerWrapperDelegate
|
|
@@ -18,7 +20,7 @@ class KotlinInteropModuleRegistry(
|
|
|
18
20
|
legacyModuleRegistry: expo.modules.core.ModuleRegistry,
|
|
19
21
|
reactContext: WeakReference<ReactApplicationContext>
|
|
20
22
|
) {
|
|
21
|
-
|
|
23
|
+
internal val appContext = AppContext(modulesProvider, legacyModuleRegistry, reactContext)
|
|
22
24
|
|
|
23
25
|
private val registry: ModuleRegistry
|
|
24
26
|
get() = appContext.registry
|
|
@@ -26,9 +28,16 @@ class KotlinInteropModuleRegistry(
|
|
|
26
28
|
fun hasModule(name: String): Boolean = registry.hasModule(name)
|
|
27
29
|
|
|
28
30
|
fun callMethod(moduleName: String, method: String, arguments: ReadableArray, promise: Promise) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
try {
|
|
32
|
+
requireNotNull(
|
|
33
|
+
registry.getModuleHolder(moduleName)
|
|
34
|
+
) { "Trying to call '$method' on the non-existing module '$moduleName'" }
|
|
35
|
+
.call(method, arguments, promise)
|
|
36
|
+
} catch (e: CodedException) {
|
|
37
|
+
promise.reject(e)
|
|
38
|
+
} catch (e: Throwable) {
|
|
39
|
+
promise.reject(UnexpectedException(e))
|
|
40
|
+
}
|
|
32
41
|
}
|
|
33
42
|
|
|
34
43
|
fun exportedModulesConstants(): Map<ModuleName, ModuleConstants> {
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
package expo.modules.kotlin
|
|
2
2
|
|
|
3
3
|
import com.facebook.react.bridge.ReadableArray
|
|
4
|
-
import expo.modules.core.utilities.ifNull
|
|
5
4
|
import expo.modules.kotlin.events.BasicEventListener
|
|
6
5
|
import expo.modules.kotlin.events.EventListenerWithPayload
|
|
7
6
|
import expo.modules.kotlin.events.EventListenerWithSenderAndPayload
|
|
8
7
|
import expo.modules.kotlin.events.EventName
|
|
8
|
+
import expo.modules.kotlin.exception.FunctionCallException
|
|
9
9
|
import expo.modules.kotlin.exception.MethodNotFoundException
|
|
10
|
+
import expo.modules.kotlin.exception.exceptionDecorator
|
|
10
11
|
import expo.modules.kotlin.modules.Module
|
|
11
12
|
|
|
12
13
|
class ModuleHolder(val module: Module) {
|
|
13
14
|
val definition = module.definition()
|
|
14
15
|
val name get() = definition.name
|
|
15
16
|
|
|
16
|
-
fun call(methodName: String, args: ReadableArray, promise: Promise) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
fun call(methodName: String, args: ReadableArray, promise: Promise) = exceptionDecorator({
|
|
18
|
+
FunctionCallException(methodName, definition.name, it)
|
|
19
|
+
}) {
|
|
20
|
+
val method = definition.methods[methodName]
|
|
21
|
+
?: throw MethodNotFoundException()
|
|
21
22
|
|
|
22
23
|
method.call(args, promise)
|
|
23
24
|
}
|
|
@@ -7,7 +7,8 @@ import java.lang.ref.WeakReference
|
|
|
7
7
|
class ModuleRegistry(
|
|
8
8
|
private val appContext: WeakReference<AppContext>
|
|
9
9
|
) : Iterable<ModuleHolder> {
|
|
10
|
-
|
|
10
|
+
@PublishedApi
|
|
11
|
+
internal val registry = mutableMapOf<String, ModuleHolder>()
|
|
11
12
|
|
|
12
13
|
fun register(module: Module) {
|
|
13
14
|
val holder = ModuleHolder(module)
|
|
@@ -27,6 +28,10 @@ class ModuleRegistry(
|
|
|
27
28
|
|
|
28
29
|
fun getModule(name: String): Module? = registry[name]?.module
|
|
29
30
|
|
|
31
|
+
inline fun <reified T> getModule(): T? {
|
|
32
|
+
return registry.values.find { it.module is T }?.module as? T
|
|
33
|
+
}
|
|
34
|
+
|
|
30
35
|
fun getModuleHolder(name: String): ModuleHolder? = registry[name]
|
|
31
36
|
|
|
32
37
|
fun getModuleHolder(module: Module): ModuleHolder? =
|
|
@@ -8,6 +8,6 @@ interface Promise {
|
|
|
8
8
|
fun reject(code: String, message: String?, cause: Throwable?)
|
|
9
9
|
|
|
10
10
|
fun reject(exception: CodedException) {
|
|
11
|
-
reject(exception.code, exception.
|
|
11
|
+
reject(exception.code, exception.localizedMessage, exception.cause)
|
|
12
12
|
}
|
|
13
13
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
package expo.modules.kotlin.callbacks
|
|
2
|
+
|
|
3
|
+
import android.os.Bundle
|
|
4
|
+
import android.view.View
|
|
5
|
+
import com.facebook.react.bridge.ReactContext
|
|
6
|
+
import expo.modules.adapters.react.NativeModulesProxy
|
|
7
|
+
import expo.modules.kotlin.modules.Module
|
|
8
|
+
import kotlin.reflect.KType
|
|
9
|
+
|
|
10
|
+
class ViewCallback<T>(
|
|
11
|
+
private val name: String,
|
|
12
|
+
private val type: KType,
|
|
13
|
+
private val view: View
|
|
14
|
+
) : Callback<T> {
|
|
15
|
+
internal lateinit var module: Module
|
|
16
|
+
|
|
17
|
+
override operator fun invoke(arg: T) {
|
|
18
|
+
val reactContext = view.context as ReactContext
|
|
19
|
+
val nativeModulesProxy = reactContext
|
|
20
|
+
.catalystInstance
|
|
21
|
+
?.getNativeModule("NativeUnimoduleProxy") as? NativeModulesProxy
|
|
22
|
+
?: return
|
|
23
|
+
val appContext = nativeModulesProxy.kotlinInteropModuleRegistry.appContext
|
|
24
|
+
|
|
25
|
+
// TODO(@lukmccall): handles other types
|
|
26
|
+
appContext.callbackInvoker?.emit(view.id, name, arg as Bundle)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
@file:OptIn(ExperimentalStdlibApi::class)
|
|
2
|
+
|
|
3
|
+
package expo.modules.kotlin.callbacks
|
|
4
|
+
|
|
5
|
+
import android.view.View
|
|
6
|
+
import java.lang.ref.WeakReference
|
|
7
|
+
import kotlin.reflect.KProperty
|
|
8
|
+
import kotlin.reflect.KType
|
|
9
|
+
import kotlin.reflect.typeOf
|
|
10
|
+
|
|
11
|
+
class ViewCallbackDelegate<T>(private val type: KType, view: View) {
|
|
12
|
+
private val viewHolder = WeakReference(view)
|
|
13
|
+
internal var isValidated = false
|
|
14
|
+
|
|
15
|
+
operator fun getValue(thisRef: View, property: KProperty<*>): Callback<T> {
|
|
16
|
+
if (!isValidated) {
|
|
17
|
+
throw IllegalStateException("You have to export this property as a callback in the `ViewManager`.")
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
val view = viewHolder.get() ?: throw IllegalStateException("Can't send an event from the view that is deallocated.")
|
|
21
|
+
return ViewCallback(property.name, type, view)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
inline fun <reified T> View.callback(): ViewCallbackDelegate<T> {
|
|
26
|
+
return ViewCallbackDelegate(typeOf<T>(), this)
|
|
27
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
package expo.modules.kotlin.defaultmodules
|
|
2
|
+
|
|
3
|
+
import android.os.Bundle
|
|
4
|
+
import expo.modules.kotlin.exception.CodedException
|
|
5
|
+
import expo.modules.kotlin.modules.Module
|
|
6
|
+
import expo.modules.kotlin.modules.ModuleDefinition
|
|
7
|
+
|
|
8
|
+
private const val onNewException = "ExpoModulesCoreErrorManager.onNewException"
|
|
9
|
+
|
|
10
|
+
class ErrorManagerModule : Module() {
|
|
11
|
+
override fun definition() = ModuleDefinition {
|
|
12
|
+
name("ExpoModulesCoreErrorManager")
|
|
13
|
+
events(onNewException)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
fun reportExceptionToLogBox(codedException: CodedException) {
|
|
17
|
+
val eventEmitter = appContext.eventEmitter(this) ?: return
|
|
18
|
+
eventEmitter.emit(
|
|
19
|
+
onNewException,
|
|
20
|
+
Bundle().apply {
|
|
21
|
+
putString("message", codedException.message ?: codedException.toString())
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package expo.modules.kotlin.exception
|
|
2
2
|
|
|
3
|
+
import com.facebook.react.bridge.ReadableType
|
|
3
4
|
import java.util.*
|
|
4
5
|
import kotlin.reflect.KType
|
|
5
6
|
|
|
@@ -17,7 +18,7 @@ open class CodedException(
|
|
|
17
18
|
val code
|
|
18
19
|
get() = providedCode ?: inferCode(javaClass)
|
|
19
20
|
|
|
20
|
-
constructor(code: String, message: String
|
|
21
|
+
constructor(code: String, message: String?, cause: Throwable?) : this(message, cause) {
|
|
21
22
|
providedCode = code
|
|
22
23
|
}
|
|
23
24
|
|
|
@@ -47,24 +48,83 @@ internal class IncompatibleArgTypeException(
|
|
|
47
48
|
desiredType: KType,
|
|
48
49
|
cause: Throwable? = null
|
|
49
50
|
) : CodedException(
|
|
50
|
-
message = "Argument type $argumentType is not compatible with expected type $desiredType.",
|
|
51
|
+
message = "Argument type '$argumentType' is not compatible with expected type '$desiredType'.",
|
|
51
52
|
cause = cause
|
|
52
53
|
)
|
|
53
54
|
|
|
54
55
|
internal class MissingTypeConverter(
|
|
55
56
|
forType: KType
|
|
56
57
|
) : CodedException(
|
|
57
|
-
message = "Cannot find type converter for $forType.",
|
|
58
|
+
message = "Cannot find type converter for '$forType'.",
|
|
58
59
|
)
|
|
59
60
|
|
|
60
61
|
internal class InvalidArgsNumberException(received: Int, expected: Int) :
|
|
61
62
|
CodedException(message = "Received $received arguments, but $expected was expected.")
|
|
62
63
|
|
|
63
|
-
internal class MethodNotFoundException
|
|
64
|
-
CodedException(message = "
|
|
64
|
+
internal class MethodNotFoundException :
|
|
65
|
+
CodedException(message = "Method does not exist.")
|
|
65
66
|
|
|
66
|
-
internal class NullArgumentException
|
|
67
|
-
CodedException(message = "Cannot assigned null to not nullable type
|
|
67
|
+
internal class NullArgumentException :
|
|
68
|
+
CodedException(message = "Cannot assigned null to not nullable type.")
|
|
68
69
|
|
|
69
70
|
internal class UnexpectedException(val throwable: Throwable) :
|
|
70
|
-
CodedException(throwable)
|
|
71
|
+
CodedException(message = throwable.toString(), throwable)
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* A base class for all exceptions used in `exceptionDecorator` function.
|
|
75
|
+
*/
|
|
76
|
+
internal open class DecoratedException(
|
|
77
|
+
message: String,
|
|
78
|
+
cause: CodedException,
|
|
79
|
+
) : CodedException(
|
|
80
|
+
cause.code,
|
|
81
|
+
message = "$message${System.lineSeparator()}→ Caused by: ${cause.localizedMessage ?: cause}",
|
|
82
|
+
cause
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
internal class FunctionCallException(
|
|
86
|
+
methodName: String,
|
|
87
|
+
moduleName: String,
|
|
88
|
+
cause: CodedException
|
|
89
|
+
) : DecoratedException(
|
|
90
|
+
message = "Call to function '$moduleName.$methodName' has been rejected.",
|
|
91
|
+
cause,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
internal class ArgumentCastException(
|
|
95
|
+
argDesiredType: KType,
|
|
96
|
+
argIndex: Int,
|
|
97
|
+
providedType: ReadableType,
|
|
98
|
+
cause: CodedException,
|
|
99
|
+
) : DecoratedException(
|
|
100
|
+
message = "Argument at index '$argIndex' couldn't be casted to type '$argDesiredType' (received '$providedType').",
|
|
101
|
+
cause,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
internal class FieldCastException(
|
|
105
|
+
fieldName: String,
|
|
106
|
+
fieldType: KType,
|
|
107
|
+
providedType: ReadableType,
|
|
108
|
+
cause: CodedException
|
|
109
|
+
) : DecoratedException(
|
|
110
|
+
message = "Cannot cast '${providedType.name}' for field '$fieldName' ('$fieldType').",
|
|
111
|
+
cause
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
internal class RecordCastException(
|
|
115
|
+
recordType: KType,
|
|
116
|
+
cause: CodedException
|
|
117
|
+
) : DecoratedException(
|
|
118
|
+
message = "Cannot create a record of the type: '$recordType'.",
|
|
119
|
+
cause
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
internal class CollectionElementCastException(
|
|
123
|
+
collectionType: KType,
|
|
124
|
+
elementType: KType,
|
|
125
|
+
providedType: ReadableType,
|
|
126
|
+
cause: CodedException
|
|
127
|
+
) : DecoratedException(
|
|
128
|
+
message = "Cannot cast '${providedType.name}' to '$elementType' required by the collection of type: '$collectionType'.",
|
|
129
|
+
cause
|
|
130
|
+
)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
package expo.modules.kotlin.exception
|
|
2
|
+
|
|
3
|
+
internal inline fun <T> exceptionDecorator(decoratorBlock: (e: CodedException) -> Throwable, block: () -> T): T {
|
|
4
|
+
return try {
|
|
5
|
+
block()
|
|
6
|
+
} catch (e: CodedException) {
|
|
7
|
+
throw decoratorBlock(e)
|
|
8
|
+
} catch (e: Throwable) {
|
|
9
|
+
throw decoratorBlock(UnexpectedException(e))
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -2,31 +2,26 @@ package expo.modules.kotlin.methods
|
|
|
2
2
|
|
|
3
3
|
import com.facebook.react.bridge.ReadableArray
|
|
4
4
|
import expo.modules.kotlin.Promise
|
|
5
|
+
import expo.modules.kotlin.exception.ArgumentCastException
|
|
5
6
|
import expo.modules.kotlin.exception.CodedException
|
|
6
7
|
import expo.modules.kotlin.exception.InvalidArgsNumberException
|
|
7
|
-
import expo.modules.kotlin.exception.
|
|
8
|
+
import expo.modules.kotlin.exception.exceptionDecorator
|
|
8
9
|
import expo.modules.kotlin.iterator
|
|
9
10
|
import expo.modules.kotlin.recycle
|
|
10
11
|
import expo.modules.kotlin.types.AnyType
|
|
11
|
-
import kotlin.jvm.Throws
|
|
12
12
|
|
|
13
13
|
abstract class AnyMethod(
|
|
14
14
|
protected val name: String,
|
|
15
15
|
private val desiredArgsTypes: Array<AnyType>
|
|
16
16
|
) {
|
|
17
|
+
@Throws(CodedException::class)
|
|
17
18
|
fun call(args: ReadableArray, promise: Promise) {
|
|
18
19
|
if (desiredArgsTypes.size != args.size()) {
|
|
19
|
-
|
|
20
|
-
return
|
|
21
|
-
}
|
|
22
|
-
try {
|
|
23
|
-
val convertedArgs = convertArgs(args)
|
|
24
|
-
callImplementation(convertedArgs, promise)
|
|
25
|
-
} catch (codedError: CodedException) {
|
|
26
|
-
promise.reject(codedError)
|
|
27
|
-
} catch (e: Throwable) {
|
|
28
|
-
promise.reject(UnexpectedException(e))
|
|
20
|
+
throw InvalidArgsNumberException(args.size(), desiredArgsTypes.size)
|
|
29
21
|
}
|
|
22
|
+
|
|
23
|
+
val convertedArgs = convertArgs(args)
|
|
24
|
+
callImplementation(convertedArgs, promise)
|
|
30
25
|
}
|
|
31
26
|
|
|
32
27
|
@Throws(CodedException::class)
|
|
@@ -40,9 +35,13 @@ abstract class AnyMethod(
|
|
|
40
35
|
val argIterator = args.iterator()
|
|
41
36
|
desiredArgsTypes
|
|
42
37
|
.withIndex()
|
|
43
|
-
.forEach { (index,
|
|
38
|
+
.forEach { (index, desiredType) ->
|
|
44
39
|
argIterator.next().recycle {
|
|
45
|
-
|
|
40
|
+
exceptionDecorator({ cause ->
|
|
41
|
+
ArgumentCastException(desiredType.kType, index, type, cause)
|
|
42
|
+
}) {
|
|
43
|
+
finalArgs[index] = desiredType.convert(this)
|
|
44
|
+
}
|
|
46
45
|
}
|
|
47
46
|
}
|
|
48
47
|
return finalArgs
|
|
@@ -4,6 +4,7 @@ import android.os.Bundle
|
|
|
4
4
|
import expo.modules.kotlin.AppContext
|
|
5
5
|
|
|
6
6
|
abstract class Module {
|
|
7
|
+
@Suppress("PropertyName")
|
|
7
8
|
internal var _appContext: AppContext? = null
|
|
8
9
|
|
|
9
10
|
private val moduleEventEmitter by lazy { appContext.eventEmitter(this) }
|
|
@@ -19,6 +20,6 @@ abstract class Module {
|
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
@Suppress("FunctionName")
|
|
22
|
-
inline fun ModuleDefinition(block: ModuleDefinitionBuilder.() -> Unit): ModuleDefinitionData {
|
|
23
|
-
return ModuleDefinitionBuilder().also(block).build()
|
|
23
|
+
inline fun Module.ModuleDefinition(block: ModuleDefinitionBuilder.() -> Unit): ModuleDefinitionData {
|
|
24
|
+
return ModuleDefinitionBuilder(this).also(block).build()
|
|
24
25
|
}
|