expo 53.0.17 → 53.0.19

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.
@@ -32,7 +32,7 @@ buildscript {
32
32
  def reactNativeVersion = project.extensions.getByType(ExpoModuleExtension).reactNativeVersion
33
33
 
34
34
  group = 'host.exp.exponent'
35
- version = '53.0.17'
35
+ version = '53.0.19'
36
36
 
37
37
  expoModule {
38
38
  // We can't prebuild the module because it depends on the generated files.
@@ -43,7 +43,7 @@ android {
43
43
  namespace "expo.core"
44
44
  defaultConfig {
45
45
  versionCode 1
46
- versionName "53.0.17"
46
+ versionName "53.0.19"
47
47
  consumerProguardFiles("proguard-rules.pro")
48
48
  }
49
49
  testOptions {
@@ -29,8 +29,13 @@ import expo.modules.core.interfaces.ReactActivityHandler.DelayLoadAppHandler
29
29
  import expo.modules.core.interfaces.ReactActivityLifecycleListener
30
30
  import expo.modules.kotlin.Utils
31
31
  import expo.modules.rncompatibility.ReactNativeFeatureFlags
32
+ import kotlinx.coroutines.CompletableDeferred
33
+ import kotlinx.coroutines.CoroutineScope
32
34
  import kotlinx.coroutines.CoroutineStart
35
+ import kotlinx.coroutines.Dispatchers
33
36
  import kotlinx.coroutines.launch
37
+ import kotlinx.coroutines.sync.Mutex
38
+ import kotlinx.coroutines.sync.withLock
34
39
  import java.lang.reflect.Field
35
40
  import java.lang.reflect.Method
36
41
  import java.lang.reflect.Modifier
@@ -63,10 +68,25 @@ class ReactActivityDelegateWrapper(
63
68
  }
64
69
 
65
70
  /**
66
- * When the app delay for `loadApp`, the React Native lifecycle will be disrupted.
67
- * This flag indicates we should emit `onResume` after `loadApp`.
71
+ * A deferred that indicates when the app loading is ready
68
72
  */
69
- private var shouldEmitPendingResume = false
73
+ private val loadAppReady = CompletableDeferred<Unit>()
74
+
75
+ /**
76
+ * A mutex to ensure all coroutines in a scope are running in atomic way.
77
+ *
78
+ * This is to act like [Activity] lifecycle,
79
+ * e.g. all work in [onResume] should be executed after all work in [onCreate] finished.
80
+ */
81
+ private val mutex = Mutex()
82
+
83
+ /**
84
+ * A [CoroutineScope] that binds its lifecycle as [ReactActivityDelegateWrapper].
85
+ * This is used for [onDestroy] because we need a longer lifecycle scope to call [onDestroy]
86
+ */
87
+ private val applicationCoroutineScope: CoroutineScope by lazy {
88
+ CoroutineScope(Dispatchers.Main)
89
+ }
70
90
 
71
91
  //region ReactActivityDelegate
72
92
 
@@ -99,7 +119,7 @@ class ReactActivityDelegateWrapper(
99
119
  }
100
120
 
101
121
  override fun loadApp(appKey: String?) {
102
- activity.lifecycleScope.launch(start = CoroutineStart.UNDISPATCHED) {
122
+ launchLifecycleScopeWithLock(start = CoroutineStart.UNDISPATCHED) {
103
123
  loadAppImpl(appKey, supportsDelayLoad = true)
104
124
  }
105
125
  }
@@ -127,8 +147,9 @@ class ReactActivityDelegateWrapper(
127
147
  // Instead we intercept `ReactActivityDelegate.onCreate` and replace the `mReactDelegate` with our version.
128
148
  // That's not ideal but works.
129
149
 
130
- activity.lifecycleScope.launch(start = CoroutineStart.UNDISPATCHED) {
150
+ launchLifecycleScopeWithLock(start = CoroutineStart.UNDISPATCHED) {
131
151
  awaitDelayLoadAppWhenReady(delayLoadAppHandler)
152
+ loadAppReady.complete(Unit)
132
153
 
133
154
  if (VERSION.SDK_INT >= Build.VERSION_CODES.O && isWideColorGamutEnabled) {
134
155
  activity.window.colorMode = ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT
@@ -172,69 +193,70 @@ class ReactActivityDelegateWrapper(
172
193
  }
173
194
 
174
195
  override fun onResume() {
175
- if (shouldEmitPendingResume) {
176
- return
177
- }
178
- delegate.onResume()
179
- reactActivityLifecycleListeners.forEach { listener ->
180
- listener.onResume(activity)
196
+ launchLifecycleScopeWithLock {
197
+ loadAppReady.await()
198
+ delegate.onResume()
199
+ reactActivityLifecycleListeners.forEach { listener ->
200
+ listener.onResume(activity)
201
+ }
181
202
  }
182
203
  }
183
204
 
184
205
  override fun onPause() {
185
- // If app is stopped before the delayed `loadApp`, we should cancel the pending resume
186
- // and avoid propagating the pause event because the state was never resumed.
187
- if (shouldEmitPendingResume) {
188
- shouldEmitPendingResume = false
189
- return
190
- }
191
- reactActivityLifecycleListeners.forEach { listener ->
192
- listener.onPause(activity)
193
- }
194
- if (delayLoadAppHandler != null) {
195
- try {
196
- // For the delay load case, we may enter a different call flow than react-native.
197
- // For example, Activity stopped before delay load finished.
198
- // We stop before the ReactActivityDelegate gets a chance to set up.
199
- // In this case, we should catch the exceptions.
206
+ launchLifecycleScopeWithLock {
207
+ loadAppReady.await()
208
+ reactActivityLifecycleListeners.forEach { listener ->
209
+ listener.onPause(activity)
210
+ }
211
+ if (delayLoadAppHandler != null) {
212
+ try {
213
+ // For the delay load case, we may enter a different call flow than react-native.
214
+ // For example, Activity stopped before delay load finished.
215
+ // We stop before the ReactActivityDelegate gets a chance to set up.
216
+ // In this case, we should catch the exceptions.
217
+ delegate.onPause()
218
+ } catch (e: Exception) {
219
+ Log.e(TAG, "Exception occurred during onPause with delayed app loading", e)
220
+ }
221
+ } else {
200
222
  delegate.onPause()
201
- } catch (e: Exception) {
202
- Log.e(TAG, "Exception occurred during onPause with delayed app loading", e)
203
223
  }
204
- } else {
205
- delegate.onPause()
206
224
  }
207
225
  }
208
226
 
209
227
  override fun onUserLeaveHint() {
210
- reactActivityLifecycleListeners.forEach { listener ->
211
- listener.onUserLeaveHint(activity)
228
+ launchLifecycleScopeWithLock {
229
+ loadAppReady.await()
230
+ reactActivityLifecycleListeners.forEach { listener ->
231
+ listener.onUserLeaveHint(activity)
232
+ }
233
+ delegate.onUserLeaveHint()
212
234
  }
213
- delegate.onUserLeaveHint()
214
235
  }
215
236
 
216
237
  override fun onDestroy() {
217
- // If app is stopped before the delayed `loadApp`, we should cancel the pending resume
218
- // and avoid propagating the destroy event because the state was never resumed.
219
- if (shouldEmitPendingResume) {
220
- shouldEmitPendingResume = false
221
- return
222
- }
223
- reactActivityLifecycleListeners.forEach { listener ->
224
- listener.onDestroy(activity)
225
- }
226
- if (delayLoadAppHandler != null) {
227
- try {
228
- // For the delay load case, we may enter a different call flow than react-native.
229
- // For example, Activity stopped before delay load finished.
230
- // We stop before the ReactActivityDelegate gets a chance to set up.
231
- // In this case, we should catch the exceptions.
232
- delegate.onDestroy()
233
- } catch (e: Exception) {
234
- Log.e(TAG, "Exception occurred during onDestroy with delayed app loading", e)
238
+ // Note: use our `coroutineScope` for onDestroy here
239
+ // because the lifecycleScope destroyed before the executions.
240
+ applicationCoroutineScope.launch {
241
+ mutex.withLock {
242
+ loadAppReady.await()
243
+ reactActivityLifecycleListeners.forEach { listener ->
244
+ listener.onDestroy(activity)
245
+ }
246
+ if (delayLoadAppHandler != null) {
247
+ try {
248
+ // For the delay load case, we may enter a different call flow than react-native.
249
+ // For example, Activity stopped before delay load finished.
250
+ // We stop before the ReactActivityDelegate gets a chance to set up.
251
+ // In this case, we should catch the exceptions.
252
+ delegate.onDestroy()
253
+ } catch (e: Exception) {
254
+ Log.e(TAG, "Exception occurred during onDestroy with delayed app loading", e)
255
+ }
256
+ } else {
257
+ delegate.onDestroy()
258
+ }
235
259
  }
236
- } else {
237
- delegate.onDestroy()
238
260
  }
239
261
  }
240
262
 
@@ -252,20 +274,28 @@ class ReactActivityDelegateWrapper(
252
274
  *
253
275
  * TODO (@bbarthec): fix it upstream?
254
276
  */
255
- if (!ReactNativeFeatureFlags.enableBridgelessArchitecture && delegate.reactInstanceManager.currentReactContext == null) {
256
- val reactContextListener = object : ReactInstanceEventListener {
257
- override fun onReactContextInitialized(context: ReactContext) {
258
- delegate.reactInstanceManager.removeReactInstanceEventListener(this)
259
- delegate.onActivityResult(requestCode, resultCode, data)
277
+ launchLifecycleScopeWithLock {
278
+ loadAppReady.await()
279
+ if (!ReactNativeFeatureFlags.enableBridgelessArchitecture && delegate.reactInstanceManager.currentReactContext == null) {
280
+ val reactContextListener = object : ReactInstanceEventListener {
281
+ override fun onReactContextInitialized(context: ReactContext) {
282
+ delegate.reactInstanceManager.removeReactInstanceEventListener(this)
283
+ delegate.onActivityResult(requestCode, resultCode, data)
284
+ }
260
285
  }
286
+ return@launchLifecycleScopeWithLock delegate.reactInstanceManager.addReactInstanceEventListener(
287
+ reactContextListener
288
+ )
261
289
  }
262
- return delegate.reactInstanceManager.addReactInstanceEventListener(reactContextListener)
263
- }
264
290
 
265
- delegate.onActivityResult(requestCode, resultCode, data)
291
+ delegate.onActivityResult(requestCode, resultCode, data)
292
+ }
266
293
  }
267
294
 
268
295
  override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
296
+ if (!loadAppReady.isCompleted) {
297
+ return false
298
+ }
269
299
  // if any of the handlers return true, intentionally consume the event instead of passing it
270
300
  // through to the delegate
271
301
  return reactActivityHandlers
@@ -274,6 +304,9 @@ class ReactActivityDelegateWrapper(
274
304
  }
275
305
 
276
306
  override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
307
+ if (!loadAppReady.isCompleted) {
308
+ return false
309
+ }
277
310
  // if any of the handlers return true, intentionally consume the event instead of passing it
278
311
  // through to the delegate
279
312
  return reactActivityHandlers
@@ -282,6 +315,9 @@ class ReactActivityDelegateWrapper(
282
315
  }
283
316
 
284
317
  override fun onKeyLongPress(keyCode: Int, event: KeyEvent?): Boolean {
318
+ if (!loadAppReady.isCompleted) {
319
+ return false
320
+ }
285
321
  // if any of the handlers return true, intentionally consume the event instead of passing it
286
322
  // through to the delegate
287
323
  return reactActivityHandlers
@@ -290,6 +326,9 @@ class ReactActivityDelegateWrapper(
290
326
  }
291
327
 
292
328
  override fun onBackPressed(): Boolean {
329
+ if (!loadAppReady.isCompleted) {
330
+ return false
331
+ }
293
332
  val listenerResult = reactActivityLifecycleListeners
294
333
  .map(ReactActivityLifecycleListener::onBackPressed)
295
334
  .fold(false) { accu, current -> accu || current }
@@ -298,6 +337,9 @@ class ReactActivityDelegateWrapper(
298
337
  }
299
338
 
300
339
  override fun onNewIntent(intent: Intent?): Boolean {
340
+ if (!loadAppReady.isCompleted) {
341
+ return false
342
+ }
301
343
  val listenerResult = reactActivityLifecycleListeners
302
344
  .map { it.onNewIntent(intent) }
303
345
  .fold(false) { accu, current -> accu || current }
@@ -306,15 +348,24 @@ class ReactActivityDelegateWrapper(
306
348
  }
307
349
 
308
350
  override fun onWindowFocusChanged(hasFocus: Boolean) {
309
- delegate.onWindowFocusChanged(hasFocus)
351
+ launchLifecycleScopeWithLock {
352
+ loadAppReady.await()
353
+ delegate.onWindowFocusChanged(hasFocus)
354
+ }
310
355
  }
311
356
 
312
357
  override fun requestPermissions(permissions: Array<out String>?, requestCode: Int, listener: PermissionListener?) {
313
- delegate.requestPermissions(permissions, requestCode, listener)
358
+ launchLifecycleScopeWithLock {
359
+ loadAppReady.await()
360
+ delegate.requestPermissions(permissions, requestCode, listener)
361
+ }
314
362
  }
315
363
 
316
364
  override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>?, grantResults: IntArray?) {
317
- delegate.onRequestPermissionsResult(requestCode, permissions, grantResults)
365
+ launchLifecycleScopeWithLock {
366
+ loadAppReady.await()
367
+ delegate.onRequestPermissionsResult(requestCode, permissions, grantResults)
368
+ }
318
369
  }
319
370
 
320
371
  override fun getContext(): Context {
@@ -338,7 +389,10 @@ class ReactActivityDelegateWrapper(
338
389
  }
339
390
 
340
391
  override fun onConfigurationChanged(newConfig: Configuration?) {
341
- delegate.onConfigurationChanged(newConfig)
392
+ launchLifecycleScopeWithLock {
393
+ loadAppReady.await()
394
+ delegate.onConfigurationChanged(newConfig)
395
+ }
342
396
  }
343
397
 
344
398
  //endregion
@@ -401,10 +455,6 @@ class ReactActivityDelegateWrapper(
401
455
  reactActivityLifecycleListeners.forEach { listener ->
402
456
  listener.onContentChanged(activity)
403
457
  }
404
- if (shouldEmitPendingResume) {
405
- shouldEmitPendingResume = false
406
- onResume()
407
- }
408
458
  return
409
459
  }
410
460
 
@@ -412,17 +462,12 @@ class ReactActivityDelegateWrapper(
412
462
  reactActivityLifecycleListeners.forEach { listener ->
413
463
  listener.onContentChanged(activity)
414
464
  }
415
- if (shouldEmitPendingResume) {
416
- shouldEmitPendingResume = false
417
- onResume()
418
- }
419
465
  }
420
466
 
421
467
  private suspend fun awaitDelayLoadAppWhenReady(delayLoadAppHandler: DelayLoadAppHandler?) {
422
468
  if (delayLoadAppHandler == null) {
423
469
  return
424
470
  }
425
- shouldEmitPendingResume = true
426
471
  suspendCoroutine { continuation ->
427
472
  delayLoadAppHandler.whenReady {
428
473
  Utils.assertMainThread()
@@ -431,6 +476,26 @@ class ReactActivityDelegateWrapper(
431
476
  }
432
477
  }
433
478
 
479
+ private fun launchLifecycleScopeWithLock(
480
+ start: CoroutineStart = CoroutineStart.DEFAULT,
481
+ block: suspend CoroutineScope.() -> Unit
482
+ ) {
483
+ activity.lifecycleScope.launch(start = start) {
484
+ mutex.withLock {
485
+ block()
486
+ }
487
+ }
488
+ }
489
+
490
+ /**
491
+ * Set the [loadAppReady] to completed state.
492
+ * This is only for unit tests when a test setups mocks and skips the [Activity] lifecycle.
493
+ */
494
+ @VisibleForTesting
495
+ internal fun setLoadAppReadyForTesting() {
496
+ loadAppReady.complete(Unit)
497
+ }
498
+
434
499
  //endregion
435
500
 
436
501
  companion object {
@@ -135,7 +135,7 @@ internal class ReactActivityDelegateWrapperDelayLoadTest {
135
135
  verify(exactly = 0) { spyDelegate.onResume() }
136
136
 
137
137
  callbackSlot.captured.run()
138
- verify(exactly = 2) { spyDelegateWrapper.onResume() }
138
+ verify(exactly = 1) { spyDelegateWrapper.onResume() }
139
139
  verify(exactly = 1) { spyDelegate.onResume() }
140
140
  verify(exactly = 0) { spyDelegateWrapper.onPause() }
141
141
  verify(exactly = 0) { spyDelegateWrapper.onDestroy() }
@@ -173,60 +173,6 @@ internal class ReactActivityDelegateWrapperDelayLoadTest {
173
173
  verify(exactly = 1) { spyDelegate.onDestroy() }
174
174
  }
175
175
 
176
- @Test
177
- fun `should cancel pending resume if activity pause before delay load finished`() = runTest {
178
- every { ExpoModulesPackage.Companion.packageList } returns listOf(mockPackageWithDelay)
179
-
180
- val callbackSlot = slot<Runnable>()
181
- every { delayLoadAppHandler.whenReady(capture(callbackSlot)) } answers {
182
- // Don't call the callback immediately to simulate delay
183
- }
184
-
185
- activityController = Robolectric.buildActivity(MockActivity::class.java)
186
- .also {
187
- val activity = it.get()
188
- (activity.application as MockApplication).bindCurrentActivity(activity)
189
- }
190
- .setup()
191
- val spyDelegateWrapper = activity.reactActivityDelegate as ReactActivityDelegateWrapper
192
- val spyDelegate = spyDelegateWrapper.delegate
193
-
194
- verify(exactly = 1) { spyDelegateWrapper.onCreate(any()) }
195
- verify(exactly = 1) { spyDelegateWrapper.onResume() }
196
- verify(exactly = 0) { spyDelegate.onResume() }
197
-
198
- activityController.pause()
199
- callbackSlot.captured.run()
200
- verify(exactly = 0) { spyDelegate.onResume() }
201
- }
202
-
203
- @Test
204
- fun `should cancel pending resume if activity stop before delay load finished`() = runTest {
205
- every { ExpoModulesPackage.Companion.packageList } returns listOf(mockPackageWithDelay)
206
-
207
- val callbackSlot = slot<Runnable>()
208
- every { delayLoadAppHandler.whenReady(capture(callbackSlot)) } answers {
209
- // Don't call the callback immediately to simulate delay
210
- }
211
-
212
- activityController = Robolectric.buildActivity(MockActivity::class.java)
213
- .also {
214
- val activity = it.get()
215
- (activity.application as MockApplication).bindCurrentActivity(activity)
216
- }
217
- .setup()
218
- val spyDelegateWrapper = activity.reactActivityDelegate as ReactActivityDelegateWrapper
219
- val spyDelegate = spyDelegateWrapper.delegate
220
-
221
- verify(exactly = 1) { spyDelegateWrapper.onCreate(any()) }
222
- verify(exactly = 1) { spyDelegateWrapper.onResume() }
223
- verify(exactly = 0) { spyDelegate.onResume() }
224
-
225
- activityController.pause().stop()
226
- callbackSlot.captured.run()
227
- verify(exactly = 0) { spyDelegate.onResume() }
228
- }
229
-
230
176
  @Test
231
177
  fun `should cancel pending resume if activity destroy before delay load finished`() = runTest {
232
178
  every { ExpoModulesPackage.Companion.packageList } returns listOf(mockPackageWithDelay)
@@ -20,9 +20,9 @@ import org.junit.Before
20
20
  import org.junit.Test
21
21
 
22
22
  internal class ReactActivityDelegateWrapperTest {
23
- lateinit var mockPackage0: MockPackage
23
+ private lateinit var mockPackage0: MockPackage
24
24
 
25
- lateinit var mockPackage1: MockPackage
25
+ private lateinit var mockPackage1: MockPackage
26
26
 
27
27
  @RelaxedMockK
28
28
  lateinit var activity: ReactActivity
@@ -47,6 +47,7 @@ internal class ReactActivityDelegateWrapperTest {
47
47
  @Test
48
48
  fun `onBackPressed should call each handler's callback just once`() {
49
49
  val delegateWrapper = ReactActivityDelegateWrapper(activity, delegate)
50
+ delegateWrapper.setLoadAppReadyForTesting()
50
51
  every { mockPackage0.reactActivityLifecycleListener.onBackPressed() } returns true
51
52
 
52
53
  delegateWrapper.onBackPressed()
@@ -59,6 +60,7 @@ internal class ReactActivityDelegateWrapperTest {
59
60
  @Test
60
61
  fun `onBackPressed should return true if someone returns true`() {
61
62
  val delegateWrapper = ReactActivityDelegateWrapper(activity, delegate)
63
+ delegateWrapper.setLoadAppReadyForTesting()
62
64
  every { mockPackage0.reactActivityLifecycleListener.onBackPressed() } returns false
63
65
  every { mockPackage1.reactActivityLifecycleListener.onBackPressed() } returns true
64
66
  every { delegate.onBackPressed() } returns false
@@ -71,6 +73,7 @@ internal class ReactActivityDelegateWrapperTest {
71
73
  fun `onNewIntent should call each handler's callback just once`() {
72
74
  val intent = mockk<Intent>()
73
75
  val delegateWrapper = ReactActivityDelegateWrapper(activity, delegate)
76
+ delegateWrapper.setLoadAppReadyForTesting()
74
77
  every { mockPackage0.reactActivityLifecycleListener.onNewIntent(intent) } returns false
75
78
  every { mockPackage1.reactActivityLifecycleListener.onNewIntent(intent) } returns true
76
79
  every { delegate.onNewIntent(intent) } returns false
@@ -86,6 +89,7 @@ internal class ReactActivityDelegateWrapperTest {
86
89
  fun `onNewIntent should return true if someone returns true`() {
87
90
  val intent = mockk<Intent>()
88
91
  val delegateWrapper = ReactActivityDelegateWrapper(activity, delegate)
92
+ delegateWrapper.setLoadAppReadyForTesting()
89
93
  every { mockPackage0.reactActivityLifecycleListener.onNewIntent(intent) } returns false
90
94
  every { mockPackage1.reactActivityLifecycleListener.onNewIntent(intent) } returns true
91
95
  every { delegate.onNewIntent(intent) } returns false
@@ -97,7 +101,7 @@ internal class ReactActivityDelegateWrapperTest {
97
101
 
98
102
  internal class MockPackage : Package {
99
103
  val reactActivityLifecycleListener = mockk<ReactActivityLifecycleListener>(relaxed = true)
100
- val reactActivityHandler = mockk<ReactActivityHandler>(relaxed = true)
104
+ private val reactActivityHandler = mockk<ReactActivityHandler>(relaxed = true)
101
105
 
102
106
  override fun createReactActivityLifecycleListeners(activityContext: Context?): List<ReactActivityLifecycleListener> {
103
107
  return listOf(reactActivityLifecycleListener)
@@ -19,7 +19,7 @@
19
19
  "expo-apple-authentication": "~7.2.4",
20
20
  "expo-application": "~6.1.5",
21
21
  "expo-asset": "~11.1.7",
22
- "expo-audio": "~0.4.7",
22
+ "expo-audio": "~0.4.8",
23
23
  "expo-auth-session": "~6.2.1",
24
24
  "expo-av": "~15.1.7",
25
25
  "expo-background-fetch": "~13.1.6",
@@ -65,7 +65,7 @@
65
65
  "expo-modules-core": "~2.4.2",
66
66
  "expo-navigation-bar": "~4.2.7",
67
67
  "expo-network": "~7.1.5",
68
- "expo-notifications": "~0.31.3",
68
+ "expo-notifications": "~0.31.4",
69
69
  "expo-print": "~14.1.4",
70
70
  "expo-live-photo": "~0.1.4",
71
71
  "expo-router": "~5.1.3",
@@ -77,7 +77,7 @@
77
77
  "expo-sms": "~13.1.4",
78
78
  "expo-speech": "~13.1.7",
79
79
  "expo-splash-screen": "~0.30.10",
80
- "expo-sqlite": "~15.2.13",
80
+ "expo-sqlite": "~15.2.14",
81
81
  "expo-status-bar": "~2.2.3",
82
82
  "expo-store-review": "~8.1.5",
83
83
  "expo-symbols": "~0.4.5",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo",
3
- "version": "53.0.17",
3
+ "version": "53.0.19",
4
4
  "description": "The Expo SDK",
5
5
  "main": "src/Expo.ts",
6
6
  "module": "src/Expo.ts",
@@ -73,9 +73,9 @@
73
73
  "homepage": "https://github.com/expo/expo/tree/main/packages/expo",
74
74
  "dependencies": {
75
75
  "@babel/runtime": "^7.20.0",
76
- "@expo/cli": "0.24.18",
77
- "@expo/config": "~11.0.12",
78
- "@expo/config-plugins": "~10.1.1",
76
+ "@expo/cli": "0.24.20",
77
+ "@expo/config": "~11.0.13",
78
+ "@expo/config-plugins": "~10.1.2",
79
79
  "@expo/fingerprint": "0.13.4",
80
80
  "@expo/metro-config": "0.20.17",
81
81
  "@expo/vector-icons": "^14.0.0",
@@ -85,7 +85,7 @@
85
85
  "expo-file-system": "~18.1.11",
86
86
  "expo-font": "~13.3.2",
87
87
  "expo-keep-awake": "~14.1.4",
88
- "expo-modules-autolinking": "2.1.13",
88
+ "expo-modules-autolinking": "2.1.14",
89
89
  "expo-modules-core": "2.4.2",
90
90
  "react-native-edge-to-edge": "1.6.0",
91
91
  "whatwg-url-without-unicode": "8.0.0-3"
@@ -119,5 +119,5 @@
119
119
  "optional": true
120
120
  }
121
121
  },
122
- "gitHead": "1c4a89b0c0adebb53ef84b4a6ac25864e4652917"
122
+ "gitHead": "134c147ee4274f9688929ac66cfef950947659d0"
123
123
  }