expo-modules-core 2.0.0-preview.0 → 2.0.0-preview.10
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 +71 -0
- package/ExpoModulesCore.podspec +15 -2
- package/android/build.gradle +3 -3
- package/android/src/main/java/expo/modules/adapters/react/apploader/RNHeadlessAppLoader.kt +68 -21
- package/android/src/main/java/expo/modules/adapters/react/permissions/PermissionsService.kt +14 -5
- package/android/src/main/java/expo/modules/adapters/react/services/EventEmitterModule.java +2 -0
- package/android/src/main/java/expo/modules/adapters/react/services/UIManagerModuleWrapper.java +5 -0
- package/android/src/main/java/expo/modules/core/ModulePriorities.kt +1 -1
- package/android/src/main/java/expo/modules/core/ModuleRegistry.java +1 -0
- package/android/src/main/java/expo/modules/core/arguments/ReadableArguments.java +1 -0
- package/android/src/main/java/expo/modules/interfaces/taskManager/TaskServiceProviderHelper.kt +41 -0
- package/android/src/main/java/expo/modules/interfaces/taskManager/TaskServiceProviderInterface.java +18 -0
- package/android/src/main/java/expo/modules/kotlin/Promise.kt +6 -6
- package/android/src/main/java/expo/modules/kotlin/classcomponent/ClassComponentBuilder.kt +2 -2
- package/android/src/main/java/expo/modules/kotlin/devtools/ExpoRequestCdpInterceptor.kt +4 -3
- package/android/src/main/java/expo/modules/kotlin/events/EventEmitter.kt +2 -0
- package/android/src/main/java/expo/modules/kotlin/events/KModuleEventEmitterWrapper.kt +12 -2
- package/android/src/main/java/expo/modules/kotlin/exception/CommonExceptions.kt +16 -0
- package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +0 -22
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleUtils.kt +25 -0
- package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +15 -0
- package/android/src/main/java/expo/modules/kotlin/sharedobjects/SharedObject.kt +1 -0
- package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverterHelper.kt +1 -0
- package/android/src/main/java/expo/modules/kotlin/viewevent/ViewEvent.kt +1 -1
- package/android/src/main/java/expo/modules/kotlin/views/ExpoView.kt +37 -1
- package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +2 -14
- package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +2 -14
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +11 -12
- package/build/ts-declarations/global.d.ts +17 -16
- package/build/ts-declarations/global.d.ts.map +1 -1
- package/ios/AppDelegates/EXAppDelegateWrapper.mm +0 -3
- package/ios/Core/{Convertibles → Arguments}/Either.swift +29 -12
- package/ios/Core/DynamicTypes/DynamicEitherType.swift +47 -0
- package/ios/Core/DynamicTypes/DynamicEnumType.swift +4 -0
- package/ios/Core/DynamicTypes/DynamicOptionalType.swift +1 -1
- package/ios/Core/Modules/CoreModule.swift +2 -2
- package/ios/Core/Protocols/AnyExpoView.swift +6 -0
- package/ios/Core/SharedObjects/SharedRef.swift +1 -1
- package/ios/Core/Views/ComponentData.swift +1 -1
- package/ios/Core/Views/ExpoView.swift +9 -0
- package/ios/Core/Views/SwiftUI/SwiftUIHostingView.swift +28 -8
- package/ios/Core/Views/SwiftUI/SwiftUIViewDefinition.swift +1 -1
- package/ios/DevTools/ExpoRequestCdpInterceptor.swift +1 -1
- package/ios/DevTools/ExpoRequestInterceptorProtocol.swift +11 -0
- package/ios/DevTools/URLAuthenticationChallengeForwardSender.swift +33 -0
- package/ios/DevTools/URLSessionSessionDelegateProxy.swift +15 -0
- package/ios/Legacy/NativeModulesProxy/EXNativeModulesProxy.mm +5 -1
- package/ios/Tests/DynamicEitherTypeSpec.swift +93 -0
- package/ios/Tests/DynamicTypeSpec.swift +18 -0
- package/ios/Tests/EitherSpec.swift +0 -44
- package/package.json +2 -2
- package/src/ts-declarations/global.ts +22 -20
- package/ios/Interfaces/BarcodeScanner/EXBarcodeScannerInterface.h +0 -22
- package/ios/Interfaces/BarcodeScanner/EXBarcodeScannerProviderInterface.h +0 -9
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,73 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 2.0.0-preview.10 — 2024-11-07
|
|
14
|
+
|
|
15
|
+
### 🐛 Bug fixes
|
|
16
|
+
|
|
17
|
+
- [iOS] Fixed broken self-signed connections from network inspector. ([#32670](https://github.com/expo/expo/pull/32670) by [@kudo](https://github.com/kudo))
|
|
18
|
+
|
|
19
|
+
## 2.0.0-preview.9 — 2024-10-31
|
|
20
|
+
|
|
21
|
+
### 💡 Others
|
|
22
|
+
|
|
23
|
+
- [Android] Fix `ClassCastException` in headless app loader under the old architecture. ([#32390](https://github.com/expo/expo/pull/32390) by [@robertying](https://github.com/robertying))
|
|
24
|
+
|
|
25
|
+
## 2.0.0-preview.8 — 2024-10-31
|
|
26
|
+
|
|
27
|
+
### 🛠 Breaking changes
|
|
28
|
+
|
|
29
|
+
- Remove expo barcode scanner interface. ([#32198](https://github.com/expo/expo/pull/32198) by [@aleqsio](https://github.com/aleqsio))
|
|
30
|
+
|
|
31
|
+
### 💡 Others
|
|
32
|
+
|
|
33
|
+
- [android] Added helper for looking up TaskService instance used by expo-task-manager ([#32300](https://github.com/expo/expo/pull/32300) by [@chrfalch](https://github.com/chrfalch))
|
|
34
|
+
- Made TypeScript declaration for `process` an interface. ([#32464](https://github.com/expo/expo/pull/32464) by [@tsapeta](https://github.com/tsapeta))
|
|
35
|
+
|
|
36
|
+
## 2.0.0-preview.7 — 2024-10-29
|
|
37
|
+
|
|
38
|
+
### 💡 Others
|
|
39
|
+
|
|
40
|
+
- [Android] Added `shouldUseAndroidLayout` flag to `ExpoView`. ([#32446](https://github.com/expo/expo/pull/32446) by [@lukmccall](https://github.com/lukmccall))
|
|
41
|
+
|
|
42
|
+
## 2.0.0-preview.6 — 2024-10-29
|
|
43
|
+
|
|
44
|
+
_This version does not introduce any user-facing changes._
|
|
45
|
+
|
|
46
|
+
## 2.0.0-preview.5 — 2024-10-28
|
|
47
|
+
|
|
48
|
+
### 🐛 Bug fixes
|
|
49
|
+
|
|
50
|
+
- Fixed updating props on SwiftUI views on the New Architecture. ([#32381](https://github.com/expo/expo/pull/32381) by [@tsapeta](https://github.com/tsapeta))
|
|
51
|
+
- Fixed build error when `use_frameworks!`. ([#32358](https://github.com/expo/expo/pull/32358) by [@kudo](https://github.com/kudo))
|
|
52
|
+
|
|
53
|
+
## 2.0.0-preview.4 — 2024-10-25
|
|
54
|
+
|
|
55
|
+
### 💡 Others
|
|
56
|
+
|
|
57
|
+
- Added a new dynamic type dedicated for Either types. ([#32328](https://github.com/expo/expo/pull/32328) by [@tsapeta](https://github.com/tsapeta))
|
|
58
|
+
|
|
59
|
+
## 2.0.0-preview.3 — 2024-10-24
|
|
60
|
+
|
|
61
|
+
_This version does not introduce any user-facing changes._
|
|
62
|
+
|
|
63
|
+
## 2.0.0-preview.2 — 2024-10-24
|
|
64
|
+
|
|
65
|
+
### 🐛 Bug fixes
|
|
66
|
+
|
|
67
|
+
- [iOS] Fix optionals conversion. ([#32239](https://github.com/expo/expo/pull/32239) by [@aleqsio](https://github.com/aleqsio))
|
|
68
|
+
- Fixed retain cycle for `ExpoRequestCdpInterceptor`. ([#32289](https://github.com/expo/expo/pull/32289) by [@kudo](https://github.com/kudo))
|
|
69
|
+
|
|
70
|
+
### 💡 Others
|
|
71
|
+
|
|
72
|
+
- [android] Add enum event support to OnStartObserving and OnStopObserving. ([#32251](https://github.com/expo/expo/pull/32251), [#32287](https://github.com/expo/expo/pull/32287) by [@wschurman](https://github.com/wschurman))
|
|
73
|
+
|
|
74
|
+
## 2.0.0-preview.1 — 2024-10-22
|
|
75
|
+
|
|
76
|
+
### 🐛 Bug fixes
|
|
77
|
+
|
|
78
|
+
- [iOS] Removed window synthesis in `EXAppDelegateWrapper` to fix crashes caused by deallocated `RCTFabricSurface`. ([#32233](https://github.com/expo/expo/pull/32233) by [@tsapeta](https://github.com/tsapeta))
|
|
79
|
+
|
|
13
80
|
## 2.0.0-preview.0 — 2024-10-22
|
|
14
81
|
|
|
15
82
|
### 🛠 Breaking changes
|
|
@@ -50,6 +117,8 @@
|
|
|
50
117
|
|
|
51
118
|
### 🐛 Bug fixes
|
|
52
119
|
|
|
120
|
+
- [Android] Fixed `RNHeadlessAppLoader` class for New Architecture support. ([#32146](https://github.com/expo/expo/pull/32146) by [@chrfalch](https://github.com/chrfalch))
|
|
121
|
+
- [iOS] Fix using enums as optional arguments. ([#32147](https://github.com/expo/expo/pull/32147) by [@aleqsio](https://github.com/aleqsio))
|
|
53
122
|
- [Android] Change JS return type for kotlin `null` to be `null` instead of `undefined`. ([#31301](https://github.com/expo/expo/pull/31301) by [@aleqsio](https://github.com/aleqsio))
|
|
54
123
|
- [iOS] Swift `Enumerable`s did not correctly convert to JS values. ([#30191](https://github.com/expo/expo/pull/30191) by [@vonovak](https://github.com/vonovak))
|
|
55
124
|
- [jest] Fix `uuid` mock in `jest-expo`. ([#29840](https://github.com/expo/expo/pull/29840) by [@EvanBacon](https://github.com/EvanBacon))
|
|
@@ -75,6 +144,7 @@
|
|
|
75
144
|
- Fixed iOS reload crash on New Architecture mode. ([#31789](https://github.com/expo/expo/pull/31789) by [@kudo](https://github.com/kudo))
|
|
76
145
|
- [iOS] Fixed views using the incorrect `AppContext` instance. ([#31897](https://github.com/expo/expo/pull/31897) by [@lukmccall](https://github.com/lukmccall))
|
|
77
146
|
- [iOS] Fixed crashes on the New Architecture when dispatching events during the props update. ([#31971](https://github.com/expo/expo/pull/31971) by [@tsapeta](https://github.com/tsapeta))
|
|
147
|
+
- Fixed `registerAdditionalModuleClasses` deadlock issue on old architecture mode. ([#32209](https://github.com/expo/expo/pull/32209) by [@kudo](https://github.com/kudo))
|
|
78
148
|
|
|
79
149
|
### 💡 Others
|
|
80
150
|
|
|
@@ -118,6 +188,7 @@
|
|
|
118
188
|
- [Android] Renamed `SharedObject.deallocate` to `SharedObject.sharedObjectDidRelease`. ([#31921](https://github.com/expo/expo/pull/31921) by [@lukmccall](https://github.com/lukmccall))
|
|
119
189
|
- [Android] Throws a descriptive error when trying to use a released `SharedObject`. ([#31922](https://github.com/expo/expo/pull/31922) by [@lukmccall](https://github.com/lukmccall))
|
|
120
190
|
- Include error cause message in logger ([#31929](https://github.com/expo/expo/pull/31929), [#31953](https://github.com/expo/expo/pull/31953) by [@wschurman](https://github.com/wschurman))
|
|
191
|
+
- [Android] Started using view's event dispatchers with the `surfaceId`. ([#32227](https://github.com/expo/expo/pull/32227) by [@lukmccall](https://github.com/lukmccall))
|
|
121
192
|
|
|
122
193
|
### ⚠️ Notices
|
|
123
194
|
|
package/ExpoModulesCore.podspec
CHANGED
|
@@ -47,19 +47,32 @@ Pod::Spec.new do |s|
|
|
|
47
47
|
s.static_framework = true
|
|
48
48
|
s.header_dir = 'ExpoModulesCore'
|
|
49
49
|
|
|
50
|
+
header_search_paths = []
|
|
51
|
+
if ENV['USE_FRAMEWORKS']
|
|
52
|
+
header_search_paths.concat([
|
|
53
|
+
# [begin] transitive dependencies of React-RCTAppDelegate that are not defined modules
|
|
54
|
+
'"${PODS_CONFIGURATION_BUILD_DIR}/React-RuntimeApple/React_RuntimeApple.framework/Headers"',
|
|
55
|
+
'"${PODS_CONFIGURATION_BUILD_DIR}/React-RuntimeCore/React_RuntimeCore.framework/Headers"',
|
|
56
|
+
'"${PODS_CONFIGURATION_BUILD_DIR}/React-jserrorhandler/React_jserrorhandler.framework/Headers"',
|
|
57
|
+
'"${PODS_CONFIGURATION_BUILD_DIR}/React-runtimescheduler/React_runtimescheduler.framework/Headers"',
|
|
58
|
+
'"${PODS_CONFIGURATION_BUILD_DIR}/React-performancetimeline/React_performancetimeline.framework/Headers"',
|
|
59
|
+
'"${PODS_CONFIGURATION_BUILD_DIR}/React-rendererconsistency/React_rendererconsistency.framework/Headers"',
|
|
60
|
+
# [end] transitive dependencies of React-RCTAppDelegate that are not defined modules
|
|
61
|
+
])
|
|
62
|
+
end
|
|
50
63
|
# Swift/Objective-C compatibility
|
|
51
64
|
s.pod_target_xcconfig = {
|
|
52
65
|
'USE_HEADERMAP' => 'YES',
|
|
53
66
|
'DEFINES_MODULE' => 'YES',
|
|
54
67
|
'CLANG_CXX_LANGUAGE_STANDARD' => 'c++20',
|
|
55
68
|
'SWIFT_COMPILATION_MODE' => 'wholemodule',
|
|
56
|
-
'OTHER_SWIFT_FLAGS' => "$(inherited) #{new_arch_enabled ? new_arch_compiler_flags : ''}"
|
|
69
|
+
'OTHER_SWIFT_FLAGS' => "$(inherited) #{new_arch_enabled ? new_arch_compiler_flags : ''}",
|
|
70
|
+
'HEADER_SEARCH_PATHS' => header_search_paths.join(' '),
|
|
57
71
|
}
|
|
58
72
|
s.user_target_xcconfig = {
|
|
59
73
|
"HEADER_SEARCH_PATHS" => [
|
|
60
74
|
'"${PODS_CONFIGURATION_BUILD_DIR}/ExpoModulesCore/Swift Compatibility Header"',
|
|
61
75
|
'"$(PODS_ROOT)/Headers/Private/Yoga"', # Expo.h -> ExpoModulesCore-umbrella.h -> Fabric ViewProps.h -> Private Yoga headers
|
|
62
|
-
|
|
63
76
|
],
|
|
64
77
|
}
|
|
65
78
|
|
package/android/build.gradle
CHANGED
|
@@ -3,7 +3,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
|
|
3
3
|
apply plugin: 'com.android.library'
|
|
4
4
|
|
|
5
5
|
group = 'host.exp.exponent'
|
|
6
|
-
version = '2.0.0-preview.
|
|
6
|
+
version = '2.0.0-preview.10'
|
|
7
7
|
|
|
8
8
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
9
9
|
apply from: expoModulesCorePlugin
|
|
@@ -67,7 +67,7 @@ android {
|
|
|
67
67
|
defaultConfig {
|
|
68
68
|
consumerProguardFiles 'proguard-rules.pro'
|
|
69
69
|
versionCode 1
|
|
70
|
-
versionName "2.0.0-preview.
|
|
70
|
+
versionName "2.0.0-preview.10"
|
|
71
71
|
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled.toString()
|
|
72
72
|
|
|
73
73
|
testInstrumentationRunner "expo.modules.TestRunner"
|
|
@@ -198,7 +198,7 @@ dependencies {
|
|
|
198
198
|
|
|
199
199
|
if (shouldTurnWarningsIntoErrors) {
|
|
200
200
|
tasks.withType(JavaCompile) configureEach {
|
|
201
|
-
options.compilerArgs << "-Werror" << "-Xlint:all"
|
|
201
|
+
options.compilerArgs << "-Werror" << "-Xlint:all" << '-Xlint:-serial' << '-Xlint:-rawtypes'
|
|
202
202
|
}
|
|
203
203
|
tasks.withType(KotlinCompile) configureEach {
|
|
204
204
|
compilerOptions.allWarningsAsErrors = true
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
package expo.modules.adapters.react.apploader
|
|
2
2
|
|
|
3
|
+
import android.annotation.SuppressLint
|
|
3
4
|
import android.content.Context
|
|
4
5
|
import com.facebook.react.ReactApplication
|
|
5
6
|
import com.facebook.react.ReactInstanceEventListener
|
|
6
7
|
import com.facebook.react.ReactInstanceManager
|
|
7
8
|
import com.facebook.react.bridge.ReactContext
|
|
8
9
|
import com.facebook.react.common.LifecycleState
|
|
10
|
+
import expo.modules.BuildConfig
|
|
9
11
|
import expo.modules.apploader.HeadlessAppLoader
|
|
10
12
|
import expo.modules.core.interfaces.Consumer
|
|
11
13
|
import expo.modules.core.interfaces.DoNotStrip
|
|
12
14
|
|
|
13
|
-
private val appRecords: MutableMap<String,
|
|
15
|
+
private val appRecords: MutableMap<String, ReactContext> = mutableMapOf()
|
|
14
16
|
|
|
15
17
|
class RNHeadlessAppLoader @DoNotStrip constructor(private val context: Context) : HeadlessAppLoader {
|
|
16
18
|
|
|
@@ -22,16 +24,35 @@ class RNHeadlessAppLoader @DoNotStrip constructor(private val context: Context)
|
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
if (context.applicationContext is ReactApplication) {
|
|
25
|
-
val reactInstanceManager = (context.applicationContext as ReactApplication).reactNativeHost.reactInstanceManager
|
|
26
27
|
if (!appRecords.containsKey(params.appScopeKey)) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
// In old arch reactHost will be null
|
|
29
|
+
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
|
30
|
+
// New architecture
|
|
31
|
+
val reactHost = (context.applicationContext as ReactApplication).reactHost ?: throw IllegalStateException("Your application does not have a valid reactHost")
|
|
32
|
+
reactHost.addReactInstanceEventListener(
|
|
33
|
+
object : ReactInstanceEventListener {
|
|
34
|
+
override fun onReactContextInitialized(context: ReactContext) {
|
|
35
|
+
reactHost.removeReactInstanceEventListener(this)
|
|
36
|
+
HeadlessAppLoaderNotifier.notifyAppLoaded(params.appScopeKey)
|
|
37
|
+
appRecords[params.appScopeKey] = context
|
|
38
|
+
callback?.apply(true)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
)
|
|
42
|
+
reactHost.start()
|
|
43
|
+
} else {
|
|
44
|
+
// Old architecture
|
|
45
|
+
val reactInstanceManager = (context.applicationContext as ReactApplication).reactNativeHost.reactInstanceManager
|
|
46
|
+
reactInstanceManager.addReactInstanceEventListener(
|
|
47
|
+
object : ReactInstanceEventListener {
|
|
48
|
+
override fun onReactContextInitialized(context: ReactContext) {
|
|
49
|
+
HeadlessAppLoaderNotifier.notifyAppLoaded(params.appScopeKey)
|
|
50
|
+
reactInstanceManager.removeReactInstanceEventListener(this)
|
|
51
|
+
appRecords[params.appScopeKey] = context
|
|
52
|
+
callback?.apply(true)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
)
|
|
35
56
|
reactInstanceManager.createReactContextInBackground()
|
|
36
57
|
}
|
|
37
58
|
} else {
|
|
@@ -42,18 +63,34 @@ class RNHeadlessAppLoader @DoNotStrip constructor(private val context: Context)
|
|
|
42
63
|
}
|
|
43
64
|
}
|
|
44
65
|
|
|
66
|
+
@SuppressLint("VisibleForTests")
|
|
45
67
|
override fun invalidateApp(appScopeKey: String?): Boolean {
|
|
46
68
|
return if (appRecords.containsKey(appScopeKey) && appRecords[appScopeKey] != null) {
|
|
47
|
-
val
|
|
48
|
-
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
69
|
+
val reactContext = appRecords[appScopeKey] ?: return false
|
|
70
|
+
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
|
71
|
+
// New architecture
|
|
72
|
+
val reactHost = (reactContext.applicationContext as ReactApplication).reactHost ?: throw IllegalStateException("Your application does not have a valid reactHost")
|
|
73
|
+
android.os.Handler(reactContext.mainLooper).post {
|
|
74
|
+
reactHost.destroy("Closing headless task app", null)
|
|
75
|
+
HeadlessAppLoaderNotifier.notifyAppDestroyed(appScopeKey)
|
|
76
|
+
appRecords.remove(appScopeKey)
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
// Old architecture
|
|
80
|
+
val reactNativeHost = (reactContext.applicationContext as ReactApplication).reactNativeHost
|
|
81
|
+
if (reactNativeHost.hasInstance()) {
|
|
82
|
+
val reactInstanceManager: ReactInstanceManager = reactNativeHost.reactInstanceManager
|
|
83
|
+
android.os.Handler(reactContext.mainLooper).post {
|
|
84
|
+
// Only destroy the `ReactInstanceManager` if it does not bind with an Activity.
|
|
85
|
+
// And The Activity would take over the ownership of `ReactInstanceManager`.
|
|
86
|
+
// This case happens when a user clicks a background task triggered notification immediately.
|
|
87
|
+
if (reactInstanceManager.lifecycleState == LifecycleState.BEFORE_CREATE) {
|
|
88
|
+
reactInstanceManager.destroy()
|
|
89
|
+
}
|
|
90
|
+
HeadlessAppLoaderNotifier.notifyAppDestroyed(appScopeKey)
|
|
91
|
+
appRecords.remove(appScopeKey)
|
|
92
|
+
}
|
|
54
93
|
}
|
|
55
|
-
HeadlessAppLoaderNotifier.notifyAppDestroyed(appScopeKey)
|
|
56
|
-
appRecords.remove(appScopeKey)
|
|
57
94
|
}
|
|
58
95
|
true
|
|
59
96
|
} else {
|
|
@@ -61,8 +98,18 @@ class RNHeadlessAppLoader @DoNotStrip constructor(private val context: Context)
|
|
|
61
98
|
}
|
|
62
99
|
}
|
|
63
100
|
|
|
64
|
-
override fun isRunning(appScopeKey: String?): Boolean
|
|
65
|
-
|
|
101
|
+
override fun isRunning(appScopeKey: String?): Boolean {
|
|
102
|
+
val reactContext = appRecords[appScopeKey] ?: return false
|
|
103
|
+
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
|
104
|
+
// New architecture - We can return true since the fact that we have a reactContext
|
|
105
|
+
// means that we've already called start on the reactHost
|
|
106
|
+
return true
|
|
107
|
+
} else {
|
|
108
|
+
// Old architecture
|
|
109
|
+
val reactNativeHost = (reactContext.applicationContext as ReactApplication).reactNativeHost
|
|
110
|
+
return reactNativeHost.reactInstanceManager.hasStartedCreatingInitialContext()
|
|
111
|
+
}
|
|
112
|
+
}
|
|
66
113
|
|
|
67
114
|
//endregion HeadlessAppLoader
|
|
68
115
|
}
|
|
@@ -13,7 +13,6 @@ import androidx.core.content.ContextCompat
|
|
|
13
13
|
import com.facebook.react.modules.core.PermissionAwareActivity
|
|
14
14
|
import com.facebook.react.modules.core.PermissionListener
|
|
15
15
|
import expo.modules.core.ModuleRegistry
|
|
16
|
-
import expo.modules.core.Promise
|
|
17
16
|
import expo.modules.core.interfaces.ActivityProvider
|
|
18
17
|
import expo.modules.core.interfaces.InternalModule
|
|
19
18
|
import expo.modules.core.interfaces.LifecycleEventListener
|
|
@@ -59,7 +58,12 @@ open class PermissionsService(val context: Context) : InternalModule, Permission
|
|
|
59
58
|
mAskedPermissionsCache = context.applicationContext.getSharedPreferences(PREFERENCE_FILENAME, Context.MODE_PRIVATE)
|
|
60
59
|
}
|
|
61
60
|
|
|
62
|
-
override fun getPermissionsWithPromise(
|
|
61
|
+
override fun getPermissionsWithPromise(
|
|
62
|
+
promise:
|
|
63
|
+
@Suppress("DEPRECATION")
|
|
64
|
+
expo.modules.core.Promise,
|
|
65
|
+
vararg permissions: String
|
|
66
|
+
) {
|
|
63
67
|
getPermissions(
|
|
64
68
|
PermissionsResponseListener { permissionsMap: MutableMap<String, PermissionsResponse> ->
|
|
65
69
|
val areAllGranted = permissionsMap.all { (_, response) -> response.status == PermissionsStatus.GRANTED }
|
|
@@ -86,7 +90,12 @@ open class PermissionsService(val context: Context) : InternalModule, Permission
|
|
|
86
90
|
)
|
|
87
91
|
}
|
|
88
92
|
|
|
89
|
-
override fun askForPermissionsWithPromise(
|
|
93
|
+
override fun askForPermissionsWithPromise(
|
|
94
|
+
promise:
|
|
95
|
+
@Suppress("DEPRECATION")
|
|
96
|
+
expo.modules.core.Promise,
|
|
97
|
+
vararg permissions: String
|
|
98
|
+
) {
|
|
90
99
|
askForPermissions(
|
|
91
100
|
PermissionsResponseListener {
|
|
92
101
|
getPermissionsWithPromise(promise, *permissions)
|
|
@@ -165,7 +174,7 @@ open class PermissionsService(val context: Context) : InternalModule, Permission
|
|
|
165
174
|
return requestedPermissions!!.contains(permission)
|
|
166
175
|
}
|
|
167
176
|
return false
|
|
168
|
-
} catch (
|
|
177
|
+
} catch (_: PackageManager.NameNotFoundException) {
|
|
169
178
|
return false
|
|
170
179
|
}
|
|
171
180
|
}
|
|
@@ -206,7 +215,7 @@ open class PermissionsService(val context: Context) : InternalModule, Permission
|
|
|
206
215
|
private fun canAskAgain(permission: String): Boolean {
|
|
207
216
|
return mActivityProvider?.currentActivity?.let {
|
|
208
217
|
ActivityCompat.shouldShowRequestPermissionRationale(it, permission)
|
|
209
|
-
}
|
|
218
|
+
} == true
|
|
210
219
|
}
|
|
211
220
|
|
|
212
221
|
private fun parseNativeResult(permissionsString: Array<out String>, grantResults: IntArray): Map<String, PermissionsResponse> {
|
|
@@ -35,6 +35,7 @@ public class EventEmitterModule implements EventEmitter, InternalModule {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
@Override
|
|
38
|
+
@SuppressWarnings("deprecation")
|
|
38
39
|
public void emit(final int viewId, final String eventName, final Bundle eventBody) {
|
|
39
40
|
final EventDispatcher dispatcher = UIManagerHelper.getEventDispatcherForReactTag(mReactContext, viewId);
|
|
40
41
|
dispatcher.dispatchEvent(new com.facebook.react.uimanager.events.Event(viewId) {
|
|
@@ -65,6 +66,7 @@ public class EventEmitterModule implements EventEmitter, InternalModule {
|
|
|
65
66
|
return Collections.singletonList((Class) EventEmitter.class);
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
@SuppressWarnings("deprecation")
|
|
68
70
|
private static com.facebook.react.uimanager.events.Event getReactEventFromEvent(final int viewId, final Event event) {
|
|
69
71
|
return new com.facebook.react.uimanager.events.Event(viewId) {
|
|
70
72
|
@Override
|
package/android/src/main/java/expo/modules/adapters/react/services/UIManagerModuleWrapper.java
CHANGED
|
@@ -70,6 +70,7 @@ public class UIManagerModuleWrapper implements
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
@Override
|
|
73
|
+
@SuppressWarnings("deprecation")
|
|
73
74
|
public <T> void addUIBlock(final int tag, final UIBlock<T> block, final Class<T> tClass) {
|
|
74
75
|
UIBlockInterface uiBlock = new UIBlockInterface() {
|
|
75
76
|
@Override
|
|
@@ -105,6 +106,7 @@ public class UIManagerModuleWrapper implements
|
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
@Override
|
|
109
|
+
@SuppressWarnings("deprecation")
|
|
108
110
|
public void addUIBlock(final GroupUIBlock block) {
|
|
109
111
|
UIBlockInterface uiBlock = new UIBlockInterface() {
|
|
110
112
|
@Override
|
|
@@ -141,6 +143,7 @@ public class UIManagerModuleWrapper implements
|
|
|
141
143
|
|
|
142
144
|
@Nullable
|
|
143
145
|
@Override
|
|
146
|
+
@SuppressWarnings("deprecation")
|
|
144
147
|
public View resolveView(int viewTag) {
|
|
145
148
|
final com.facebook.react.bridge.UIManager uiManager = UIManagerHelper.getUIManagerForReactTag(getContext(), viewTag);
|
|
146
149
|
if (uiManager == null) {
|
|
@@ -263,6 +266,7 @@ public class UIManagerModuleWrapper implements
|
|
|
263
266
|
}
|
|
264
267
|
|
|
265
268
|
@androidx.annotation.OptIn(markerClass = FrameworkAPI.class)
|
|
269
|
+
@SuppressWarnings("deprecation")
|
|
266
270
|
public CallInvokerHolderImpl getJSCallInvokerHolder() {
|
|
267
271
|
return (CallInvokerHolderImpl) mReactContext.getCatalystInstance().getJSCallInvokerHolder();
|
|
268
272
|
}
|
|
@@ -273,5 +277,6 @@ public class UIManagerModuleWrapper implements
|
|
|
273
277
|
}
|
|
274
278
|
}
|
|
275
279
|
|
|
280
|
+
@SuppressWarnings("deprecation")
|
|
276
281
|
interface UIBlockInterface extends com.facebook.react.uimanager.UIBlock, com.facebook.react.fabric.interop.UIBlock {
|
|
277
282
|
}
|
|
@@ -20,7 +20,7 @@ object ModulePriorities {
|
|
|
20
20
|
// {key} to {value}
|
|
21
21
|
// key: full qualified class name
|
|
22
22
|
// value: priority value, the higher value takes precedence
|
|
23
|
-
"
|
|
23
|
+
"host.exp.exponent.experience.splashscreen.legacy.SplashScreenPackage" to 11,
|
|
24
24
|
"expo.modules.updates.UpdatesPackage" to 10
|
|
25
25
|
)
|
|
26
26
|
}
|
|
@@ -40,6 +40,7 @@ public class ModuleRegistry {
|
|
|
40
40
|
return (T) mInternalModulesMap.get(interfaceClass);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
@SuppressWarnings("unchecked")
|
|
43
44
|
public <T> T getSingletonModule(String singletonName, Class<T> singletonClass) {
|
|
44
45
|
return (T) mSingletonModulesMap.get(singletonName);
|
|
45
46
|
}
|
package/android/src/main/java/expo/modules/interfaces/taskManager/TaskServiceProviderHelper.kt
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
package expo.modules.interfaces.taskManager
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import expo.modules.core.ModulePriorities
|
|
5
|
+
import expo.modules.core.interfaces.DoNotStrip
|
|
6
|
+
import expo.modules.core.interfaces.Package
|
|
7
|
+
|
|
8
|
+
@DoNotStrip
|
|
9
|
+
object TaskServiceProviderHelper {
|
|
10
|
+
/**
|
|
11
|
+
Uses reflection to look through the current list of packages and attempts to find
|
|
12
|
+
one that provides a TaskServiceInterface implementation.
|
|
13
|
+
@param context Provide the application context (context.getApplicationContext())
|
|
14
|
+
@return A implementation of the TaskServiceInterface it a package offers it
|
|
15
|
+
*/
|
|
16
|
+
@DoNotStrip
|
|
17
|
+
fun getTaskServiceImpl(context: Context): TaskServiceInterface? {
|
|
18
|
+
// Use reflection to get the packages list from ExpoModulesPackageList without
|
|
19
|
+
// creating the reactInstanceManager. ExpoModulesPackageList is generated by
|
|
20
|
+
// autolinking and should safely be callable in this way - we already have a
|
|
21
|
+
// few other places in our code where it is called like this.
|
|
22
|
+
val expoModules: Class<*>? = try {
|
|
23
|
+
Class.forName("expo.modules.ExpoModulesPackageList")
|
|
24
|
+
} catch (e: ClassNotFoundException) {
|
|
25
|
+
// Handle the exception, e.g., log it or fallback to a default behavior
|
|
26
|
+
return null
|
|
27
|
+
}
|
|
28
|
+
val getPackageList = expoModules?.getMethod("getPackageList") ?: return null
|
|
29
|
+
|
|
30
|
+
// Invoke and get the list of packages
|
|
31
|
+
val result = getPackageList.invoke(null) as? List<*> ?: return null
|
|
32
|
+
val packages = result.filterIsInstance<Package>()
|
|
33
|
+
.sortedByDescending { ModulePriorities.get(it::class.qualifiedName) }
|
|
34
|
+
|
|
35
|
+
// Check if any of the packages are providing a task manager implementation
|
|
36
|
+
return packages
|
|
37
|
+
.filterIsInstance<TaskServiceProviderInterface>()
|
|
38
|
+
.firstOrNull()
|
|
39
|
+
?.getTaskServiceImpl(context)
|
|
40
|
+
}
|
|
41
|
+
}
|
package/android/src/main/java/expo/modules/interfaces/taskManager/TaskServiceProviderInterface.java
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
package expo.modules.interfaces.taskManager;
|
|
2
|
+
|
|
3
|
+
import android.content.Context;
|
|
4
|
+
|
|
5
|
+
import expo.modules.core.interfaces.Package;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Interface defining a package that provides a TaskServiceInterface implementation.
|
|
9
|
+
* This is utilized when an app is launched in the background without an activity.
|
|
10
|
+
* It enables running expo-task-manager JavaScript tasks in the background via the HeadlessAppLoader.
|
|
11
|
+
*/
|
|
12
|
+
public interface TaskServiceProviderInterface extends Package {
|
|
13
|
+
/**
|
|
14
|
+
* @param context Current application context
|
|
15
|
+
* @return A task service implementation that can be provided without having setup the whole app
|
|
16
|
+
*/
|
|
17
|
+
TaskServiceInterface getTaskServiceImpl(Context context);
|
|
18
|
+
}
|
|
@@ -46,15 +46,15 @@ fun Promise.toBridgePromise(): com.facebook.react.bridge.Promise {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
override fun reject(code: String, message: String?) {
|
|
49
|
-
expoPromise.reject(code
|
|
49
|
+
expoPromise.reject(code, message, null)
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
override fun reject(code: String, throwable: Throwable?) {
|
|
53
|
-
expoPromise.reject(code
|
|
53
|
+
expoPromise.reject(code, null, throwable)
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
override fun reject(code: String, message: String?, throwable: Throwable?) {
|
|
57
|
-
expoPromise.reject(code
|
|
57
|
+
expoPromise.reject(code, message, throwable)
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
override fun reject(throwable: Throwable) {
|
|
@@ -66,15 +66,15 @@ fun Promise.toBridgePromise(): com.facebook.react.bridge.Promise {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
override fun reject(code: String, userInfo: WritableMap) {
|
|
69
|
-
expoPromise.reject(code
|
|
69
|
+
expoPromise.reject(code, null, null)
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
override fun reject(code: String, throwable: Throwable?, userInfo: WritableMap) {
|
|
73
|
-
expoPromise.reject(code
|
|
73
|
+
expoPromise.reject(code, null, throwable)
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
override fun reject(code: String, message: String?, userInfo: WritableMap) {
|
|
77
|
-
expoPromise.reject(code
|
|
77
|
+
expoPromise.reject(code, message, null)
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
override fun reject(code: String?, message: String?, throwable: Throwable?, userInfo: WritableMap?) {
|
|
@@ -32,10 +32,10 @@ class ClassComponentBuilder<SharedObjectType : Any>(
|
|
|
32
32
|
|
|
33
33
|
if (eventsDefinition != null && isSharedObject) {
|
|
34
34
|
listOf("__expo_onStartListeningToEvent" to SharedObject::onStartListeningToEvent, "__expo_onStopListeningToEvent" to SharedObject::onStopListeningToEvent)
|
|
35
|
-
.forEach { (name,
|
|
35
|
+
.forEach { (name, listener) ->
|
|
36
36
|
SyncFunctionComponent(name, arrayOf(ownerType, toAnyType<String>()), toReturnType<Unit>()) { (self, eventName) ->
|
|
37
37
|
enforceType<SharedObject, String>(self, eventName)
|
|
38
|
-
|
|
38
|
+
listener.invoke(self, eventName)
|
|
39
39
|
}.also { function ->
|
|
40
40
|
function.enumerable(false)
|
|
41
41
|
syncFunctions[name] = function
|
|
@@ -14,6 +14,7 @@ import kotlinx.coroutines.launch
|
|
|
14
14
|
import okhttp3.Request
|
|
15
15
|
import okhttp3.Response
|
|
16
16
|
import okhttp3.ResponseBody
|
|
17
|
+
import java.lang.ref.WeakReference
|
|
17
18
|
import java.math.BigDecimal
|
|
18
19
|
import java.math.RoundingMode
|
|
19
20
|
|
|
@@ -22,18 +23,18 @@ import java.math.RoundingMode
|
|
|
22
23
|
* dispatch CDP (Chrome DevTools Protocol: https://chromedevtools.github.io/devtools-protocol/) events.
|
|
23
24
|
*/
|
|
24
25
|
object ExpoRequestCdpInterceptor : ExpoNetworkInspectOkHttpInterceptorsDelegate {
|
|
25
|
-
private var delegate: Delegate
|
|
26
|
+
private var delegate: WeakReference<Delegate?> = WeakReference(null)
|
|
26
27
|
internal var coroutineScope = CoroutineScope(Dispatchers.Default)
|
|
27
28
|
|
|
28
29
|
fun setDelegate(delegate: Delegate?) {
|
|
29
30
|
coroutineScope.launch {
|
|
30
|
-
this@ExpoRequestCdpInterceptor.delegate = delegate
|
|
31
|
+
this@ExpoRequestCdpInterceptor.delegate = WeakReference(delegate)
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
private fun dispatchEvent(event: Event) {
|
|
35
36
|
coroutineScope.launch {
|
|
36
|
-
this@ExpoRequestCdpInterceptor.delegate?.dispatch(event.toJson())
|
|
37
|
+
this@ExpoRequestCdpInterceptor.delegate.get()?.dispatch(event.toJson())
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package expo.modules.kotlin.events
|
|
2
2
|
|
|
3
|
+
import android.view.View
|
|
3
4
|
import com.facebook.react.bridge.WritableMap
|
|
4
5
|
import expo.modules.kotlin.records.Record
|
|
5
6
|
|
|
@@ -10,4 +11,5 @@ interface EventEmitter : expo.modules.core.interfaces.services.EventEmitter {
|
|
|
10
11
|
fun emit(eventName: String, eventBody: Record?)
|
|
11
12
|
fun emit(eventName: String, eventBody: Map<*, *>?)
|
|
12
13
|
fun emit(viewId: Int, eventName: String, eventBody: WritableMap?, coalescingKey: Short? = null)
|
|
14
|
+
fun emit(view: View, eventName: String, eventBody: WritableMap?, coalescingKey: Short? = null)
|
|
13
15
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package expo.modules.kotlin.events
|
|
2
2
|
|
|
3
3
|
import android.os.Bundle
|
|
4
|
+
import android.view.View
|
|
4
5
|
import com.facebook.react.bridge.Arguments
|
|
5
6
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
7
|
import com.facebook.react.bridge.ReadableNativeMap
|
|
@@ -96,15 +97,24 @@ open class KEventEmitterWrapper(
|
|
|
96
97
|
override fun emit(viewId: Int, eventName: String, eventBody: WritableMap?, coalescingKey: Short?) {
|
|
97
98
|
val context = reactContextHolder.get() ?: return
|
|
98
99
|
UIManagerHelper.getEventDispatcherForReactTag(context, viewId)
|
|
99
|
-
?.dispatchEvent(UIEvent(viewId, eventName, eventBody, coalescingKey))
|
|
100
|
+
?.dispatchEvent(UIEvent(surfaceId = -1, viewId, eventName, eventBody, coalescingKey))
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
override fun emit(view: View, eventName: String, eventBody: WritableMap?, coalescingKey: Short?) {
|
|
104
|
+
val context = reactContextHolder.get() ?: return
|
|
105
|
+
val surfaceId = UIManagerHelper.getSurfaceId(view)
|
|
106
|
+
val viewId = view.id
|
|
107
|
+
UIManagerHelper.getEventDispatcherForReactTag(context, view.id)
|
|
108
|
+
?.dispatchEvent(UIEvent(surfaceId, viewId, eventName, eventBody, coalescingKey))
|
|
100
109
|
}
|
|
101
110
|
|
|
102
111
|
private class UIEvent(
|
|
112
|
+
surfaceId: Int,
|
|
103
113
|
viewId: Int,
|
|
104
114
|
private val eventName: String,
|
|
105
115
|
private val eventBody: WritableMap?,
|
|
106
116
|
private val coalescingKey: Short?
|
|
107
|
-
) : com.facebook.react.uimanager.events.Event<UIEvent>(viewId) {
|
|
117
|
+
) : com.facebook.react.uimanager.events.Event<UIEvent>(surfaceId, viewId) {
|
|
108
118
|
override fun getEventName(): String = normalizeEventName(eventName)
|
|
109
119
|
override fun canCoalesce(): Boolean = coalescingKey != null
|
|
110
120
|
override fun getCoalescingKey(): Short = coalescingKey ?: 0
|
|
@@ -70,4 +70,20 @@ class Exceptions {
|
|
|
70
70
|
* An exception to throw when the root view is missing.
|
|
71
71
|
*/
|
|
72
72
|
class MissingRootView : CodedException(message = "The root view is missing")
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* An exception to throw to indicate that a method has been passed an illegal or inappropriate argument.
|
|
76
|
+
*/
|
|
77
|
+
class IllegalArgument(
|
|
78
|
+
message: String,
|
|
79
|
+
cause: Throwable? = null
|
|
80
|
+
) : CodedException(message, cause)
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* An exception to signal that a method has been invoked at an illegal or inappropriate time.
|
|
84
|
+
*/
|
|
85
|
+
class IllegalStateException(
|
|
86
|
+
message: String,
|
|
87
|
+
cause: Throwable? = null
|
|
88
|
+
) : CodedException(message, cause)
|
|
73
89
|
}
|