expo 58.0.0-preview.0 → 58.0.0-preview.2
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/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/ExpoModulesV2ModuleList.kt +15 -0
- package/android/src/main/java/expo/modules/LocalNetworkPermission.kt +19 -0
- package/android/src/main/java/expo/modules/ReactActivityDelegateWrapper.kt +19 -2
- package/android/src/test/java/expo/modules/ReactActivityDelegateWrapperLocalNetworkPermissionTest.kt +99 -0
- package/build/Expo.d.ts +1 -1
- package/build/Expo.js.map +1 -1
- package/build/winter/runtime.native.d.ts +1 -1
- package/build/winter/runtime.native.js +1 -1
- package/build/winter/runtime.native.js.map +1 -1
- package/bundledNativeModules.json +44 -44
- package/ios/Expo/ExpoAppSceneDelegate.swift +57 -42
- package/ios/Expo/SceneEventForwarder.swift +154 -0
- package/ios/Tests/ExpoAppSceneDelegateTests.swift +501 -1
- package/package.json +17 -17
- package/src/Expo.ts +2 -0
- package/src/winter/runtime.native.ts +1 -1
- package/template.tgz +0 -0
package/android/build.gradle
CHANGED
|
@@ -10,7 +10,7 @@ buildscript {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
group = 'host.exp.exponent'
|
|
13
|
-
version = '58.0.0-preview.
|
|
13
|
+
version = '58.0.0-preview.2'
|
|
14
14
|
|
|
15
15
|
expoModule {
|
|
16
16
|
// We can't prebuild the module because it depends on the generated files.
|
|
@@ -21,7 +21,7 @@ android {
|
|
|
21
21
|
namespace "expo.core"
|
|
22
22
|
defaultConfig {
|
|
23
23
|
versionCode 1
|
|
24
|
-
versionName "58.0.0-preview.
|
|
24
|
+
versionName "58.0.0-preview.2"
|
|
25
25
|
consumerProguardFiles("proguard-rules.pro")
|
|
26
26
|
}
|
|
27
27
|
testOptions {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
package expo.modules
|
|
2
|
+
|
|
3
|
+
import expo.modules.v2.ExpoModulesV2Provider
|
|
4
|
+
import io.github.expo.modules.v2.Module
|
|
5
|
+
import io.github.expo.modules.v2.discoveredExpoModules
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The list is filled in at compile time: the Expo Modules v2 compiler plugin, which autolinking
|
|
9
|
+
* applies to this project, expands `discoveredExpoModules()` into every `@ExpoModule` on the compile
|
|
10
|
+
* classpath. Autolinking adds every module project as a dependency of this one, so the classpath is
|
|
11
|
+
* exactly the set of installed modules and nothing has to be listed anywhere.
|
|
12
|
+
*/
|
|
13
|
+
class ExpoModulesV2ModuleList : ExpoModulesV2Provider {
|
|
14
|
+
override fun getModules(): List<Class<out Module>> = discoveredExpoModules()
|
|
15
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
package expo.modules
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.content.pm.PackageManager
|
|
5
|
+
import android.os.Build
|
|
6
|
+
import com.facebook.react.common.build.ReactBuildConfig
|
|
7
|
+
|
|
8
|
+
// Android 17 blocks dev server traffic until the app holds the permission React Native's debug manifest declares.
|
|
9
|
+
internal object LocalNetworkPermission {
|
|
10
|
+
const val PERMISSION = "android.permission.ACCESS_LOCAL_NETWORK"
|
|
11
|
+
const val REQUEST_CODE = 0x4c4e
|
|
12
|
+
|
|
13
|
+
private const val FIRST_ENFORCED_SDK = 37
|
|
14
|
+
|
|
15
|
+
fun shouldRequest(activity: Activity): Boolean =
|
|
16
|
+
ReactBuildConfig.DEBUG &&
|
|
17
|
+
Build.VERSION.SDK_INT >= FIRST_ENFORCED_SDK &&
|
|
18
|
+
activity.checkSelfPermission(PERMISSION) != PackageManager.PERMISSION_GRANTED
|
|
19
|
+
}
|
|
@@ -30,13 +30,13 @@ import kotlinx.coroutines.CoroutineScope
|
|
|
30
30
|
import kotlinx.coroutines.CoroutineStart
|
|
31
31
|
import kotlinx.coroutines.Dispatchers
|
|
32
32
|
import kotlinx.coroutines.launch
|
|
33
|
+
import kotlinx.coroutines.suspendCancellableCoroutine
|
|
33
34
|
import kotlinx.coroutines.sync.Mutex
|
|
34
35
|
import kotlinx.coroutines.sync.withLock
|
|
35
36
|
import java.lang.reflect.Field
|
|
36
37
|
import java.lang.reflect.Method
|
|
37
38
|
import java.lang.reflect.Modifier
|
|
38
39
|
import kotlin.coroutines.resume
|
|
39
|
-
import kotlin.coroutines.suspendCoroutine
|
|
40
40
|
|
|
41
41
|
class ReactActivityDelegateWrapper(
|
|
42
42
|
private val activity: ReactActivity,
|
|
@@ -64,6 +64,7 @@ class ReactActivityDelegateWrapper(
|
|
|
64
64
|
* A deferred that indicates when the app loading is ready
|
|
65
65
|
*/
|
|
66
66
|
private val loadAppReady = CompletableDeferred<Unit>()
|
|
67
|
+
private var localNetworkPermissionResult: CompletableDeferred<Unit>? = null
|
|
67
68
|
|
|
68
69
|
/**
|
|
69
70
|
* A mutex to ensure all coroutines in a scope are running in atomic way.
|
|
@@ -161,6 +162,7 @@ class ReactActivityDelegateWrapper(
|
|
|
161
162
|
mReactDelegate.isAccessible = true
|
|
162
163
|
mReactDelegate.set(delegate, reactDelegate)
|
|
163
164
|
if (mainComponentName != null) {
|
|
165
|
+
awaitLocalNetworkPermission()
|
|
164
166
|
loadAppImpl(mainComponentName, supportsDelayLoad = false)
|
|
165
167
|
}
|
|
166
168
|
}
|
|
@@ -329,6 +331,10 @@ class ReactActivityDelegateWrapper(
|
|
|
329
331
|
}
|
|
330
332
|
|
|
331
333
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
|
334
|
+
if (requestCode == LocalNetworkPermission.REQUEST_CODE) {
|
|
335
|
+
localNetworkPermissionResult?.complete(Unit)
|
|
336
|
+
return
|
|
337
|
+
}
|
|
332
338
|
launchLifecycleScopeWithLock {
|
|
333
339
|
loadAppReady.await()
|
|
334
340
|
delegate.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
|
@@ -431,11 +437,22 @@ class ReactActivityDelegateWrapper(
|
|
|
431
437
|
}
|
|
432
438
|
}
|
|
433
439
|
|
|
440
|
+
private suspend fun awaitLocalNetworkPermission() {
|
|
441
|
+
if (!LocalNetworkPermission.shouldRequest(activity)) {
|
|
442
|
+
return
|
|
443
|
+
}
|
|
444
|
+
val result = CompletableDeferred<Unit>()
|
|
445
|
+
localNetworkPermissionResult = result
|
|
446
|
+
activity.requestPermissions(arrayOf(LocalNetworkPermission.PERMISSION), LocalNetworkPermission.REQUEST_CODE)
|
|
447
|
+
result.await()
|
|
448
|
+
localNetworkPermissionResult = null
|
|
449
|
+
}
|
|
450
|
+
|
|
434
451
|
private suspend fun awaitDelayLoadAppWhenReady(delayLoadAppHandler: DelayLoadAppHandler?) {
|
|
435
452
|
if (delayLoadAppHandler == null) {
|
|
436
453
|
return
|
|
437
454
|
}
|
|
438
|
-
|
|
455
|
+
suspendCancellableCoroutine { continuation ->
|
|
439
456
|
delayLoadAppHandler.whenReady {
|
|
440
457
|
Utils.assertMainThread()
|
|
441
458
|
continuation.resume(Unit)
|
package/android/src/test/java/expo/modules/ReactActivityDelegateWrapperLocalNetworkPermissionTest.kt
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
package expo.modules
|
|
2
|
+
|
|
3
|
+
import android.content.pm.PackageManager
|
|
4
|
+
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
|
|
5
|
+
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlagsForTests
|
|
6
|
+
import com.facebook.soloader.SoLoader
|
|
7
|
+
import com.google.common.truth.Truth.assertThat
|
|
8
|
+
import io.mockk.every
|
|
9
|
+
import io.mockk.mockkObject
|
|
10
|
+
import io.mockk.mockkStatic
|
|
11
|
+
import io.mockk.unmockkAll
|
|
12
|
+
import io.mockk.verify
|
|
13
|
+
import kotlinx.coroutines.Dispatchers
|
|
14
|
+
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
15
|
+
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
|
16
|
+
import kotlinx.coroutines.test.setMain
|
|
17
|
+
import org.junit.After
|
|
18
|
+
import org.junit.Before
|
|
19
|
+
import org.junit.Test
|
|
20
|
+
import org.junit.runner.RunWith
|
|
21
|
+
import org.robolectric.Robolectric
|
|
22
|
+
import org.robolectric.RobolectricTestRunner
|
|
23
|
+
import org.robolectric.Shadows.shadowOf
|
|
24
|
+
import org.robolectric.android.controller.ActivityController
|
|
25
|
+
import org.robolectric.annotation.Config
|
|
26
|
+
|
|
27
|
+
@RunWith(RobolectricTestRunner::class)
|
|
28
|
+
@Config(application = MockApplication::class)
|
|
29
|
+
internal class ReactActivityDelegateWrapperLocalNetworkPermissionTest {
|
|
30
|
+
private lateinit var activityController: ActivityController<MockActivity>
|
|
31
|
+
private val activity: MockActivity
|
|
32
|
+
get() = activityController.get()
|
|
33
|
+
private val wrapper: ReactActivityDelegateWrapper
|
|
34
|
+
get() = activity.reactActivityDelegate as ReactActivityDelegateWrapper
|
|
35
|
+
|
|
36
|
+
@OptIn(ExperimentalCoroutinesApi::class)
|
|
37
|
+
@Before
|
|
38
|
+
fun setUp() {
|
|
39
|
+
SoLoader.setInTestMode()
|
|
40
|
+
mockkObject(ExpoModulesPackage.Companion)
|
|
41
|
+
every { ExpoModulesPackage.Companion.packageList } returns listOf(MockPackageWithoutDelayHandler())
|
|
42
|
+
ReactNativeFeatureFlagsForTests.setUp()
|
|
43
|
+
mockkStatic(ReactNativeFeatureFlags::class)
|
|
44
|
+
every { ReactNativeFeatureFlags.enableBridgelessArchitecture() } returns true
|
|
45
|
+
Dispatchers.setMain(UnconfinedTestDispatcher())
|
|
46
|
+
mockkObject(LocalNetworkPermission)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@After
|
|
50
|
+
fun tearDown() {
|
|
51
|
+
unmockkAll()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private fun launchActivity() {
|
|
55
|
+
activityController = Robolectric.buildActivity(MockActivity::class.java)
|
|
56
|
+
.also { (it.get().application as MockApplication).bindCurrentActivity(it.get()) }
|
|
57
|
+
.setup()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private fun verifyLoadApp(times: Int) {
|
|
61
|
+
verify(exactly = times) { wrapper.invokeDelegateMethod("loadApp", arrayOf(String::class.java), arrayOf("main")) }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@Test
|
|
65
|
+
fun `requests the local network permission before loading the app`() {
|
|
66
|
+
every { LocalNetworkPermission.shouldRequest(any()) } returns true
|
|
67
|
+
|
|
68
|
+
launchActivity()
|
|
69
|
+
|
|
70
|
+
verifyLoadApp(0)
|
|
71
|
+
val request = shadowOf(activity).lastRequestedPermission
|
|
72
|
+
assertThat(request.requestedPermissions.toList()).containsExactly(LocalNetworkPermission.PERMISSION)
|
|
73
|
+
|
|
74
|
+
activity.onRequestPermissionsResult(request.requestCode, request.requestedPermissions, intArrayOf(PackageManager.PERMISSION_GRANTED))
|
|
75
|
+
|
|
76
|
+
verifyLoadApp(1)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@Test
|
|
80
|
+
fun `loads the app when the local network permission is denied`() {
|
|
81
|
+
every { LocalNetworkPermission.shouldRequest(any()) } returns true
|
|
82
|
+
|
|
83
|
+
launchActivity()
|
|
84
|
+
val request = shadowOf(activity).lastRequestedPermission
|
|
85
|
+
activity.onRequestPermissionsResult(request.requestCode, request.requestedPermissions, intArrayOf(PackageManager.PERMISSION_DENIED))
|
|
86
|
+
|
|
87
|
+
verifyLoadApp(1)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@Test
|
|
91
|
+
fun `loads the app immediately when the permission is not required`() {
|
|
92
|
+
every { LocalNetworkPermission.shouldRequest(any()) } returns false
|
|
93
|
+
|
|
94
|
+
launchActivity()
|
|
95
|
+
|
|
96
|
+
assertThat(shadowOf(activity).lastRequestedPermission).isNull()
|
|
97
|
+
verifyLoadApp(1)
|
|
98
|
+
}
|
|
99
|
+
}
|
package/build/Expo.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { disableErrorHandling } from './errors/ExpoErrorManager';
|
|
|
3
3
|
export { default as registerRootComponent } from './launch/registerRootComponent';
|
|
4
4
|
export { isRunningInExpoGo, getExpoGoProjectConfig } from './environment/ExpoGo';
|
|
5
5
|
export { EventEmitter, SharedObject, SharedRef, NativeModule, UnavailabilityError, CodedError, requireNativeModule, requireOptionalNativeModule, requireNativeViewManager as requireNativeView, registerWebModule, reloadAppAsync, installOnUIRuntime, Platform, uuid, createSnapshotFriendlyRef, useReleasingSharedObject, useReleasingSharedObjectWithLifecycle, } from 'expo-modules-core';
|
|
6
|
-
export type { EventSubscription, TypedArray, IntBasedTypedArray, UintBasedTypedArray, FloatBasedTypedArray, } from 'expo-modules-core';
|
|
6
|
+
export type { EventSubscription, TypedArray, IntBasedTypedArray, UintBasedTypedArray, FloatBasedTypedArray, ReleasingSharedObjectLifecycle, ReleasingSharedObjectLifecycleContext, } from 'expo-modules-core';
|
|
7
7
|
export type {
|
|
8
8
|
/** @deprecated Move to `SharedRef` with a type-only import instead */
|
|
9
9
|
SharedRef as SharedRefType,
|
package/build/Expo.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["Expo.ts"],"sourcesContent":[null],"names":["disableErrorHandling","default","registerRootComponent","isRunningInExpoGo","getExpoGoProjectConfig","EventEmitter","SharedObject","SharedRef","NativeModule","UnavailabilityError","CodedError","requireNativeModule","requireOptionalNativeModule","requireNativeViewManager","requireNativeView","registerWebModule","reloadAppAsync","installOnUIRuntime","Platform","uuid","createSnapshotFriendlyRef","useReleasingSharedObject","useReleasingSharedObjectWithLifecycle","PermissionStatus","createPermissionHook","useEvent","useEventListener"],"mappings":"AAAA,OAAO,YAAY;AAEnB,SAASA,oBAAoB,QAAQ,4BAA4B;AACjE,SAASC,WAAWC,qBAAqB,QAAQ,iCAAiC;AAElF,SAASC,iBAAiB,EAAEC,sBAAsB,QAAQ,uBAAuB;AAEjF,SACE,eAAe;AACfC,YAAY,EACZC,YAAY,EACZC,SAAS,EACTC,YAAY,EACZC,mBAAmB,EACnBC,UAAU,EAEV,UAAU;AACVC,mBAAmB,EACnBC,2BAA2B,EAC3BC,4BAA4BC,iBAAiB,EAC7CC,iBAAiB,EACjBC,cAAc,EAEd,WAAW;AACXC,kBAAkB,EAElB,QAAQ;AACRC,QAAQ,EACRC,IAAI,EACJC,yBAAyB,EACzBC,wBAAwB,EACxBC,qCAAqC,QAChC,oBAAoB;
|
|
1
|
+
{"version":3,"sources":["Expo.ts"],"sourcesContent":[null],"names":["disableErrorHandling","default","registerRootComponent","isRunningInExpoGo","getExpoGoProjectConfig","EventEmitter","SharedObject","SharedRef","NativeModule","UnavailabilityError","CodedError","requireNativeModule","requireOptionalNativeModule","requireNativeViewManager","requireNativeView","registerWebModule","reloadAppAsync","installOnUIRuntime","Platform","uuid","createSnapshotFriendlyRef","useReleasingSharedObject","useReleasingSharedObjectWithLifecycle","PermissionStatus","createPermissionHook","useEvent","useEventListener"],"mappings":"AAAA,OAAO,YAAY;AAEnB,SAASA,oBAAoB,QAAQ,4BAA4B;AACjE,SAASC,WAAWC,qBAAqB,QAAQ,iCAAiC;AAElF,SAASC,iBAAiB,EAAEC,sBAAsB,QAAQ,uBAAuB;AAEjF,SACE,eAAe;AACfC,YAAY,EACZC,YAAY,EACZC,SAAS,EACTC,YAAY,EACZC,mBAAmB,EACnBC,UAAU,EAEV,UAAU;AACVC,mBAAmB,EACnBC,2BAA2B,EAC3BC,4BAA4BC,iBAAiB,EAC7CC,iBAAiB,EACjBC,cAAc,EAEd,WAAW;AACXC,kBAAkB,EAElB,QAAQ;AACRC,QAAQ,EACRC,IAAI,EACJC,yBAAyB,EACzBC,wBAAwB,EACxBC,qCAAqC,QAChC,oBAAoB;AAuB3B,SACEC,gBAAgB,QAIX,oBAAoB;AAE3B,SAASC,oBAAoB,QAAQ,oBAAoB;AAEzD,SAASC,QAAQ,EAAEC,gBAAgB,QAAQ,mBAAmB"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import 'react-native/
|
|
1
|
+
import 'react-native/setup-env';
|
|
2
2
|
import '../../types';
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// https://wintercg.org/
|
|
3
3
|
// WARN(@kitten): We must ensure that the core react-native globals are initialized before ours
|
|
4
4
|
// Otherwise we're relying on `getModulesRunBeforeMainModule` which is unstable or can be missing
|
|
5
|
-
import 'react-native/
|
|
5
|
+
import 'react-native/setup-env';
|
|
6
6
|
import '../../types';
|
|
7
7
|
import { installAbortSignalPatch } from './AbortSignal';
|
|
8
8
|
import { installFormDataPatch } from './FormData';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["winter/runtime.native.ts"],"sourcesContent":[null],"names":["installAbortSignalPatch","installFormDataPatch","installGlobal","install","require","TextDecoder","TextDecoderStream","TextEncoderStream","URL","URLSearchParams","DOMException","ImportMetaRegistry","default","FormData","AbortSignal","Symbol","asyncIterator","for","useRnFetch","process","env","EXPO_PUBLIC_USE_RN_FETCH","globalThis","Headers","Error","fetch"],"mappings":"AAAA,wFAAwF;AACxF,wBAAwB;AAExB,+FAA+F;AAC/F,iGAAiG;AACjG,OAAO,
|
|
1
|
+
{"version":3,"sources":["winter/runtime.native.ts"],"sourcesContent":[null],"names":["installAbortSignalPatch","installFormDataPatch","installGlobal","install","require","TextDecoder","TextDecoderStream","TextEncoderStream","URL","URLSearchParams","DOMException","ImportMetaRegistry","default","FormData","AbortSignal","Symbol","asyncIterator","for","useRnFetch","process","env","EXPO_PUBLIC_USE_RN_FETCH","globalThis","Headers","Error","fetch"],"mappings":"AAAA,wFAAwF;AACxF,wBAAwB;AAExB,+FAA+F;AAC/F,iGAAiG;AACjG,OAAO,yBAAyB;AAChC,OAAO,cAAc;AACrB,SAASA,uBAAuB,QAAQ,gBAAgB;AACxD,SAASC,oBAAoB,QAAQ,aAAa;AAClD,SAASC,iBAAiBC,OAAO,QAAQ,kBAAkB;AAE3D,gDAAgD;AAChDA,QAAQ,eAAe,IAAMC,QAAQ,iBAAiBC,WAAW;AACjE,gEAAgE;AAChEF,QAAQ,qBAAqB,IAAMC,QAAQ,uBAAuBE,iBAAiB;AACnF,gEAAgE;AAChEH,QAAQ,qBAAqB,IAAMC,QAAQ,uBAAuBG,iBAAiB;AACnF,mCAAmC;AACnCJ,QAAQ,OAAO,IAAMC,QAAQ,SAASI,GAAG;AACzC,+CAA+C;AAC/CL,QAAQ,mBAAmB,IAAMC,QAAQ,SAASK,eAAe;AACjE,mDAAmD;AACnDN,QAAQ,gBAAgB,IAAMC,QAAQ,kBAAkBM,YAAY;AACpE,sCAAsC;AACtC,kDAAkD;AAElDP,QAAQ,4BAA4B,IAAMC,QAAQ,wBAAwBO,kBAAkB;AAE5F,8EAA8E;AAC9ER,QAAQ,mBAAmB,IAAMC,QAAQ,2BAA2BQ,OAAO;AAE3EX,qBAAqBY;AACrBb,wBAAwBc;AAExB,6CAA6C;AAC7C,+EAA+E;AAC/EC,OAAOC,aAAa,KAAKD,OAAOE,GAAG,CAAC;AAEpC,MAAMC,aACJC,QAAQC,GAAG,CAACC,wBAAwB,KAAK,OAAOF,QAAQC,GAAG,CAACC,wBAAwB,KAAK;AAE3F,IAAI,CAACH,YAAY;IACf,sEAAsE;IACtE,sEAAsE;IACtE,IAAI,CAACI,WAAWC,OAAO,EAAE;QACvB,MAAM,IAAIC,MACR;IAEJ;IACArB,QAAQ,SAAS,IAAMC,QAAQ,WAAWqB,KAAK;AACjD"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"@expo/dom-webview": "~58.0.0",
|
|
3
|
-
"@expo/fingerprint": "~0.21.
|
|
4
|
-
"@expo/metro-runtime": "~58.0.
|
|
3
|
+
"@expo/fingerprint": "~0.21.1",
|
|
4
|
+
"@expo/metro-runtime": "~58.0.2",
|
|
5
5
|
"@expo/vector-icons": "^15.0.2",
|
|
6
|
-
"@expo/ui": "~58.0.
|
|
6
|
+
"@expo/ui": "~58.0.2",
|
|
7
7
|
"@react-native-async-storage/async-storage": "2.2.0",
|
|
8
8
|
"@react-native-community/datetimepicker": "9.2.1",
|
|
9
9
|
"@react-native-masked-view/masked-view": "0.3.2",
|
|
@@ -13,95 +13,95 @@
|
|
|
13
13
|
"@react-native-picker/picker": "2.11.4",
|
|
14
14
|
"@react-native-segmented-control/segmented-control": "2.5.7",
|
|
15
15
|
"@stripe/stripe-react-native": "0.76.0",
|
|
16
|
-
"eslint-config-expo": "~58.0.
|
|
16
|
+
"eslint-config-expo": "~58.0.1",
|
|
17
17
|
"expo-analytics-amplitude": "~11.3.0",
|
|
18
18
|
"expo-app-auth": "~11.1.0",
|
|
19
|
-
"expo-app-intents": "~0.
|
|
19
|
+
"expo-app-intents": "~0.4.0",
|
|
20
20
|
"expo-app-loader-provider": "~8.0.0",
|
|
21
|
-
"expo-app-metrics": "~58.0.
|
|
21
|
+
"expo-app-metrics": "~58.0.2",
|
|
22
22
|
"expo-apple-authentication": "~58.0.0",
|
|
23
|
-
"expo-application": "~58.0.
|
|
24
|
-
"expo-asset": "~58.0.
|
|
23
|
+
"expo-application": "~58.0.1",
|
|
24
|
+
"expo-asset": "~58.0.2",
|
|
25
25
|
"expo-audio": "~58.0.0",
|
|
26
|
-
"expo-auth-session": "~58.0.
|
|
27
|
-
"expo-background-fetch": "~58.0.
|
|
28
|
-
"expo-background-task": "~58.0.
|
|
26
|
+
"expo-auth-session": "~58.0.1",
|
|
27
|
+
"expo-background-fetch": "~58.0.2",
|
|
28
|
+
"expo-background-task": "~58.0.2",
|
|
29
29
|
"expo-battery": "~58.0.0",
|
|
30
30
|
"expo-blur": "~58.0.0",
|
|
31
31
|
"expo-brightness": "~58.0.0",
|
|
32
|
-
"expo-brownfield": "~58.0.
|
|
33
|
-
"expo-build-properties": "~58.0.
|
|
34
|
-
"expo-calendar": "~58.0.
|
|
35
|
-
"expo-camera": "~58.0.
|
|
32
|
+
"expo-brownfield": "~58.0.2",
|
|
33
|
+
"expo-build-properties": "~58.0.2",
|
|
34
|
+
"expo-calendar": "~58.0.1",
|
|
35
|
+
"expo-camera": "~58.0.1",
|
|
36
36
|
"expo-cellular": "~58.0.0",
|
|
37
37
|
"expo-checkbox": "~58.0.0",
|
|
38
38
|
"expo-clipboard": "~58.0.0",
|
|
39
|
-
"expo-constants": "~58.0.
|
|
40
|
-
"expo-contacts": "~58.0.
|
|
41
|
-
"expo-crypto": "~58.0.
|
|
42
|
-
"expo-dev-client": "~58.0.
|
|
39
|
+
"expo-constants": "~58.0.2",
|
|
40
|
+
"expo-contacts": "~58.0.1",
|
|
41
|
+
"expo-crypto": "~58.0.1",
|
|
42
|
+
"expo-dev-client": "~58.0.2",
|
|
43
43
|
"expo-device": "~58.0.0",
|
|
44
44
|
"expo-document-picker": "~58.0.0",
|
|
45
45
|
"expo-eas-client": "~58.0.0",
|
|
46
46
|
"expo-file-system": "~58.0.0",
|
|
47
|
-
"expo-font": "~58.0.
|
|
47
|
+
"expo-font": "~58.0.1",
|
|
48
48
|
"expo-gl": "~58.0.0",
|
|
49
49
|
"expo-glass-effect": "~58.0.0",
|
|
50
50
|
"expo-google-app-auth": "~8.3.0",
|
|
51
|
-
"expo-haptics": "~58.0.
|
|
52
|
-
"expo-image": "~58.0.
|
|
53
|
-
"expo-image-loader": "~58.0.
|
|
54
|
-
"expo-image-manipulator": "~58.0.
|
|
55
|
-
"expo-image-picker": "~58.0.
|
|
51
|
+
"expo-haptics": "~58.0.1",
|
|
52
|
+
"expo-image": "~58.0.2",
|
|
53
|
+
"expo-image-loader": "~58.0.1",
|
|
54
|
+
"expo-image-manipulator": "~58.0.3",
|
|
55
|
+
"expo-image-picker": "~58.0.2",
|
|
56
56
|
"expo-intent-launcher": "~58.0.0",
|
|
57
|
-
"expo-insights": "~58.0.
|
|
57
|
+
"expo-insights": "~58.0.2",
|
|
58
58
|
"expo-keep-awake": "~58.0.0",
|
|
59
59
|
"expo-linear-gradient": "~58.0.0",
|
|
60
|
-
"expo-linking": "~58.0.
|
|
60
|
+
"expo-linking": "~58.0.2",
|
|
61
61
|
"expo-local-authentication": "~58.0.0",
|
|
62
62
|
"expo-localization": "~58.0.0",
|
|
63
|
-
"expo-location": "~58.0.
|
|
63
|
+
"expo-location": "~58.0.2",
|
|
64
64
|
"expo-mail-composer": "~58.0.0",
|
|
65
65
|
"expo-manifests": "~58.0.0",
|
|
66
|
-
"expo-maps": "~58.0.
|
|
66
|
+
"expo-maps": "~58.0.1",
|
|
67
67
|
"expo-mcp": "~0.2.1",
|
|
68
68
|
"expo-media-library": "~58.0.0",
|
|
69
69
|
"expo-mesh-gradient": "~58.0.0",
|
|
70
|
-
"expo-module-template": "~58.0.
|
|
71
|
-
"expo-modules-core": "~58.0.
|
|
70
|
+
"expo-module-template": "~58.0.1",
|
|
71
|
+
"expo-modules-core": "~58.0.2",
|
|
72
72
|
"expo-navigation-bar": "~58.0.0",
|
|
73
73
|
"expo-network": "~58.0.0",
|
|
74
|
-
"expo-notifications": "~58.0.
|
|
75
|
-
"expo-observe": "~58.0.
|
|
74
|
+
"expo-notifications": "~58.0.2",
|
|
75
|
+
"expo-observe": "~58.0.4",
|
|
76
76
|
"expo-print": "~58.0.0",
|
|
77
77
|
"expo-live-photo": "~58.0.0",
|
|
78
|
-
"expo-router": "~58.0.
|
|
78
|
+
"expo-router": "~58.0.3",
|
|
79
79
|
"expo-screen-capture": "~58.0.0",
|
|
80
80
|
"expo-screen-orientation": "~58.0.0",
|
|
81
81
|
"expo-secure-store": "~58.0.0",
|
|
82
82
|
"expo-sensors": "~58.0.0",
|
|
83
83
|
"expo-server": "~58.0.0",
|
|
84
|
-
"expo-sharing": "~58.0.
|
|
84
|
+
"expo-sharing": "~58.0.4",
|
|
85
85
|
"expo-sms": "~58.0.0",
|
|
86
86
|
"expo-speech": "~58.0.0",
|
|
87
87
|
"expo-splash-screen": "~58.0.0",
|
|
88
|
-
"expo-sqlite": "~58.0.
|
|
88
|
+
"expo-sqlite": "~58.0.3",
|
|
89
89
|
"expo-status-bar": "~58.0.0",
|
|
90
90
|
"expo-store-review": "~58.0.0",
|
|
91
|
-
"expo-symbols": "~58.0.
|
|
92
|
-
"expo-system-ui": "~58.0.
|
|
93
|
-
"expo-task-manager": "~58.0.
|
|
91
|
+
"expo-symbols": "~58.0.1",
|
|
92
|
+
"expo-system-ui": "~58.0.1",
|
|
93
|
+
"expo-task-manager": "~58.0.3",
|
|
94
94
|
"expo-tracking-transparency": "~58.0.0",
|
|
95
|
-
"expo-updates": "~58.0.
|
|
95
|
+
"expo-updates": "~58.0.4",
|
|
96
96
|
"expo-video-thumbnails": "~58.0.0",
|
|
97
|
-
"expo-video": "~58.0.
|
|
97
|
+
"expo-video": "~58.0.1",
|
|
98
98
|
"expo-web-browser": "~58.0.0",
|
|
99
|
-
"expo-widgets": "~58.0.
|
|
100
|
-
"jest-expo": "~58.0.
|
|
99
|
+
"expo-widgets": "~58.0.2",
|
|
100
|
+
"jest-expo": "~58.0.2",
|
|
101
101
|
"lottie-react-native": "~7.5.0",
|
|
102
102
|
"react": "19.2.3",
|
|
103
103
|
"react-dom": "19.2.3",
|
|
104
|
-
"react-native": "0.
|
|
104
|
+
"react-native": "0.88.0-rc.0",
|
|
105
105
|
"react-native-web": "~0.21.0",
|
|
106
106
|
"react-native-gesture-handler": "~3.2.1",
|
|
107
107
|
"react-native-keyboard-controller": "1.22.4",
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
2
2
|
|
|
3
3
|
import Foundation
|
|
4
|
-
import ExpoModulesCore
|
|
5
4
|
import React
|
|
6
5
|
#if canImport(ExpoObjC)
|
|
7
6
|
import ExpoObjC
|
|
@@ -15,14 +14,18 @@ import ExpoObjC
|
|
|
15
14
|
|
|
16
15
|
Responsibilities:
|
|
17
16
|
- Create the `UIWindow` from the connecting `UIWindowScene` and start React Native into it.
|
|
18
|
-
- Re-feed scene life-cycle, URL,
|
|
19
|
-
|
|
17
|
+
- Re-feed scene life-cycle, URL, user-activity, and quick-action events to the app delegate.
|
|
18
|
+
|
|
19
|
+
Requires the app delegate to be an `ExpoAppDelegate`; it forwards every event to the subscribers,
|
|
20
|
+
so one call reaches both subscribers and `AppDelegate` overrides.
|
|
20
21
|
*/
|
|
21
22
|
@available(iOSApplicationExtension, unavailable)
|
|
22
23
|
@objc(EXExpoAppSceneDelegate)
|
|
23
24
|
open class ExpoAppSceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|
24
25
|
open var window: UIWindow?
|
|
25
26
|
|
|
27
|
+
let forwarder = SceneEventForwarder()
|
|
28
|
+
|
|
26
29
|
open func scene(
|
|
27
30
|
_ scene: UIScene,
|
|
28
31
|
willConnectTo session: UISceneSession,
|
|
@@ -31,12 +34,14 @@ open class ExpoAppSceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|
|
31
34
|
guard let windowScene = scene as? UIWindowScene else {
|
|
32
35
|
return
|
|
33
36
|
}
|
|
34
|
-
guard let
|
|
37
|
+
guard let appDelegate = UIApplication.shared.delegate as? ExpoAppDelegate,
|
|
38
|
+
let provider = appDelegate as? ExpoReactNativeFactoryProvider,
|
|
35
39
|
let factory = provider.reactNativeFactory else {
|
|
36
40
|
fatalError(
|
|
37
|
-
"ExpoAppSceneDelegate couldn't start React Native because the app delegate
|
|
38
|
-
+ "React Native factory. Make sure your AppDelegate
|
|
39
|
-
+ "creates its
|
|
41
|
+
"ExpoAppSceneDelegate couldn't start React Native because the app delegate isn't an "
|
|
42
|
+
+ "ExpoAppDelegate that provides a React Native factory. Make sure your AppDelegate subclasses "
|
|
43
|
+
+ "ExpoAppDelegate, conforms to ExpoReactNativeFactoryProvider and creates its "
|
|
44
|
+
+ "RCTReactNativeFactory in application(_:didFinishLaunchingWithOptions:)."
|
|
40
45
|
)
|
|
41
46
|
}
|
|
42
47
|
|
|
@@ -64,43 +69,76 @@ open class ExpoAppSceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|
|
64
69
|
)
|
|
65
70
|
|
|
66
71
|
// Deep links / universal links.
|
|
67
|
-
|
|
68
|
-
|
|
72
|
+
connectionOptions.urlContexts.forEach {
|
|
73
|
+
forwarder.open(url: $0.url, options: Self.openURLOptions(from: $0.options))
|
|
74
|
+
}
|
|
75
|
+
connectionOptions.userActivities.forEach { forwarder.continue($0) }
|
|
76
|
+
|
|
77
|
+
#if os(iOS)
|
|
78
|
+
// A quick action that cold-starts the app arrives here instead of in
|
|
79
|
+
// `windowScene(_:performActionFor:completionHandler:)`, which UIKit only calls while running.
|
|
80
|
+
if let shortcutItem = connectionOptions.shortcutItem {
|
|
81
|
+
forwarder.perform(shortcutItem) { _ in }
|
|
82
|
+
}
|
|
83
|
+
#endif
|
|
69
84
|
}
|
|
70
85
|
|
|
71
86
|
open func sceneDidDisconnect(_ scene: UIScene) {
|
|
72
87
|
window = nil
|
|
73
88
|
}
|
|
74
89
|
|
|
75
|
-
// In the scene lifecycle UIKit no longer calls the app delegate equivalents, so we forward
|
|
76
|
-
// these to the subscriber manager to preserve existing subscriber behavior.
|
|
77
|
-
|
|
78
90
|
open func sceneDidBecomeActive(_ scene: UIScene) {
|
|
79
|
-
|
|
91
|
+
forwarder.didBecomeActive()
|
|
80
92
|
}
|
|
81
93
|
|
|
82
94
|
open func sceneWillResignActive(_ scene: UIScene) {
|
|
83
|
-
|
|
95
|
+
forwarder.willResignActive()
|
|
84
96
|
}
|
|
85
97
|
|
|
86
98
|
open func sceneWillEnterForeground(_ scene: UIScene) {
|
|
87
|
-
|
|
99
|
+
forwarder.willEnterForeground()
|
|
88
100
|
}
|
|
89
101
|
|
|
90
102
|
open func sceneDidEnterBackground(_ scene: UIScene) {
|
|
91
|
-
|
|
103
|
+
forwarder.didEnterBackground()
|
|
92
104
|
}
|
|
93
105
|
|
|
94
106
|
open func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
|
|
95
|
-
Self.
|
|
107
|
+
URLContexts.forEach { forwarder.open(url: $0.url, options: Self.openURLOptions(from: $0.options)) }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
open func scene(_ scene: UIScene, willContinueUserActivityWithType userActivityType: String) {
|
|
111
|
+
forwarder.willContinueUserActivity(withType: userActivityType)
|
|
96
112
|
}
|
|
97
113
|
|
|
98
114
|
open func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
|
|
99
|
-
|
|
115
|
+
forwarder.continue(userActivity)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
open func scene(
|
|
119
|
+
_ scene: UIScene,
|
|
120
|
+
didFailToContinueUserActivityWithType userActivityType: String,
|
|
121
|
+
error: Error
|
|
122
|
+
) {
|
|
123
|
+
forwarder.didFailToContinueUserActivity(withType: userActivityType, error: error)
|
|
100
124
|
}
|
|
125
|
+
|
|
126
|
+
open func scene(_ scene: UIScene, didUpdate userActivity: NSUserActivity) {
|
|
127
|
+
forwarder.didUpdate(userActivity)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
#if os(iOS)
|
|
131
|
+
open func windowScene(
|
|
132
|
+
_ windowScene: UIWindowScene,
|
|
133
|
+
performActionFor shortcutItem: UIApplicationShortcutItem,
|
|
134
|
+
completionHandler: @escaping (Bool) -> Void
|
|
135
|
+
) {
|
|
136
|
+
forwarder.perform(shortcutItem, completionHandler: completionHandler)
|
|
137
|
+
}
|
|
138
|
+
#endif
|
|
101
139
|
}
|
|
102
140
|
|
|
103
|
-
// MARK: - Launch options
|
|
141
|
+
// MARK: - Launch options
|
|
104
142
|
|
|
105
143
|
@available(iOSApplicationExtension, unavailable)
|
|
106
144
|
extension ExpoAppSceneDelegate {
|
|
@@ -132,29 +170,6 @@ extension ExpoAppSceneDelegate {
|
|
|
132
170
|
return launchOptions.isEmpty ? nil : launchOptions
|
|
133
171
|
}
|
|
134
172
|
|
|
135
|
-
/// Pass incoming URL contexts to both the subscriber manager and `RCTLinkingManager`.
|
|
136
|
-
public static func route(urlContexts: Set<UIOpenURLContext>) {
|
|
137
|
-
for context in urlContexts {
|
|
138
|
-
let options = openURLOptions(from: context.options)
|
|
139
|
-
_ = ExpoAppDelegateSubscriberManager.application(UIApplication.shared, open: context.url, options: options)
|
|
140
|
-
RCTLinkingManager.application(UIApplication.shared, open: context.url, options: options)
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/// Passes an incoming `NSUserActivity` to both the subscriber manager and `RCTLinkingManager`.
|
|
145
|
-
public static func route(userActivity: NSUserActivity) {
|
|
146
|
-
_ = ExpoAppDelegateSubscriberManager.application(
|
|
147
|
-
UIApplication.shared,
|
|
148
|
-
continue: userActivity,
|
|
149
|
-
restorationHandler: { _ in }
|
|
150
|
-
)
|
|
151
|
-
RCTLinkingManager.application(
|
|
152
|
-
UIApplication.shared,
|
|
153
|
-
continue: userActivity,
|
|
154
|
-
restorationHandler: { _ in }
|
|
155
|
-
)
|
|
156
|
-
}
|
|
157
|
-
|
|
158
173
|
private static func openURLOptions(
|
|
159
174
|
from sceneOptions: UIScene.OpenURLOptions
|
|
160
175
|
) -> [UIApplication.OpenURLOptionsKey: Any] {
|