expo-updates 0.26.0 → 0.26.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/CHANGELOG.md +20 -0
- package/android/build.gradle +2 -2
- package/android/proguard-rules.pro +1 -1
- package/android/src/main/java/expo/modules/updates/UpdatesController.kt +5 -5
- package/android/src/main/java/expo/modules/updates/UpdatesModule.kt +22 -9
- package/android/src/main/java/expo/modules/updates/errorrecovery/ErrorRecovery.kt +2 -2
- package/android/src/main/java/expo/modules/updates/events/IUpdatesEventManager.kt +4 -4
- package/android/src/main/java/expo/modules/updates/events/NoOpUpdatesEventManager.kt +2 -2
- package/android/src/main/java/expo/modules/updates/events/UpdatesEventManager.kt +8 -12
- package/android/src/main/java/expo/modules/updates/loader/FileDownloader.kt +1 -1
- package/android/src/main/java/expo/modules/updates/statemachine/UpdatesStateContext.kt +1 -13
- package/e2e/fixtures/Updates.e2e.ts +30 -44
- package/e2e/setup/project.ts +3 -0
- package/ios/EXUpdates/AppController.swift +4 -4
- package/ios/EXUpdates/Events/NoOpUpdatesEventManager.swift +1 -1
- package/ios/EXUpdates/Events/QueueUpdatesEventManager.swift +6 -12
- package/ios/EXUpdates/Events/UpdatesEventManager.swift +5 -1
- package/ios/EXUpdates/UpdatesModule.swift +15 -5
- package/ios/EXUpdates/UpdatesStateMachine.swift +0 -1
- package/ios/Tests/UpdatesStateMachineSpec.swift +2 -3
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,26 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 0.26.2 — 2024-10-24
|
|
14
|
+
|
|
15
|
+
### 🐛 Bug fixes
|
|
16
|
+
|
|
17
|
+
- Move event emitting responsibility to module. ([#32248](https://github.com/expo/expo/pull/32248) by [@wschurman](https://github.com/wschurman))
|
|
18
|
+
|
|
19
|
+
### 💡 Others
|
|
20
|
+
|
|
21
|
+
- Use enum event in OnStartObserving and OnStopObserving. ([#32252](https://github.com/expo/expo/pull/32252) by [@wschurman](https://github.com/wschurman))
|
|
22
|
+
|
|
23
|
+
## 0.26.1 — 2024-10-22
|
|
24
|
+
|
|
25
|
+
### 🐛 Bug fixes
|
|
26
|
+
|
|
27
|
+
- Fixed Android launch crash when R8 is enabled. ([#32226](https://github.com/expo/expo/pull/32226) by [@kudo](https://github.com/kudo))
|
|
28
|
+
|
|
29
|
+
### 💡 Others
|
|
30
|
+
|
|
31
|
+
- Fixed updates E2E tests. ([#32226](https://github.com/expo/expo/pull/32226) by [@kudo](https://github.com/kudo))
|
|
32
|
+
|
|
13
33
|
## 0.26.0 — 2024-10-22
|
|
14
34
|
|
|
15
35
|
### 🛠 Breaking changes
|
package/android/build.gradle
CHANGED
|
@@ -16,7 +16,7 @@ apply plugin: 'com.android.library'
|
|
|
16
16
|
apply plugin: 'com.google.devtools.ksp'
|
|
17
17
|
|
|
18
18
|
group = 'host.exp.exponent'
|
|
19
|
-
version = '0.26.
|
|
19
|
+
version = '0.26.2'
|
|
20
20
|
|
|
21
21
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
22
22
|
apply from: expoModulesCorePlugin
|
|
@@ -62,7 +62,7 @@ android {
|
|
|
62
62
|
namespace "expo.modules.updates"
|
|
63
63
|
defaultConfig {
|
|
64
64
|
versionCode 31
|
|
65
|
-
versionName '0.26.
|
|
65
|
+
versionName '0.26.2'
|
|
66
66
|
consumerProguardFiles("proguard-rules.pro")
|
|
67
67
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
68
68
|
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
-keepclassmembers class com.facebook.react.devsupport.ReleaseDevSupportManager {
|
|
6
|
-
private final com.facebook.react.bridge.DefaultJSExceptionHandler
|
|
6
|
+
private final com.facebook.react.bridge.DefaultJSExceptionHandler defaultJSExceptionHandler;
|
|
7
7
|
}
|
|
@@ -2,7 +2,7 @@ package expo.modules.updates
|
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
4
|
import com.facebook.react.ReactApplication
|
|
5
|
-
import expo.modules.
|
|
5
|
+
import expo.modules.updates.events.IUpdatesEventManagerObserver
|
|
6
6
|
import expo.modules.updates.loader.LoaderTask
|
|
7
7
|
import expo.modules.updates.logging.UpdatesErrorCode
|
|
8
8
|
import expo.modules.updates.logging.UpdatesLogger
|
|
@@ -151,13 +151,13 @@ class UpdatesController {
|
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
internal fun
|
|
155
|
-
singletonInstance?.eventManager?.
|
|
154
|
+
internal fun setUpdatesEventManagerObserver(observer: WeakReference<IUpdatesEventManagerObserver>) {
|
|
155
|
+
singletonInstance?.eventManager?.observer = observer
|
|
156
156
|
singletonInstance?.onEventListenerStartObserving()
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
internal fun
|
|
160
|
-
singletonInstance?.eventManager?.
|
|
159
|
+
internal fun removeUpdatesEventManagerObserver() {
|
|
160
|
+
singletonInstance?.eventManager?.observer = null
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
}
|
|
@@ -8,19 +8,26 @@ import expo.modules.kotlin.exception.CodedException
|
|
|
8
8
|
import expo.modules.kotlin.exception.Exceptions
|
|
9
9
|
import expo.modules.kotlin.modules.Module
|
|
10
10
|
import expo.modules.kotlin.modules.ModuleDefinition
|
|
11
|
-
import expo.modules.
|
|
11
|
+
import expo.modules.kotlin.types.Enumerable
|
|
12
|
+
import expo.modules.updates.events.IUpdatesEventManagerObserver
|
|
12
13
|
import expo.modules.updates.logging.UpdatesErrorCode
|
|
13
14
|
import expo.modules.updates.logging.UpdatesLogEntry
|
|
14
15
|
import expo.modules.updates.logging.UpdatesLogReader
|
|
15
16
|
import expo.modules.updates.logging.UpdatesLogger
|
|
17
|
+
import expo.modules.updates.statemachine.UpdatesStateContext
|
|
18
|
+
import java.lang.ref.WeakReference
|
|
16
19
|
import java.util.Date
|
|
17
20
|
|
|
21
|
+
enum class UpdatesJSEvent(val eventName: String) : Enumerable {
|
|
22
|
+
StateChange("Expo.nativeUpdatesStateChangeEvent")
|
|
23
|
+
}
|
|
24
|
+
|
|
18
25
|
/**
|
|
19
26
|
* Exported module which provides to the JS runtime information about the currently running update
|
|
20
27
|
* and updates state, along with methods to check for and download new updates, reload with the
|
|
21
28
|
* newest downloaded update applied, and read/clear native log entries.
|
|
22
29
|
*/
|
|
23
|
-
class UpdatesModule : Module() {
|
|
30
|
+
class UpdatesModule : Module(), IUpdatesEventManagerObserver {
|
|
24
31
|
private val logger: UpdatesLogger
|
|
25
32
|
get() = UpdatesLogger(context)
|
|
26
33
|
|
|
@@ -30,21 +37,23 @@ class UpdatesModule : Module() {
|
|
|
30
37
|
override fun definition() = ModuleDefinition {
|
|
31
38
|
Name("ExpoUpdates")
|
|
32
39
|
|
|
33
|
-
Events(
|
|
34
|
-
UpdatesJSEvent.StateChange.eventName
|
|
35
|
-
)
|
|
40
|
+
Events<UpdatesJSEvent>()
|
|
36
41
|
|
|
37
42
|
Constants {
|
|
38
43
|
UpdatesLogger(context).info("UpdatesModule: getConstants called", UpdatesErrorCode.None)
|
|
39
44
|
UpdatesController.instance.getConstantsForModule().toModuleConstantsMap()
|
|
40
45
|
}
|
|
41
46
|
|
|
42
|
-
OnStartObserving {
|
|
43
|
-
UpdatesController.
|
|
47
|
+
OnStartObserving(UpdatesJSEvent.StateChange) {
|
|
48
|
+
UpdatesController.setUpdatesEventManagerObserver(WeakReference(this@UpdatesModule))
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
OnStopObserving(UpdatesJSEvent.StateChange) {
|
|
52
|
+
UpdatesController.removeUpdatesEventManagerObserver()
|
|
44
53
|
}
|
|
45
54
|
|
|
46
|
-
|
|
47
|
-
UpdatesController.
|
|
55
|
+
OnDestroy {
|
|
56
|
+
UpdatesController.removeUpdatesEventManagerObserver()
|
|
48
57
|
}
|
|
49
58
|
|
|
50
59
|
AsyncFunction("reload") { promise: Promise ->
|
|
@@ -240,4 +249,8 @@ class UpdatesModule : Module() {
|
|
|
240
249
|
)
|
|
241
250
|
}
|
|
242
251
|
}
|
|
252
|
+
|
|
253
|
+
override fun onStateMachineContextEvent(context: UpdatesStateContext) {
|
|
254
|
+
sendEvent(UpdatesJSEvent.StateChange, Bundle().apply { putBundle("context", context.bundle) })
|
|
255
|
+
}
|
|
243
256
|
}
|
|
@@ -120,7 +120,7 @@ class ErrorRecovery(
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
val devSupportManagerClass = devSupportManager.javaClass
|
|
123
|
-
previousExceptionHandler = devSupportManagerClass.getDeclaredField("
|
|
123
|
+
previousExceptionHandler = devSupportManagerClass.getDeclaredField("defaultJSExceptionHandler").let { field ->
|
|
124
124
|
field.isAccessible = true
|
|
125
125
|
val previousValue = field[devSupportManager]
|
|
126
126
|
field[devSupportManager] = defaultJSExceptionHandler
|
|
@@ -152,7 +152,7 @@ class ErrorRecovery(
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
val devSupportManagerClass = devSupportManager.javaClass
|
|
155
|
-
devSupportManagerClass.getDeclaredField("
|
|
155
|
+
devSupportManagerClass.getDeclaredField("defaultJSExceptionHandler").let { field ->
|
|
156
156
|
field.isAccessible = true
|
|
157
157
|
field[devSupportManager] = previousExceptionHandler
|
|
158
158
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
package expo.modules.updates.events
|
|
2
2
|
|
|
3
|
-
import expo.modules.kotlin.events.EventEmitter
|
|
4
3
|
import expo.modules.updates.statemachine.UpdatesStateContext
|
|
4
|
+
import java.lang.ref.WeakReference
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
interface IUpdatesEventManagerObserver {
|
|
7
|
+
fun onStateMachineContextEvent(context: UpdatesStateContext)
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
interface IUpdatesEventManager {
|
|
11
|
-
var
|
|
11
|
+
var observer: WeakReference<IUpdatesEventManagerObserver>?
|
|
12
12
|
fun sendStateMachineContextEvent(context: UpdatesStateContext)
|
|
13
13
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
package expo.modules.updates.events
|
|
2
2
|
|
|
3
|
-
import expo.modules.kotlin.events.EventEmitter
|
|
4
3
|
import expo.modules.updates.statemachine.UpdatesStateContext
|
|
4
|
+
import java.lang.ref.WeakReference
|
|
5
5
|
|
|
6
6
|
class NoOpUpdatesEventManager : IUpdatesEventManager {
|
|
7
|
-
override var
|
|
7
|
+
override var observer: WeakReference<IUpdatesEventManagerObserver>? = null
|
|
8
8
|
override fun sendStateMachineContextEvent(context: UpdatesStateContext) {}
|
|
9
9
|
}
|
|
@@ -1,31 +1,27 @@
|
|
|
1
1
|
package expo.modules.updates.events
|
|
2
2
|
|
|
3
|
-
import expo.modules.kotlin.events.EventEmitter
|
|
4
3
|
import expo.modules.updates.logging.UpdatesErrorCode
|
|
5
4
|
import expo.modules.updates.logging.UpdatesLogger
|
|
6
5
|
import expo.modules.updates.statemachine.UpdatesStateContext
|
|
6
|
+
import java.lang.ref.WeakReference
|
|
7
7
|
|
|
8
8
|
class UpdatesEventManager(private val logger: UpdatesLogger) : IUpdatesEventManager {
|
|
9
|
-
override var
|
|
9
|
+
override var observer: WeakReference<IUpdatesEventManagerObserver>? = null
|
|
10
10
|
|
|
11
11
|
override fun sendStateMachineContextEvent(context: UpdatesStateContext) {
|
|
12
|
-
|
|
12
|
+
logger.debug("Sending state machine context to observer")
|
|
13
13
|
|
|
14
|
-
val
|
|
15
|
-
|
|
16
|
-
logger.info(
|
|
17
|
-
"Could not emit $eventName event; no event emitter was found.",
|
|
18
|
-
UpdatesErrorCode.JSRuntimeError
|
|
19
|
-
)
|
|
14
|
+
val observer = observer?.get() ?: run {
|
|
15
|
+
logger.debug("Unable to send state machine context to observer, no observer", UpdatesErrorCode.JSRuntimeError)
|
|
20
16
|
return
|
|
21
17
|
}
|
|
22
18
|
|
|
23
19
|
try {
|
|
24
|
-
|
|
25
|
-
logger.
|
|
20
|
+
observer.onStateMachineContextEvent(context)
|
|
21
|
+
logger.debug("Sent state machine context to observer")
|
|
26
22
|
} catch (e: Exception) {
|
|
27
23
|
logger.error(
|
|
28
|
-
"Could not
|
|
24
|
+
"Could not send state machine context to observer",
|
|
29
25
|
e,
|
|
30
26
|
UpdatesErrorCode.JSRuntimeError
|
|
31
27
|
)
|
|
@@ -575,7 +575,7 @@ class FileDownloader(
|
|
|
575
575
|
|
|
576
576
|
val update = UpdateFactory.getUpdate(preManifest, responseHeaderData, extensions, configuration)
|
|
577
577
|
if (!SelectionPolicies.matchesFilters(update.updateEntity!!, responseHeaderData.manifestFilters)) {
|
|
578
|
-
callback.onFailure(Exception("Manifest filters
|
|
578
|
+
callback.onFailure(Exception("Manifest filters do not match manifest content for downloaded manifest"))
|
|
579
579
|
} else {
|
|
580
580
|
callback.onSuccess(UpdateResponsePart.ManifestUpdateResponsePart(update))
|
|
581
581
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
package expo.modules.updates.statemachine
|
|
2
2
|
|
|
3
3
|
import android.os.Bundle
|
|
4
|
-
import com.facebook.react.bridge.Arguments
|
|
5
|
-
import com.facebook.react.bridge.WritableMap
|
|
6
4
|
import org.json.JSONObject
|
|
7
5
|
import java.text.SimpleDateFormat
|
|
8
6
|
import java.util.Date
|
|
@@ -113,17 +111,7 @@ class UpdatesStateContext private constructor(
|
|
|
113
111
|
}
|
|
114
112
|
|
|
115
113
|
/**
|
|
116
|
-
* Creates a
|
|
117
|
-
*/
|
|
118
|
-
val writableMap: WritableMap
|
|
119
|
-
get() {
|
|
120
|
-
val result = Arguments.createMap()
|
|
121
|
-
result.putMap("context", Arguments.fromBundle(bundle))
|
|
122
|
-
return result
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Creates a Bundle to be returned to JS on a call to nativeStateMachineContext()
|
|
114
|
+
* Creates a Bundle to be synchronized with JS state
|
|
127
115
|
*/
|
|
128
116
|
val bundle: Bundle
|
|
129
117
|
get() {
|
|
@@ -629,23 +629,29 @@ describe('JS API tests', () => {
|
|
|
629
629
|
});
|
|
630
630
|
await waitForAppToBecomeVisible();
|
|
631
631
|
|
|
632
|
-
// Check state
|
|
632
|
+
// Check state on launch
|
|
633
633
|
const isUpdatePending = await testElementValueAsync('state.isUpdatePending');
|
|
634
634
|
const isUpdateAvailable = await testElementValueAsync('state.isUpdateAvailable');
|
|
635
635
|
const latestManifestId = await testElementValueAsync('state.latestManifest.id');
|
|
636
636
|
const downloadedManifestId = await testElementValueAsync('state.downloadedManifest.id');
|
|
637
637
|
const isRollback = await testElementValueAsync('state.isRollback');
|
|
638
|
-
|
|
639
638
|
console.warn(`isUpdatePending = ${isUpdatePending}`);
|
|
640
639
|
console.warn(`isUpdateAvailable = ${isUpdateAvailable}`);
|
|
641
640
|
console.warn(`isRollback = ${isRollback}`);
|
|
642
641
|
console.warn(`latestManifestId = ${latestManifestId}`);
|
|
643
642
|
console.warn(`downloadedManifestId = ${downloadedManifestId}`);
|
|
643
|
+
jestExpect(isUpdateAvailable).toEqual('false');
|
|
644
|
+
jestExpect(isUpdatePending).toEqual('false');
|
|
645
|
+
jestExpect(isRollback).toEqual('false');
|
|
646
|
+
jestExpect(latestManifestId).toEqual('null');
|
|
647
|
+
jestExpect(downloadedManifestId).toEqual('null');
|
|
644
648
|
|
|
645
649
|
const updatesExpoClientEmbeddedString = await testElementValueAsync('updates.expoClient');
|
|
646
650
|
const constantsExpoConfigEmbeddedString = await testElementValueAsync('constants.expoConfig');
|
|
647
651
|
console.warn(`updatesExpoClientEmbedded = ${updatesExpoClientEmbeddedString}`);
|
|
648
652
|
console.warn(`constantsExpoConfigEmbedded = ${constantsExpoConfigEmbeddedString}`);
|
|
653
|
+
const updatesExpoConfigEmbedded = JSON.parse(updatesExpoClientEmbeddedString);
|
|
654
|
+
jestExpect(updatesExpoConfigEmbedded).not.toBeNull();
|
|
649
655
|
|
|
650
656
|
// Now serve a manifest
|
|
651
657
|
Server.start(Update.serverPort, protocolVersion);
|
|
@@ -660,12 +666,16 @@ describe('JS API tests', () => {
|
|
|
660
666
|
const latestManifestId2 = await testElementValueAsync('state.latestManifest.id');
|
|
661
667
|
const downloadedManifestId2 = await testElementValueAsync('state.downloadedManifest.id');
|
|
662
668
|
const isRollback2 = await testElementValueAsync('state.isRollback');
|
|
663
|
-
|
|
664
669
|
console.warn(`isUpdatePending2 = ${isUpdatePending2}`);
|
|
665
670
|
console.warn(`isUpdateAvailable2 = ${isUpdateAvailable2}`);
|
|
666
671
|
console.warn(`isRollback2 = ${isRollback2}`);
|
|
667
672
|
console.warn(`latestManifestId2 = ${latestManifestId2}`);
|
|
668
673
|
console.warn(`downloadedManifestId2 = ${downloadedManifestId2}`);
|
|
674
|
+
jestExpect(isUpdateAvailable2).toEqual('true');
|
|
675
|
+
jestExpect(isUpdatePending2).toEqual('false');
|
|
676
|
+
jestExpect(isRollback2).toEqual('false');
|
|
677
|
+
jestExpect(latestManifestId2).toEqual(manifest.id);
|
|
678
|
+
jestExpect(downloadedManifestId2).toEqual('null');
|
|
669
679
|
|
|
670
680
|
// Download update and expect isUpdatePending to be true
|
|
671
681
|
await pressTestButtonAsync('downloadUpdate');
|
|
@@ -676,12 +686,16 @@ describe('JS API tests', () => {
|
|
|
676
686
|
const latestManifestId3 = await testElementValueAsync('state.latestManifest.id');
|
|
677
687
|
const downloadedManifestId3 = await testElementValueAsync('state.downloadedManifest.id');
|
|
678
688
|
const isRollback3 = await testElementValueAsync('state.isRollback');
|
|
679
|
-
|
|
680
689
|
console.warn(`isUpdatePending3 = ${isUpdatePending3}`);
|
|
681
690
|
console.warn(`isUpdateAvailable3 = ${isUpdateAvailable3}`);
|
|
682
691
|
console.warn(`isRollback3 = ${isRollback3}`);
|
|
683
692
|
console.warn(`latestManifestId3 = ${latestManifestId3}`);
|
|
684
693
|
console.warn(`downloadedManifestId3 = ${downloadedManifestId3}`);
|
|
694
|
+
jestExpect(isUpdateAvailable3).toEqual('true');
|
|
695
|
+
jestExpect(isUpdatePending3).toEqual('true');
|
|
696
|
+
jestExpect(isRollback3).toEqual('false');
|
|
697
|
+
jestExpect(latestManifestId3).toEqual(manifest.id);
|
|
698
|
+
jestExpect(downloadedManifestId3).toEqual(manifest.id);
|
|
685
699
|
|
|
686
700
|
// Terminate and relaunch app, we should be running the update, and back to the default state
|
|
687
701
|
await device.terminateApp();
|
|
@@ -694,13 +708,18 @@ describe('JS API tests', () => {
|
|
|
694
708
|
const downloadedManifestId4 = await testElementValueAsync('state.downloadedManifest.id');
|
|
695
709
|
const isRollback4 = await testElementValueAsync('state.isRollback');
|
|
696
710
|
const rollbackCommitTime4 = await testElementValueAsync('state.rollbackCommitTime');
|
|
697
|
-
|
|
698
711
|
console.warn(`isUpdatePending4 = ${isUpdatePending4}`);
|
|
699
712
|
console.warn(`isUpdateAvailable4 = ${isUpdateAvailable4}`);
|
|
700
713
|
console.warn(`isRollback4 = ${isRollback4}`);
|
|
701
714
|
console.warn(`latestManifestId4 = ${latestManifestId4}`);
|
|
702
715
|
console.warn(`downloadedManifestId4 = ${downloadedManifestId4}`);
|
|
703
716
|
console.warn(`rollbackCommitTime4 = ${rollbackCommitTime4}`);
|
|
717
|
+
jestExpect(isUpdateAvailable4).toEqual('false');
|
|
718
|
+
jestExpect(isUpdatePending4).toEqual('false');
|
|
719
|
+
jestExpect(isRollback4).toEqual('false');
|
|
720
|
+
jestExpect(latestManifestId4).toEqual('null');
|
|
721
|
+
jestExpect(downloadedManifestId4).toEqual('null');
|
|
722
|
+
jestExpect(rollbackCommitTime4).toEqual('null');
|
|
704
723
|
|
|
705
724
|
const updatesExpoClientUpdateString = await testElementValueAsync('updates.expoClient');
|
|
706
725
|
const constantsExpoConfigUpdateString = await testElementValueAsync('constants.expoConfig');
|
|
@@ -721,13 +740,18 @@ describe('JS API tests', () => {
|
|
|
721
740
|
const downloadedManifestId5 = await testElementValueAsync('state.downloadedManifest.id');
|
|
722
741
|
const isRollback5 = await testElementValueAsync('state.isRollback');
|
|
723
742
|
const rollbackCommitTime5 = await testElementValueAsync('state.rollbackCommitTime');
|
|
724
|
-
|
|
725
743
|
console.warn(`isUpdatePending5 = ${isUpdatePending5}`);
|
|
726
744
|
console.warn(`isUpdateAvailable5 = ${isUpdateAvailable5}`);
|
|
727
745
|
console.warn(`isRollback5 = ${isRollback5}`);
|
|
728
746
|
console.warn(`latestManifestId5 = ${latestManifestId5}`);
|
|
729
747
|
console.warn(`downloadedManifestId5 = ${downloadedManifestId5}`);
|
|
730
748
|
console.warn(`rollbackCommitTime5 = ${rollbackCommitTime5}`);
|
|
749
|
+
jestExpect(isUpdateAvailable5).toEqual('true');
|
|
750
|
+
jestExpect(isUpdatePending5).toEqual('false');
|
|
751
|
+
jestExpect(isRollback5).toEqual('true');
|
|
752
|
+
jestExpect(latestManifestId5).toEqual('null');
|
|
753
|
+
jestExpect(downloadedManifestId5).toEqual('null');
|
|
754
|
+
jestExpect(rollbackCommitTime5).not.toEqual('null');
|
|
731
755
|
|
|
732
756
|
// Terminate and relaunch app, we should be running the original bundle again, and back to the default state
|
|
733
757
|
await device.terminateApp();
|
|
@@ -753,44 +777,6 @@ describe('JS API tests', () => {
|
|
|
753
777
|
console.warn(`updatesExpoConfigRollback = ${updatesExpoConfigRollbackString}`);
|
|
754
778
|
console.warn(`constantsExpoConfigRollback = ${constantsExpoConfigRollbackString}`);
|
|
755
779
|
|
|
756
|
-
// Unpack expo config values and check them
|
|
757
|
-
const updatesExpoConfigEmbedded = JSON.parse(updatesExpoClientEmbeddedString);
|
|
758
|
-
jestExpect(updatesExpoConfigEmbedded).not.toBeNull();
|
|
759
|
-
|
|
760
|
-
// Verify correct behavior
|
|
761
|
-
// On launch
|
|
762
|
-
jestExpect(isUpdateAvailable).toEqual('false');
|
|
763
|
-
jestExpect(isUpdatePending).toEqual('false');
|
|
764
|
-
jestExpect(isRollback).toEqual('false');
|
|
765
|
-
jestExpect(latestManifestId).toEqual('null');
|
|
766
|
-
jestExpect(downloadedManifestId).toEqual('null');
|
|
767
|
-
// After check for update and getting a manifest
|
|
768
|
-
jestExpect(isUpdateAvailable2).toEqual('true');
|
|
769
|
-
jestExpect(isUpdatePending2).toEqual('false');
|
|
770
|
-
jestExpect(isRollback2).toEqual('false');
|
|
771
|
-
jestExpect(latestManifestId2).toEqual(manifest.id);
|
|
772
|
-
jestExpect(downloadedManifestId2).toEqual('null');
|
|
773
|
-
// After downloading the update
|
|
774
|
-
jestExpect(isUpdateAvailable3).toEqual('true');
|
|
775
|
-
jestExpect(isUpdatePending3).toEqual('true');
|
|
776
|
-
jestExpect(isRollback3).toEqual('false');
|
|
777
|
-
jestExpect(latestManifestId3).toEqual(manifest.id);
|
|
778
|
-
jestExpect(downloadedManifestId3).toEqual(manifest.id);
|
|
779
|
-
// After restarting
|
|
780
|
-
jestExpect(isUpdateAvailable4).toEqual('false');
|
|
781
|
-
jestExpect(isUpdatePending4).toEqual('false');
|
|
782
|
-
jestExpect(isRollback4).toEqual('false');
|
|
783
|
-
jestExpect(latestManifestId4).toEqual('null');
|
|
784
|
-
jestExpect(downloadedManifestId4).toEqual('null');
|
|
785
|
-
jestExpect(rollbackCommitTime4).toEqual('null');
|
|
786
|
-
// After check for update and getting a rollback
|
|
787
|
-
jestExpect(isUpdateAvailable5).toEqual('true');
|
|
788
|
-
jestExpect(isUpdatePending5).toEqual('false');
|
|
789
|
-
jestExpect(isRollback5).toEqual('true');
|
|
790
|
-
jestExpect(latestManifestId5).toEqual('null');
|
|
791
|
-
jestExpect(downloadedManifestId5).toEqual('null');
|
|
792
|
-
jestExpect(rollbackCommitTime5).not.toEqual('null');
|
|
793
|
-
|
|
794
780
|
// Check for update, and expect isRollback to be true
|
|
795
781
|
await pressTestButtonAsync('triggerParallelFetchAndDownload');
|
|
796
782
|
await waitForAsynchronousTaskCompletion(4000);
|
package/e2e/setup/project.ts
CHANGED
|
@@ -54,6 +54,7 @@ function getExpoDependencyChunks({
|
|
|
54
54
|
'expo-blur',
|
|
55
55
|
'expo-image',
|
|
56
56
|
'expo-linear-gradient',
|
|
57
|
+
'expo-linking',
|
|
57
58
|
'expo-localization',
|
|
58
59
|
'expo-crypto',
|
|
59
60
|
'expo-network',
|
|
@@ -474,6 +475,7 @@ function transformAppJsonForE2E(
|
|
|
474
475
|
owner: 'expo-ci',
|
|
475
476
|
runtimeVersion,
|
|
476
477
|
plugins,
|
|
478
|
+
newArchEnabled: false,
|
|
477
479
|
android: { ...appJson.expo.android, package: 'dev.expo.updatese2e' },
|
|
478
480
|
ios: { ...appJson.expo.ios, bundleIdentifier: 'dev.expo.updatese2e' },
|
|
479
481
|
updates: {
|
|
@@ -555,6 +557,7 @@ export function transformAppJsonForUpdatesDisabledE2E(
|
|
|
555
557
|
owner: 'expo-ci',
|
|
556
558
|
runtimeVersion,
|
|
557
559
|
plugins,
|
|
560
|
+
newArchEnabled: false,
|
|
558
561
|
android: { ...appJson.expo.android, package: 'dev.expo.updatese2e' },
|
|
559
562
|
ios: { ...appJson.expo.ios, bundleIdentifier: 'dev.expo.updatese2e' },
|
|
560
563
|
extra: {
|
|
@@ -350,13 +350,13 @@ public class AppController: NSObject {
|
|
|
350
350
|
}
|
|
351
351
|
}
|
|
352
352
|
|
|
353
|
-
internal static func
|
|
354
|
-
_sharedInstance?.eventManager.
|
|
353
|
+
internal static func setUpdatesEventManagerObserver(_ observer: UpdatesEventManagerObserver) {
|
|
354
|
+
_sharedInstance?.eventManager.observer = observer
|
|
355
355
|
_sharedInstance?.onEventListenerStartObserving()
|
|
356
356
|
}
|
|
357
357
|
|
|
358
|
-
internal static func
|
|
359
|
-
_sharedInstance?.eventManager.
|
|
358
|
+
internal static func removeUpdatesEventManagerObserver() {
|
|
359
|
+
_sharedInstance?.eventManager.observer = nil
|
|
360
360
|
}
|
|
361
361
|
}
|
|
362
362
|
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
import ExpoModulesCore
|
|
4
4
|
|
|
5
5
|
internal class NoOpUpdatesEventManager: UpdatesEventManager {
|
|
6
|
-
internal weak var
|
|
6
|
+
internal weak var observer: (any UpdatesEventManagerObserver)?
|
|
7
7
|
func sendStateMachineContextEvent(context: UpdatesStateContext) {}
|
|
8
8
|
}
|
|
@@ -9,21 +9,15 @@ internal class QueueUpdatesEventManager: UpdatesEventManager {
|
|
|
9
9
|
self.logger = logger
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
internal weak var
|
|
12
|
+
internal weak var observer: (any UpdatesEventManagerObserver)?
|
|
13
13
|
|
|
14
14
|
internal func sendStateMachineContextEvent(context: UpdatesStateContext) {
|
|
15
|
-
logger.
|
|
16
|
-
|
|
17
|
-
"context":
|
|
18
|
-
])
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
private func sendEventToAppContext(_ eventName: String, body: [String: Any?]) {
|
|
22
|
-
guard let eventEmitter = eventEmitter else {
|
|
23
|
-
logger.info(message: "EXUpdates: Could not emit event: name = \(eventName)", code: .jsRuntimeError)
|
|
15
|
+
logger.debug(message: "Sending state machine context to observer")
|
|
16
|
+
guard let observer = observer else {
|
|
17
|
+
logger.debug(message: "Unable to send state machine context to observer, no observer", code: .jsRuntimeError)
|
|
24
18
|
return
|
|
25
19
|
}
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
observer.onStateMachineContextEvent(context: context)
|
|
21
|
+
logger.debug(message: "Sent state machine context to observer")
|
|
28
22
|
}
|
|
29
23
|
}
|
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import ExpoModulesCore
|
|
4
4
|
|
|
5
|
+
public protocol UpdatesEventManagerObserver: AnyObject {
|
|
6
|
+
func onStateMachineContextEvent(context: UpdatesStateContext)
|
|
7
|
+
}
|
|
8
|
+
|
|
5
9
|
public protocol UpdatesEventManager: AnyObject {
|
|
6
|
-
var
|
|
10
|
+
var observer: UpdatesEventManagerObserver? { get set }
|
|
7
11
|
func sendStateMachineContextEvent(context: UpdatesStateContext)
|
|
8
12
|
}
|
|
@@ -11,7 +11,7 @@ import ExpoModulesCore
|
|
|
11
11
|
* Expo Go and legacy standalone apps) via EXUpdatesService, an internal module which is overridden
|
|
12
12
|
* by EXUpdatesBinding, a scoped module, in Expo Go.
|
|
13
13
|
*/
|
|
14
|
-
public final class UpdatesModule: Module {
|
|
14
|
+
public final class UpdatesModule: Module, UpdatesEventManagerObserver {
|
|
15
15
|
public func definition() -> ModuleDefinition {
|
|
16
16
|
Name("ExpoUpdates")
|
|
17
17
|
|
|
@@ -23,12 +23,16 @@ public final class UpdatesModule: Module {
|
|
|
23
23
|
AppController.sharedInstance.getConstantsForModule().toModuleConstantsMap()
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
OnStartObserving {
|
|
27
|
-
AppController.
|
|
26
|
+
OnStartObserving(EXUpdatesStateChangeEventName) {
|
|
27
|
+
AppController.setUpdatesEventManagerObserver(self)
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
OnStopObserving {
|
|
31
|
-
AppController.
|
|
30
|
+
OnStopObserving(EXUpdatesStateChangeEventName) {
|
|
31
|
+
AppController.removeUpdatesEventManagerObserver()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
OnDestroy {
|
|
35
|
+
AppController.removeUpdatesEventManagerObserver()
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
AsyncFunction("reload") { (promise: Promise) in
|
|
@@ -137,4 +141,10 @@ public final class UpdatesModule: Module {
|
|
|
137
141
|
}
|
|
138
142
|
}
|
|
139
143
|
}
|
|
144
|
+
|
|
145
|
+
public func onStateMachineContextEvent(context: UpdatesStateContext) {
|
|
146
|
+
sendEvent(EXUpdatesStateChangeEventName, [
|
|
147
|
+
"context": context.json
|
|
148
|
+
])
|
|
149
|
+
}
|
|
140
150
|
}
|
|
@@ -359,7 +359,6 @@ internal class UpdatesStateMachine {
|
|
|
359
359
|
// Only change context if transition succeeds
|
|
360
360
|
context = reducedContext(context, event)
|
|
361
361
|
logger.info(message: "Updates state change: state = \(state), event = \(event.type), context = \(context)")
|
|
362
|
-
// Send context to JS
|
|
363
362
|
sendContextToJS()
|
|
364
363
|
}
|
|
365
364
|
}
|
|
@@ -9,11 +9,10 @@ import ExpoModulesTestCore
|
|
|
9
9
|
import EXManifests
|
|
10
10
|
|
|
11
11
|
class TestStateChangeEventManager: UpdatesEventManager {
|
|
12
|
-
var appContext: ExpoModulesCore.AppContext? = nil
|
|
13
|
-
|
|
14
12
|
var lastContext: UpdatesStateContext? = nil
|
|
13
|
+
weak var observer: (any EXUpdates.UpdatesEventManagerObserver)?
|
|
15
14
|
|
|
16
|
-
func
|
|
15
|
+
func sendStateMachineContextEvent(context: EXUpdates.UpdatesStateContext) {
|
|
17
16
|
lastContext = context
|
|
18
17
|
}
|
|
19
18
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-updates",
|
|
3
|
-
"version": "0.26.
|
|
3
|
+
"version": "0.26.2",
|
|
4
4
|
"description": "Fetches and manages remotely-hosted assets and updates to your app's JS bundle.",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"@expo/code-signing-certificates": "0.0.5",
|
|
41
41
|
"@expo/config": "~10.0.0",
|
|
42
42
|
"@expo/config-plugins": "~9.0.0",
|
|
43
|
-
"@expo/fingerprint": "^0.
|
|
43
|
+
"@expo/fingerprint": "^0.11.0",
|
|
44
44
|
"@expo/spawn-async": "^1.7.2",
|
|
45
45
|
"arg": "4.1.0",
|
|
46
46
|
"chalk": "^4.1.2",
|
|
@@ -68,5 +68,5 @@
|
|
|
68
68
|
"expo": "*",
|
|
69
69
|
"react": "*"
|
|
70
70
|
},
|
|
71
|
-
"gitHead": "
|
|
71
|
+
"gitHead": "0a07b965c4bef67e7718355a0dc770d524ad3cee"
|
|
72
72
|
}
|