expo-updates 0.19.1 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/android/build.gradle +11 -8
- package/android/src/main/java/expo/modules/updates/UpdatesController.kt +2 -2
- package/android/src/main/java/expo/modules/updates/UpdatesDevLauncherController.kt +1 -1
- package/android/src/main/java/expo/modules/updates/UpdatesModule.kt +61 -14
- package/android/src/main/java/expo/modules/updates/db/UpdatesDatabase.kt +22 -1
- package/android/src/main/java/expo/modules/updates/db/entity/UpdateEntity.kt +2 -4
- package/android/src/main/java/expo/modules/updates/loader/LoaderTask.kt +37 -6
- package/android/src/main/java/expo/modules/updates/manifest/BareUpdateManifest.kt +3 -3
- package/android/src/main/java/expo/modules/updates/manifest/LegacyUpdateManifest.kt +1 -2
- package/android/src/main/java/expo/modules/updates/manifest/NewUpdateManifest.kt +1 -3
- package/android/src/main/java/expo/modules/updates/selectionpolicy/SelectionPolicies.kt +2 -3
- package/android/src/main/java/expo/modules/updates/statemachine/UpdatesStateContext.kt +12 -3
- package/android/src/main/java/expo/modules/updates/statemachine/UpdatesStateContextRollback.kt +14 -0
- package/android/src/main/java/expo/modules/updates/statemachine/UpdatesStateEvent.kt +3 -2
- package/android/src/main/java/expo/modules/updates/statemachine/UpdatesStateMachine.kt +5 -4
- package/build/Updates.d.ts +10 -8
- package/build/Updates.d.ts.map +1 -1
- package/build/Updates.js +23 -14
- package/build/Updates.js.map +1 -1
- package/build/Updates.types.d.ts +61 -14
- package/build/Updates.types.d.ts.map +1 -1
- package/build/Updates.types.js +26 -0
- package/build/Updates.types.js.map +1 -1
- package/build/UpdatesEmitter.d.ts.map +1 -1
- package/build/UpdatesEmitter.js +9 -19
- package/build/UpdatesEmitter.js.map +1 -1
- package/build/UseUpdates.types.d.ts +34 -3
- package/build/UseUpdates.types.d.ts.map +1 -1
- package/build/UseUpdates.types.js +4 -0
- package/build/UseUpdates.types.js.map +1 -1
- package/build/UseUpdatesUtils.d.ts +2 -1
- package/build/UseUpdatesUtils.d.ts.map +1 -1
- package/build/UseUpdatesUtils.js +15 -7
- package/build/UseUpdatesUtils.js.map +1 -1
- package/build/statemachine/UpdatesStateMachine.d.ts +1 -1
- package/build/statemachine/UpdatesStateMachine.js.map +1 -1
- package/e2e/fixtures/App-apitest.tsx +12 -7
- package/e2e/fixtures/App.tsx +5 -5
- package/e2e/fixtures/Updates.e2e.ts +8 -1
- package/e2e/fixtures/project_files/eas-hooks/eas-build-on-success.sh +7 -1
- package/e2e/fixtures/project_files/eas-hooks/eas-build-pre-install.sh +0 -3
- package/e2e/setup/create-eas-project-tv.js +30 -0
- package/e2e/setup/create-eas-project.js +1 -1
- package/e2e/setup/create-updates-test.js +0 -1
- package/e2e/setup/project.js +40 -12
- package/expo-updates-gradle-plugin/src/main/kotlin/expo/modules/updates/ExpoUpdatesPlugin.kt +7 -2
- package/ios/EXUpdates/ASN1Decoder/ASN1Decoder.swift +272 -0
- package/ios/EXUpdates/ASN1Decoder/ASN1DistinguishedNames.swift +114 -0
- package/ios/EXUpdates/ASN1Decoder/ASN1Encoder.swift +60 -0
- package/ios/EXUpdates/ASN1Decoder/ASN1Identifier.swift +102 -0
- package/ios/EXUpdates/ASN1Decoder/ASN1Object.swift +107 -0
- package/ios/EXUpdates/ASN1Decoder/OID.swift +97 -0
- package/ios/EXUpdates/ASN1Decoder/PKCS7.swift +98 -0
- package/ios/EXUpdates/ASN1Decoder/PKCS7_AppleReceipt.swift +210 -0
- package/ios/EXUpdates/ASN1Decoder/PKCS7_Signature.swift +108 -0
- package/ios/EXUpdates/ASN1Decoder/README.md +161 -0
- package/ios/EXUpdates/ASN1Decoder/X509Certificate.swift +361 -0
- package/ios/EXUpdates/ASN1Decoder/X509Extension.swift +71 -0
- package/ios/EXUpdates/ASN1Decoder/X509ExtensionAltName.swift +86 -0
- package/ios/EXUpdates/ASN1Decoder/X509ExtensionClasses.swift +183 -0
- package/ios/EXUpdates/ASN1Decoder/X509PublicKey.swift +77 -0
- package/ios/EXUpdates/AppController.swift +3 -3
- package/ios/EXUpdates/AppLoader/AppLoader.swift +20 -20
- package/ios/EXUpdates/AppLoader/AppLoaderTask.swift +39 -9
- package/ios/EXUpdates/AppLoader/Crypto.swift +0 -1
- package/ios/EXUpdates/AppLoader/EmbeddedAppLoader.swift +1 -1
- package/ios/EXUpdates/AppLoader/FileDownloader.swift +9 -9
- package/ios/EXUpdates/AppLoader/RemoteAppLoader.swift +4 -4
- package/ios/EXUpdates/AppLoader/ResponseHeaderData.swift +3 -3
- package/ios/EXUpdates/AppLoader/UpdateResponse.swift +15 -10
- package/ios/EXUpdates/CodeSigning/CertificateChain.swift +0 -1
- package/ios/EXUpdates/CodeSigning/CodeSigningConfiguration.swift +0 -1
- package/ios/EXUpdates/Database/Migrations/UpdatesDatabaseMigration9To10.swift +51 -0
- package/ios/EXUpdates/Database/Migrations/UpdatesDatabaseMigrationRegistry.swift +2 -1
- package/ios/EXUpdates/Database/UpdatesDatabase.swift +3 -7
- package/ios/EXUpdates/Database/UpdatesDatabaseInitialization.swift +9 -2
- package/ios/EXUpdates/ErrorRecovery.swift +2 -2
- package/ios/EXUpdates/Logging/UpdatesLogReader.swift +0 -1
- package/ios/EXUpdates/Update/BareUpdate.swift +2 -2
- package/ios/EXUpdates/Update/LegacyUpdate.swift +2 -2
- package/ios/EXUpdates/Update/NewUpdate.swift +2 -2
- package/ios/EXUpdates/Update/Update.swift +1 -1
- package/ios/EXUpdates/UpdatesConfig.swift +1 -1
- package/ios/EXUpdates/UpdatesModule.swift +13 -2
- package/ios/EXUpdates/UpdatesStateMachine.swift +42 -13
- package/ios/EXUpdates/UpdatesUtils.swift +62 -10
- package/ios/EXUpdates.podspec +1 -2
- package/ios/Tests/DatabaseInitializationSpec.swift +120 -3
- package/ios/Tests/UpdatesStateMachineSpec.swift +3 -3
- package/package.json +8 -8
- package/plugin/build/withUpdates.d.ts +1 -3
- package/plugin/build/withUpdates.js +3 -6
- package/plugin/src/withUpdates.ts +3 -7
- package/scripts/createManifest.js +9 -3
- package/src/Updates.ts +24 -14
- package/src/Updates.types.ts +68 -22
- package/src/UpdatesEmitter.ts +9 -22
- package/src/UseUpdates.types.ts +34 -2
- package/src/UseUpdatesUtils.ts +18 -3
- package/src/statemachine/UpdatesStateMachine.ts +1 -1
- package/e2e/fixtures/project_files/xcode.env.local +0 -4
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,43 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 0.21.0 — 2023-09-15
|
|
14
|
+
|
|
15
|
+
### 🎉 New features
|
|
16
|
+
|
|
17
|
+
- Added support for Apple tvOS. ([#24329](https://github.com/expo/expo/pull/24329) by [@douglowder](https://github.com/douglowder))
|
|
18
|
+
|
|
19
|
+
### 🐛 Bug fixes
|
|
20
|
+
|
|
21
|
+
- Fix updates enabled defaulting on iOS. ([#24327](https://github.com/expo/expo/pull/24327) by [@wschurman](https://github.com/wschurman))
|
|
22
|
+
- [Android] Make scopekey only required when getting database entity. ([#24466](https://github.com/expo/expo/pull/24466) by [@wschurman](https://github.com/wschurman))
|
|
23
|
+
|
|
24
|
+
### 💡 Others
|
|
25
|
+
|
|
26
|
+
- Update E2E test. ([#24272](https://github.com/expo/expo/pull/24272) by [@EvanBacon](https://github.com/EvanBacon))
|
|
27
|
+
- [iOS] Disable packager and bundle JS when `EX_UPDATES_NATIVE_DEBUG` set. ([#24366](https://github.com/expo/expo/pull/24366) by [@douglowder](https://github.com/douglowder))
|
|
28
|
+
- Add Apple TV to Updates E2E (build only). ([#24411](https://github.com/expo/expo/pull/24411) by [@douglowder](https://github.com/douglowder))
|
|
29
|
+
|
|
30
|
+
## 0.20.0 — 2023-09-04
|
|
31
|
+
|
|
32
|
+
### 🛠 Breaking changes
|
|
33
|
+
|
|
34
|
+
- Change source of truth for constants types. ([#24049](https://github.com/expo/expo/pull/24049) by [@wschurman](https://github.com/wschurman))
|
|
35
|
+
- Remove classic manifest types and classic updates. ([#24053](https://github.com/expo/expo/pull/24053), [#24066](https://github.com/expo/expo/pull/24066) by [@wschurman](https://github.com/wschurman))
|
|
36
|
+
|
|
37
|
+
### 🎉 New features
|
|
38
|
+
|
|
39
|
+
- Added support for React Native 0.73. ([#24018](https://github.com/expo/expo/pull/24018) by [@kudo](https://github.com/kudo))
|
|
40
|
+
- Add rollback support to useUpdates(). ([#24071](https://github.com/expo/expo/pull/24071) by [@douglowder](https://github.com/douglowder))
|
|
41
|
+
|
|
42
|
+
### 🐛 Bug fixes
|
|
43
|
+
|
|
44
|
+
- [Android] completely fix `node` execution on Windows ([#24116](https://github.com/expo/expo/pull/24116) by [@weykon](https://github.com/weykon))
|
|
45
|
+
- [Android] Fixed the `node` execution on Windows. ([#23983](https://github.com/expo/expo/pull/23983) by [@kudo](https://github.com/kudo))
|
|
46
|
+
- Bare update manifest non-nullability parity. ([#23166](https://github.com/expo/expo/pull/23166) by [@wschurman](https://github.com/wschurman))
|
|
47
|
+
- Support importing assets from out of the project root when working in monorepos. ([#24090](https://github.com/expo/expo/pull/24090) by [@EvanBacon](https://github.com/EvanBacon))
|
|
48
|
+
- Prevent failed updates from passing checkForUpdateAsync(). ([#24112](https://github.com/expo/expo/pull/24112) by [@douglowder](https://github.com/douglowder))
|
|
49
|
+
|
|
13
50
|
## 0.19.1 — 2023-08-02
|
|
14
51
|
|
|
15
52
|
### 💡 Others
|
package/android/build.gradle
CHANGED
|
@@ -4,7 +4,7 @@ apply plugin: 'kotlin-kapt'
|
|
|
4
4
|
apply plugin: 'maven-publish'
|
|
5
5
|
|
|
6
6
|
group = 'host.exp.exponent'
|
|
7
|
-
version = '0.
|
|
7
|
+
version = '0.21.0'
|
|
8
8
|
|
|
9
9
|
// Utility method to derive boolean values from the environment or from Java properties,
|
|
10
10
|
// and return them as strings to be used in BuildConfig fields
|
|
@@ -81,13 +81,16 @@ afterEvaluate {
|
|
|
81
81
|
android {
|
|
82
82
|
compileSdkVersion safeExtGet("compileSdkVersion", 33)
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
|
|
85
|
+
if (agpVersion.tokenize('.')[0].toInteger() < 8) {
|
|
86
|
+
compileOptions {
|
|
87
|
+
sourceCompatibility JavaVersion.VERSION_11
|
|
88
|
+
targetCompatibility JavaVersion.VERSION_11
|
|
89
|
+
}
|
|
88
90
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
+
kotlinOptions {
|
|
92
|
+
jvmTarget = JavaVersion.VERSION_11.majorVersion
|
|
93
|
+
}
|
|
91
94
|
}
|
|
92
95
|
|
|
93
96
|
namespace "expo.modules.updates"
|
|
@@ -95,7 +98,7 @@ android {
|
|
|
95
98
|
minSdkVersion safeExtGet("minSdkVersion", 21)
|
|
96
99
|
targetSdkVersion safeExtGet("targetSdkVersion", 33)
|
|
97
100
|
versionCode 31
|
|
98
|
-
versionName '0.
|
|
101
|
+
versionName '0.21.0'
|
|
99
102
|
consumerProguardFiles("proguard-rules.pro")
|
|
100
103
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
101
104
|
|
|
@@ -289,7 +289,7 @@ class UpdatesController private constructor(
|
|
|
289
289
|
val event = when (result) {
|
|
290
290
|
is LoaderTask.RemoteCheckResult.NoUpdateAvailable -> UpdatesStateEvent.CheckCompleteUnavailable()
|
|
291
291
|
is LoaderTask.RemoteCheckResult.UpdateAvailable -> UpdatesStateEvent.CheckCompleteWithUpdate(result.manifest)
|
|
292
|
-
is LoaderTask.RemoteCheckResult.RollBackToEmbedded -> UpdatesStateEvent.CheckCompleteWithRollback()
|
|
292
|
+
is LoaderTask.RemoteCheckResult.RollBackToEmbedded -> UpdatesStateEvent.CheckCompleteWithRollback(result.commitTime)
|
|
293
293
|
}
|
|
294
294
|
stateMachine.processEvent(event)
|
|
295
295
|
}
|
|
@@ -375,7 +375,7 @@ class UpdatesController private constructor(
|
|
|
375
375
|
params.putString("manifestString", update.manifest.toString())
|
|
376
376
|
sendLegacyUpdateEventToJS(UPDATE_AVAILABLE_EVENT, params)
|
|
377
377
|
stateMachine.processEvent(
|
|
378
|
-
UpdatesStateEvent.DownloadCompleteWithUpdate(update.manifest
|
|
378
|
+
UpdatesStateEvent.DownloadCompleteWithUpdate(update.manifest)
|
|
379
379
|
)
|
|
380
380
|
}
|
|
381
381
|
RemoteUpdateStatus.NO_UPDATE_AVAILABLE -> {
|
|
@@ -154,7 +154,7 @@ class UpdatesDevLauncherController : UpdatesInterface {
|
|
|
154
154
|
controller.setLauncher(launcher)
|
|
155
155
|
callback.onSuccess(object : UpdatesInterface.Update {
|
|
156
156
|
override fun getManifest(): JSONObject {
|
|
157
|
-
return launcher.launchedUpdate!!.manifest
|
|
157
|
+
return launcher.launchedUpdate!!.manifest
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
override fun getLaunchAssetPath(): String {
|
|
@@ -27,7 +27,6 @@ import expo.modules.updates.manifest.UpdateManifest
|
|
|
27
27
|
|
|
28
28
|
// these unused imports must stay because of versioning
|
|
29
29
|
/* ktlint-disable no-unused-imports */
|
|
30
|
-
import expo.modules.updates.UpdatesConfiguration
|
|
31
30
|
|
|
32
31
|
/* ktlint-enable no-unused-imports */
|
|
33
32
|
|
|
@@ -80,8 +79,7 @@ class UpdatesModule(
|
|
|
80
79
|
if (launchedUpdate != null) {
|
|
81
80
|
constants["updateId"] = launchedUpdate.id.toString()
|
|
82
81
|
constants["commitTime"] = launchedUpdate.commitTime.time
|
|
83
|
-
constants["manifestString"] =
|
|
84
|
-
if (launchedUpdate.manifest != null) launchedUpdate.manifest.toString() else "{}"
|
|
82
|
+
constants["manifestString"] = launchedUpdate.manifest.toString()
|
|
85
83
|
}
|
|
86
84
|
val localAssetFiles = updatesServiceLocal.localAssetFiles
|
|
87
85
|
if (localAssetFiles != null) {
|
|
@@ -138,7 +136,7 @@ class UpdatesModule(
|
|
|
138
136
|
}
|
|
139
137
|
}
|
|
140
138
|
|
|
141
|
-
// Used internally by
|
|
139
|
+
// Used internally by useUpdates() to get its initial state
|
|
142
140
|
@ExpoMethod
|
|
143
141
|
fun getNativeStateMachineContextAsync(promise: Promise) {
|
|
144
142
|
try {
|
|
@@ -200,13 +198,23 @@ class UpdatesModule(
|
|
|
200
198
|
if (updateDirective != null) {
|
|
201
199
|
if (updateDirective is UpdateDirective.RollBackToEmbeddedUpdateDirective) {
|
|
202
200
|
if (!updatesServiceLocal.configuration.hasEmbeddedUpdate) {
|
|
203
|
-
promise.resolveWithCheckForUpdateAsyncResult(
|
|
201
|
+
promise.resolveWithCheckForUpdateAsyncResult(
|
|
202
|
+
CheckForUpdateAsyncResult.NoUpdateAvailable(
|
|
203
|
+
LoaderTask.RemoteCheckResultNotAvailableReason.ROLLBACK_NO_EMBEDDED
|
|
204
|
+
),
|
|
205
|
+
updatesServiceLocal
|
|
206
|
+
)
|
|
204
207
|
return
|
|
205
208
|
}
|
|
206
209
|
|
|
207
210
|
val embeddedUpdate = EmbeddedManifest.get(context, updatesServiceLocal.configuration)!!.updateEntity
|
|
208
211
|
if (embeddedUpdate == null) {
|
|
209
|
-
promise.resolveWithCheckForUpdateAsyncResult(
|
|
212
|
+
promise.resolveWithCheckForUpdateAsyncResult(
|
|
213
|
+
CheckForUpdateAsyncResult.NoUpdateAvailable(
|
|
214
|
+
LoaderTask.RemoteCheckResultNotAvailableReason.ROLLBACK_NO_EMBEDDED
|
|
215
|
+
),
|
|
216
|
+
updatesServiceLocal
|
|
217
|
+
)
|
|
210
218
|
return
|
|
211
219
|
}
|
|
212
220
|
|
|
@@ -217,17 +225,27 @@ class UpdatesModule(
|
|
|
217
225
|
updateResponse.responseHeaderData?.manifestFilters
|
|
218
226
|
)
|
|
219
227
|
) {
|
|
220
|
-
promise.resolveWithCheckForUpdateAsyncResult(
|
|
228
|
+
promise.resolveWithCheckForUpdateAsyncResult(
|
|
229
|
+
CheckForUpdateAsyncResult.NoUpdateAvailable(
|
|
230
|
+
LoaderTask.RemoteCheckResultNotAvailableReason.ROLLBACK_REJECTED_BY_SELECTION_POLICY
|
|
231
|
+
),
|
|
232
|
+
updatesServiceLocal
|
|
233
|
+
)
|
|
221
234
|
return
|
|
222
235
|
}
|
|
223
236
|
|
|
224
|
-
promise.resolveWithCheckForUpdateAsyncResult(CheckForUpdateAsyncResult.RollBackToEmbedded(), updatesServiceLocal)
|
|
237
|
+
promise.resolveWithCheckForUpdateAsyncResult(CheckForUpdateAsyncResult.RollBackToEmbedded(updateDirective.commitTime), updatesServiceLocal)
|
|
225
238
|
return
|
|
226
239
|
}
|
|
227
240
|
}
|
|
228
241
|
|
|
229
242
|
if (updateManifest == null) {
|
|
230
|
-
promise.resolveWithCheckForUpdateAsyncResult(
|
|
243
|
+
promise.resolveWithCheckForUpdateAsyncResult(
|
|
244
|
+
CheckForUpdateAsyncResult.NoUpdateAvailable(
|
|
245
|
+
LoaderTask.RemoteCheckResultNotAvailableReason.NO_UPDATE_AVAILABLE_ON_SERVER
|
|
246
|
+
),
|
|
247
|
+
updatesServiceLocal
|
|
248
|
+
)
|
|
231
249
|
return
|
|
232
250
|
}
|
|
233
251
|
|
|
@@ -238,15 +256,43 @@ class UpdatesModule(
|
|
|
238
256
|
return
|
|
239
257
|
}
|
|
240
258
|
|
|
259
|
+
var shouldLaunch = false
|
|
260
|
+
var failedPreviously = false
|
|
241
261
|
if (updatesServiceLocal.selectionPolicy.shouldLoadNewUpdate(
|
|
242
262
|
updateManifest.updateEntity,
|
|
243
263
|
launchedUpdate,
|
|
244
264
|
updateResponse.responseHeaderData?.manifestFilters
|
|
245
265
|
)
|
|
246
266
|
) {
|
|
267
|
+
// If "update" has failed to launch previously, then
|
|
268
|
+
// "launchedUpdate" will be an earlier update, and the test above
|
|
269
|
+
// will return true (incorrectly).
|
|
270
|
+
// We check to see if the new update is already in the DB, and if so,
|
|
271
|
+
// only allow the update if it has had no launch failures.
|
|
272
|
+
shouldLaunch = true
|
|
273
|
+
updateManifest.updateEntity?.let { updateEntity ->
|
|
274
|
+
val storedUpdateEntity = updatesServiceLocal.databaseHolder.database.updateDao().loadUpdateWithId(
|
|
275
|
+
updateEntity.id
|
|
276
|
+
)
|
|
277
|
+
updatesServiceLocal.databaseHolder.releaseDatabase()
|
|
278
|
+
storedUpdateEntity?.let { storedUpdateEntity ->
|
|
279
|
+
shouldLaunch = storedUpdateEntity.failedLaunchCount == 0
|
|
280
|
+
logger.info("Stored update found: ID = ${updateEntity.id}, failureCount = ${storedUpdateEntity.failedLaunchCount}")
|
|
281
|
+
failedPreviously = !shouldLaunch
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
if (shouldLaunch) {
|
|
247
286
|
promise.resolveWithCheckForUpdateAsyncResult(CheckForUpdateAsyncResult.UpdateAvailable(updateManifest), updatesServiceLocal)
|
|
248
287
|
} else {
|
|
249
|
-
|
|
288
|
+
val reason = when (failedPreviously) {
|
|
289
|
+
true -> LoaderTask.RemoteCheckResultNotAvailableReason.UPDATE_PREVIOUSLY_FAILED
|
|
290
|
+
else -> LoaderTask.RemoteCheckResultNotAvailableReason.UPDATE_REJECTED_BY_SELECTION_POLICY
|
|
291
|
+
}
|
|
292
|
+
promise.resolveWithCheckForUpdateAsyncResult(
|
|
293
|
+
CheckForUpdateAsyncResult.NoUpdateAvailable(reason),
|
|
294
|
+
updatesServiceLocal
|
|
295
|
+
)
|
|
250
296
|
}
|
|
251
297
|
}
|
|
252
298
|
}
|
|
@@ -267,9 +313,9 @@ class UpdatesModule(
|
|
|
267
313
|
ROLL_BACK_TO_EMBEDDED
|
|
268
314
|
}
|
|
269
315
|
|
|
270
|
-
class NoUpdateAvailable : CheckForUpdateAsyncResult(Status.NO_UPDATE_AVAILABLE)
|
|
316
|
+
class NoUpdateAvailable(val reason: LoaderTask.RemoteCheckResultNotAvailableReason) : CheckForUpdateAsyncResult(Status.NO_UPDATE_AVAILABLE)
|
|
271
317
|
class UpdateAvailable(val updateManifest: UpdateManifest) : CheckForUpdateAsyncResult(Status.UPDATE_AVAILABLE)
|
|
272
|
-
class RollBackToEmbedded : CheckForUpdateAsyncResult(Status.ROLL_BACK_TO_EMBEDDED)
|
|
318
|
+
class RollBackToEmbedded(val commitTime: Date) : CheckForUpdateAsyncResult(Status.ROLL_BACK_TO_EMBEDDED)
|
|
273
319
|
}
|
|
274
320
|
|
|
275
321
|
private fun Promise.resolveWithCheckForUpdateAsyncResult(checkForUpdateAsyncResult: CheckForUpdateAsyncResult, updatesServiceLocal: UpdatesInterface) {
|
|
@@ -279,6 +325,7 @@ class UpdatesModule(
|
|
|
279
325
|
is CheckForUpdateAsyncResult.NoUpdateAvailable -> {
|
|
280
326
|
putBoolean("isRollBackToEmbedded", false)
|
|
281
327
|
putBoolean("isAvailable", false)
|
|
328
|
+
putString("reason", checkForUpdateAsyncResult.reason.value)
|
|
282
329
|
}
|
|
283
330
|
|
|
284
331
|
is CheckForUpdateAsyncResult.RollBackToEmbedded -> {
|
|
@@ -297,7 +344,7 @@ class UpdatesModule(
|
|
|
297
344
|
updatesServiceLocal.stateMachine?.processEvent(
|
|
298
345
|
when (checkForUpdateAsyncResult) {
|
|
299
346
|
is CheckForUpdateAsyncResult.NoUpdateAvailable -> UpdatesStateEvent.CheckCompleteUnavailable()
|
|
300
|
-
is CheckForUpdateAsyncResult.RollBackToEmbedded -> UpdatesStateEvent.CheckCompleteWithRollback()
|
|
347
|
+
is CheckForUpdateAsyncResult.RollBackToEmbedded -> UpdatesStateEvent.CheckCompleteWithRollback(checkForUpdateAsyncResult.commitTime)
|
|
301
348
|
is CheckForUpdateAsyncResult.UpdateAvailable -> UpdatesStateEvent.CheckCompleteWithUpdate(
|
|
302
349
|
checkForUpdateAsyncResult.updateManifest.manifest.getRawJson()
|
|
303
350
|
)
|
|
@@ -418,7 +465,7 @@ class UpdatesModule(
|
|
|
418
465
|
}
|
|
419
466
|
)
|
|
420
467
|
updatesServiceLocal.stateMachine?.processEvent(
|
|
421
|
-
UpdatesStateEvent.DownloadCompleteWithUpdate(updateEntity.manifest
|
|
468
|
+
UpdatesStateEvent.DownloadCompleteWithUpdate(updateEntity.manifest)
|
|
422
469
|
)
|
|
423
470
|
}
|
|
424
471
|
}
|
|
@@ -44,7 +44,7 @@ import java.util.*
|
|
|
44
44
|
@Database(
|
|
45
45
|
entities = [UpdateEntity::class, UpdateAssetEntity::class, AssetEntity::class, JSONDataEntity::class],
|
|
46
46
|
exportSchema = false,
|
|
47
|
-
version =
|
|
47
|
+
version = 12
|
|
48
48
|
)
|
|
49
49
|
@TypeConverters(Converters::class)
|
|
50
50
|
abstract class UpdatesDatabase : RoomDatabase() {
|
|
@@ -69,6 +69,7 @@ abstract class UpdatesDatabase : RoomDatabase() {
|
|
|
69
69
|
.addMigrations(MIGRATION_8_9)
|
|
70
70
|
.addMigrations(MIGRATION_9_10)
|
|
71
71
|
.addMigrations(MIGRATION_10_11)
|
|
72
|
+
.addMigrations(MIGRATION_11_12)
|
|
72
73
|
.fallbackToDestructiveMigration()
|
|
73
74
|
.allowMainThreadQueries()
|
|
74
75
|
.build()
|
|
@@ -199,5 +200,25 @@ abstract class UpdatesDatabase : RoomDatabase() {
|
|
|
199
200
|
}
|
|
200
201
|
}
|
|
201
202
|
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Change the `updates.manifest` column to be non-null
|
|
206
|
+
*/
|
|
207
|
+
val MIGRATION_11_12: Migration = object : Migration(11, 12) {
|
|
208
|
+
override fun migrate(database: SupportSQLiteDatabase) {
|
|
209
|
+
database.runInTransactionWithForeignKeysOff {
|
|
210
|
+
execSQL("CREATE TABLE `new_updates` (`id` BLOB NOT NULL, `scope_key` TEXT NOT NULL, `commit_time` INTEGER NOT NULL, `runtime_version` TEXT NOT NULL, `launch_asset_id` INTEGER, `manifest` TEXT NOT NULL, `status` INTEGER NOT NULL, `keep` INTEGER NOT NULL, `last_accessed` INTEGER NOT NULL, `successful_launch_count` INTEGER NOT NULL DEFAULT 0, `failed_launch_count` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`id`), FOREIGN KEY(`launch_asset_id`) REFERENCES `assets`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
|
|
211
|
+
|
|
212
|
+
execSQL(
|
|
213
|
+
"INSERT INTO `new_updates` (`id`, `scope_key`, `commit_time`, `runtime_version`, `launch_asset_id`, `manifest`, `status`, `keep`, `last_accessed`, `successful_launch_count`, `failed_launch_count`)" +
|
|
214
|
+
" SELECT `id`, `scope_key`, `commit_time`, `runtime_version`, `launch_asset_id`, `manifest`, `status`, `keep`, `last_accessed`, `successful_launch_count`, `failed_launch_count` FROM `updates` WHERE `manifest` IS NOT NULL"
|
|
215
|
+
)
|
|
216
|
+
execSQL("DROP TABLE `updates`")
|
|
217
|
+
execSQL("ALTER TABLE `new_updates` RENAME TO `updates`")
|
|
218
|
+
execSQL("CREATE INDEX `index_updates_launch_asset_id` ON `updates` (`launch_asset_id`)")
|
|
219
|
+
execSQL("CREATE UNIQUE INDEX `index_updates_scope_key_commit_time` ON `updates` (`scope_key`, `commit_time`)")
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
202
223
|
}
|
|
203
224
|
}
|
|
@@ -36,14 +36,12 @@ class UpdateEntity(
|
|
|
36
36
|
@field:ColumnInfo(typeAffinity = ColumnInfo.BLOB) @field:PrimaryKey var id: UUID,
|
|
37
37
|
@field:ColumnInfo(name = "commit_time") var commitTime: Date,
|
|
38
38
|
@field:ColumnInfo(name = "runtime_version") var runtimeVersion: String,
|
|
39
|
-
@field:ColumnInfo(name = "scope_key") var scopeKey: String
|
|
39
|
+
@field:ColumnInfo(name = "scope_key") var scopeKey: String,
|
|
40
|
+
@field:ColumnInfo(name = "manifest") var manifest: JSONObject,
|
|
40
41
|
) {
|
|
41
42
|
@ColumnInfo(name = "launch_asset_id")
|
|
42
43
|
var launchAssetId: Long? = null
|
|
43
44
|
|
|
44
|
-
@ColumnInfo(name = "manifest")
|
|
45
|
-
var manifest: JSONObject? = null
|
|
46
|
-
|
|
47
45
|
var status = UpdateStatus.PENDING
|
|
48
46
|
|
|
49
47
|
var keep = false
|
|
@@ -21,6 +21,7 @@ import expo.modules.updates.manifest.UpdateManifest
|
|
|
21
21
|
import expo.modules.updates.selectionpolicy.SelectionPolicy
|
|
22
22
|
import org.json.JSONObject
|
|
23
23
|
import java.io.File
|
|
24
|
+
import java.util.Date
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* Controlling class that handles the complex logic that needs to happen each time the app is cold
|
|
@@ -53,6 +54,32 @@ class LoaderTask(
|
|
|
53
54
|
ERROR, NO_UPDATE_AVAILABLE, UPDATE_AVAILABLE
|
|
54
55
|
}
|
|
55
56
|
|
|
57
|
+
enum class RemoteCheckResultNotAvailableReason(val value: String) {
|
|
58
|
+
/**
|
|
59
|
+
* No update manifest or rollback directive received from the update server.
|
|
60
|
+
*/
|
|
61
|
+
NO_UPDATE_AVAILABLE_ON_SERVER("noUpdateAvailableOnServer"),
|
|
62
|
+
/**
|
|
63
|
+
* An update manifest was received from the update server, but the update is not launchable,
|
|
64
|
+
* or does not pass the configured selection policy.
|
|
65
|
+
*/
|
|
66
|
+
UPDATE_REJECTED_BY_SELECTION_POLICY("updateRejectedBySelectionPolicy"),
|
|
67
|
+
/**
|
|
68
|
+
* An update manifest was received from the update server, but the update has been previously
|
|
69
|
+
* launched on this device and never successfully launched.
|
|
70
|
+
*/
|
|
71
|
+
UPDATE_PREVIOUSLY_FAILED("updatePreviouslyFailed"),
|
|
72
|
+
/**
|
|
73
|
+
* A rollback directive was received from the update server, but the directive does not pass
|
|
74
|
+
* the configured selection policy.
|
|
75
|
+
*/
|
|
76
|
+
ROLLBACK_REJECTED_BY_SELECTION_POLICY("rollbackRejectedBySelectionPolicy"),
|
|
77
|
+
/**
|
|
78
|
+
* A rollback directive was received from the update server, but this app has no embedded update.
|
|
79
|
+
*/
|
|
80
|
+
ROLLBACK_NO_EMBEDDED("rollbackNoEmbeddedConfiguration"),
|
|
81
|
+
}
|
|
82
|
+
|
|
56
83
|
sealed class RemoteCheckResult(private val status: Status) {
|
|
57
84
|
private enum class Status {
|
|
58
85
|
NO_UPDATE_AVAILABLE,
|
|
@@ -60,9 +87,9 @@ class LoaderTask(
|
|
|
60
87
|
ROLL_BACK_TO_EMBEDDED
|
|
61
88
|
}
|
|
62
89
|
|
|
63
|
-
class NoUpdateAvailable : RemoteCheckResult(Status.NO_UPDATE_AVAILABLE)
|
|
90
|
+
class NoUpdateAvailable(val reason: RemoteCheckResultNotAvailableReason) : RemoteCheckResult(Status.NO_UPDATE_AVAILABLE)
|
|
64
91
|
class UpdateAvailable(val manifest: JSONObject) : RemoteCheckResult(Status.UPDATE_AVAILABLE)
|
|
65
|
-
class RollBackToEmbedded : RemoteCheckResult(Status.ROLL_BACK_TO_EMBEDDED)
|
|
92
|
+
class RollBackToEmbedded(val commitTime: Date) : RemoteCheckResult(Status.ROLL_BACK_TO_EMBEDDED)
|
|
66
93
|
}
|
|
67
94
|
|
|
68
95
|
interface LoaderTaskCallback {
|
|
@@ -335,12 +362,12 @@ class LoaderTask(
|
|
|
335
362
|
return when (updateDirective) {
|
|
336
363
|
is UpdateDirective.RollBackToEmbeddedUpdateDirective -> {
|
|
337
364
|
isUpToDate = true
|
|
338
|
-
callback.onRemoteCheckForUpdateFinished(RemoteCheckResult.RollBackToEmbedded())
|
|
365
|
+
callback.onRemoteCheckForUpdateFinished(RemoteCheckResult.RollBackToEmbedded(updateDirective.commitTime))
|
|
339
366
|
Loader.OnUpdateResponseLoadedResult(shouldDownloadManifestIfPresentInResponse = false)
|
|
340
367
|
}
|
|
341
368
|
is UpdateDirective.NoUpdateAvailableUpdateDirective -> {
|
|
342
369
|
isUpToDate = true
|
|
343
|
-
callback.onRemoteCheckForUpdateFinished(RemoteCheckResult.NoUpdateAvailable())
|
|
370
|
+
callback.onRemoteCheckForUpdateFinished(RemoteCheckResult.NoUpdateAvailable(RemoteCheckResultNotAvailableReason.NO_UPDATE_AVAILABLE_ON_SERVER))
|
|
344
371
|
Loader.OnUpdateResponseLoadedResult(shouldDownloadManifestIfPresentInResponse = false)
|
|
345
372
|
}
|
|
346
373
|
}
|
|
@@ -349,7 +376,7 @@ class LoaderTask(
|
|
|
349
376
|
val updateManifest = updateResponse.manifestUpdateResponsePart?.updateManifest
|
|
350
377
|
if (updateManifest == null) {
|
|
351
378
|
isUpToDate = true
|
|
352
|
-
callback.onRemoteCheckForUpdateFinished(RemoteCheckResult.NoUpdateAvailable())
|
|
379
|
+
callback.onRemoteCheckForUpdateFinished(RemoteCheckResult.NoUpdateAvailable(RemoteCheckResultNotAvailableReason.NO_UPDATE_AVAILABLE_ON_SERVER))
|
|
353
380
|
return Loader.OnUpdateResponseLoadedResult(shouldDownloadManifestIfPresentInResponse = false)
|
|
354
381
|
}
|
|
355
382
|
|
|
@@ -366,7 +393,11 @@ class LoaderTask(
|
|
|
366
393
|
Loader.OnUpdateResponseLoadedResult(shouldDownloadManifestIfPresentInResponse = true)
|
|
367
394
|
} else {
|
|
368
395
|
isUpToDate = true
|
|
369
|
-
callback.onRemoteCheckForUpdateFinished(
|
|
396
|
+
callback.onRemoteCheckForUpdateFinished(
|
|
397
|
+
RemoteCheckResult.NoUpdateAvailable(
|
|
398
|
+
RemoteCheckResultNotAvailableReason.UPDATE_REJECTED_BY_SELECTION_POLICY
|
|
399
|
+
)
|
|
400
|
+
)
|
|
370
401
|
Loader.OnUpdateResponseLoadedResult(shouldDownloadManifestIfPresentInResponse = false)
|
|
371
402
|
}
|
|
372
403
|
}
|
|
@@ -22,13 +22,13 @@ import java.util.*
|
|
|
22
22
|
class BareUpdateManifest private constructor(
|
|
23
23
|
override val manifest: BareManifest,
|
|
24
24
|
private val mId: UUID,
|
|
25
|
-
private val mScopeKey: String
|
|
25
|
+
private val mScopeKey: String?,
|
|
26
26
|
private val mCommitTime: Date,
|
|
27
27
|
private val mRuntimeVersion: String,
|
|
28
28
|
private val mAssets: JSONArray?
|
|
29
29
|
) : UpdateManifest {
|
|
30
30
|
override val updateEntity: UpdateEntity by lazy {
|
|
31
|
-
UpdateEntity(mId, mCommitTime, mRuntimeVersion, mScopeKey).apply {
|
|
31
|
+
UpdateEntity(mId, mCommitTime, mRuntimeVersion, mScopeKey!!, this@BareUpdateManifest.manifest.getRawJson()).apply {
|
|
32
32
|
status = UpdateStatus.EMBEDDED
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -94,7 +94,7 @@ class BareUpdateManifest private constructor(
|
|
|
94
94
|
return BareUpdateManifest(
|
|
95
95
|
manifest,
|
|
96
96
|
id,
|
|
97
|
-
configuration.scopeKey
|
|
97
|
+
configuration.scopeKey,
|
|
98
98
|
commitTime,
|
|
99
99
|
runtimeVersion,
|
|
100
100
|
assets
|
|
@@ -34,8 +34,7 @@ class LegacyUpdateManifest private constructor(
|
|
|
34
34
|
private val mAssets: JSONArray?
|
|
35
35
|
) : UpdateManifest {
|
|
36
36
|
override val updateEntity: UpdateEntity by lazy {
|
|
37
|
-
UpdateEntity(mId, mCommitTime, mRuntimeVersion, mScopeKey).apply {
|
|
38
|
-
manifest = this@LegacyUpdateManifest.manifest.getRawJson()
|
|
37
|
+
UpdateEntity(mId, mCommitTime, mRuntimeVersion, mScopeKey, this@LegacyUpdateManifest.manifest.getRawJson()).apply {
|
|
39
38
|
if (isDevelopmentMode) {
|
|
40
39
|
status = UpdateStatus.DEVELOPMENT
|
|
41
40
|
}
|
|
@@ -31,9 +31,7 @@ class NewUpdateManifest private constructor(
|
|
|
31
31
|
private val mExtensions: JSONObject?
|
|
32
32
|
) : UpdateManifest {
|
|
33
33
|
override val updateEntity: UpdateEntity by lazy {
|
|
34
|
-
UpdateEntity(mId, mCommitTime, mRuntimeVersion, mScopeKey)
|
|
35
|
-
manifest = this@NewUpdateManifest.manifest.getRawJson()
|
|
36
|
-
}
|
|
34
|
+
UpdateEntity(mId, mCommitTime, mRuntimeVersion, mScopeKey, this@NewUpdateManifest.manifest.getRawJson())
|
|
37
35
|
}
|
|
38
36
|
|
|
39
37
|
private val assetHeaders: Map<String, JSONObject> by lazy {
|
|
@@ -13,13 +13,12 @@ object SelectionPolicies {
|
|
|
13
13
|
val TAG = SelectionPolicies::class.java.simpleName
|
|
14
14
|
|
|
15
15
|
fun matchesFilters(update: UpdateEntity, manifestFilters: JSONObject?): Boolean {
|
|
16
|
-
|
|
17
|
-
if (manifestFilters == null || rawManifest == null) {
|
|
16
|
+
if (manifestFilters == null) {
|
|
18
17
|
// empty matches all
|
|
19
18
|
return true
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
val manifest = Manifest.fromManifestJson(
|
|
21
|
+
val manifest = Manifest.fromManifestJson(update.manifest)
|
|
23
22
|
val metadata = manifest.getMetadata() ?: return true // empty matches all
|
|
24
23
|
|
|
25
24
|
try {
|
|
@@ -14,12 +14,12 @@ The state machine context, with information intended to be consumed by applicati
|
|
|
14
14
|
data class UpdatesStateContext(
|
|
15
15
|
val isUpdateAvailable: Boolean = false,
|
|
16
16
|
val isUpdatePending: Boolean = false,
|
|
17
|
-
val isRollback: Boolean = false,
|
|
18
17
|
val isChecking: Boolean = false,
|
|
19
18
|
val isDownloading: Boolean = false,
|
|
20
19
|
val isRestarting: Boolean = false,
|
|
21
20
|
val latestManifest: JSONObject? = null,
|
|
22
21
|
val downloadedManifest: JSONObject? = null,
|
|
22
|
+
val rollback: UpdatesStateContextRollback? = null,
|
|
23
23
|
val checkError: UpdatesStateError? = null,
|
|
24
24
|
val downloadError: UpdatesStateError? = null,
|
|
25
25
|
val lastCheckForUpdateTime: Date? = null,
|
|
@@ -30,7 +30,6 @@ data class UpdatesStateContext(
|
|
|
30
30
|
val map: MutableMap<String, Any> = mutableMapOf(
|
|
31
31
|
"isUpdateAvailable" to isUpdateAvailable,
|
|
32
32
|
"isUpdatePending" to isUpdatePending,
|
|
33
|
-
"isRollback" to isRollback,
|
|
34
33
|
"isChecking" to isChecking,
|
|
35
34
|
"isDownloading" to isDownloading,
|
|
36
35
|
"isRestarting" to isRestarting
|
|
@@ -41,6 +40,9 @@ data class UpdatesStateContext(
|
|
|
41
40
|
if (downloadedManifest != null) {
|
|
42
41
|
map["downloadedManifest"] = downloadedManifest
|
|
43
42
|
}
|
|
43
|
+
if (rollback != null) {
|
|
44
|
+
map["rollback"] = rollback.json
|
|
45
|
+
}
|
|
44
46
|
if (checkError != null) {
|
|
45
47
|
map["checkError"] = checkError.json
|
|
46
48
|
}
|
|
@@ -71,7 +73,6 @@ data class UpdatesStateContext(
|
|
|
71
73
|
return Bundle().apply {
|
|
72
74
|
putBoolean("isUpdateAvailable", isUpdateAvailable)
|
|
73
75
|
putBoolean("isUpdatePending", isUpdatePending)
|
|
74
|
-
putBoolean("isRollback", isRollback)
|
|
75
76
|
putBoolean("isChecking", isChecking)
|
|
76
77
|
putBoolean("isDownloading", isDownloading)
|
|
77
78
|
putBoolean("isRestarting", isRestarting)
|
|
@@ -81,6 +82,14 @@ data class UpdatesStateContext(
|
|
|
81
82
|
if (downloadedManifest != null) {
|
|
82
83
|
putString("downloadedManifestString", downloadedManifest.toString())
|
|
83
84
|
}
|
|
85
|
+
if (rollback != null) {
|
|
86
|
+
putBundle(
|
|
87
|
+
"rollback",
|
|
88
|
+
Bundle().apply {
|
|
89
|
+
putString("commitTime", rollback.commitTimeString)
|
|
90
|
+
}
|
|
91
|
+
)
|
|
92
|
+
}
|
|
84
93
|
if (checkError != null) {
|
|
85
94
|
val errorMap = Bundle().apply {
|
|
86
95
|
putString("message", checkError.message)
|
package/android/src/main/java/expo/modules/updates/statemachine/UpdatesStateContextRollback.kt
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
package expo.modules.updates.statemachine
|
|
2
|
+
|
|
3
|
+
import java.util.Date
|
|
4
|
+
|
|
5
|
+
data class UpdatesStateContextRollback(
|
|
6
|
+
val commitTime: Date
|
|
7
|
+
) {
|
|
8
|
+
|
|
9
|
+
val commitTimeString: String
|
|
10
|
+
get() = UpdatesStateContext.DATE_FORMATTER.format(commitTime)
|
|
11
|
+
|
|
12
|
+
val json: Map<String, Any>
|
|
13
|
+
get() = mapOf("commitTime" to commitTimeString)
|
|
14
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package expo.modules.updates.statemachine
|
|
2
2
|
|
|
3
3
|
import org.json.JSONObject
|
|
4
|
+
import java.util.Date
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
Structure representing an event that can be sent to the machine.
|
|
@@ -20,9 +21,9 @@ sealed class UpdatesStateEvent(val type: UpdatesStateEventType) {
|
|
|
20
21
|
return UpdatesStateError(errorMessage)
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
|
-
class CheckCompleteUnavailable : UpdatesStateEvent(UpdatesStateEventType.CheckCompleteUnavailable)
|
|
24
|
+
class CheckCompleteUnavailable() : UpdatesStateEvent(UpdatesStateEventType.CheckCompleteUnavailable)
|
|
24
25
|
class CheckCompleteWithUpdate(val manifest: JSONObject) : UpdatesStateEvent(UpdatesStateEventType.CheckCompleteAvailable)
|
|
25
|
-
class CheckCompleteWithRollback : UpdatesStateEvent(UpdatesStateEventType.CheckCompleteAvailable)
|
|
26
|
+
class CheckCompleteWithRollback(val commitTime: Date) : UpdatesStateEvent(UpdatesStateEventType.CheckCompleteAvailable)
|
|
26
27
|
class DownloadComplete : UpdatesStateEvent(UpdatesStateEventType.DownloadComplete)
|
|
27
28
|
class DownloadCompleteWithUpdate(val manifest: JSONObject) : UpdatesStateEvent(UpdatesStateEventType.DownloadComplete)
|
|
28
29
|
class DownloadCompleteWithRollback : UpdatesStateEvent(UpdatesStateEventType.DownloadComplete)
|
|
@@ -106,24 +106,24 @@ class UpdatesStateMachine(
|
|
|
106
106
|
isChecking = false,
|
|
107
107
|
checkError = null,
|
|
108
108
|
latestManifest = null,
|
|
109
|
+
rollback = null,
|
|
109
110
|
isUpdateAvailable = false,
|
|
110
|
-
isRollback = false,
|
|
111
111
|
lastCheckForUpdateTime = Date(),
|
|
112
112
|
)
|
|
113
113
|
is UpdatesStateEvent.CheckCompleteWithRollback -> context.copy(
|
|
114
114
|
isChecking = false,
|
|
115
115
|
checkError = null,
|
|
116
116
|
latestManifest = null,
|
|
117
|
+
rollback = UpdatesStateContextRollback(event.commitTime),
|
|
117
118
|
isUpdateAvailable = true,
|
|
118
|
-
isRollback = true,
|
|
119
119
|
lastCheckForUpdateTime = Date()
|
|
120
120
|
)
|
|
121
121
|
is UpdatesStateEvent.CheckCompleteWithUpdate -> context.copy(
|
|
122
122
|
isChecking = false,
|
|
123
123
|
checkError = null,
|
|
124
124
|
latestManifest = event.manifest,
|
|
125
|
+
rollback = null,
|
|
125
126
|
isUpdateAvailable = true,
|
|
126
|
-
isRollback = false,
|
|
127
127
|
lastCheckForUpdateTime = Date()
|
|
128
128
|
)
|
|
129
129
|
is UpdatesStateEvent.CheckError -> context.copy(
|
|
@@ -140,13 +140,14 @@ class UpdatesStateMachine(
|
|
|
140
140
|
is UpdatesStateEvent.DownloadCompleteWithRollback -> context.copy(
|
|
141
141
|
isDownloading = false,
|
|
142
142
|
downloadError = null,
|
|
143
|
-
isUpdatePending = true
|
|
143
|
+
isUpdatePending = true
|
|
144
144
|
)
|
|
145
145
|
is UpdatesStateEvent.DownloadCompleteWithUpdate -> context.copy(
|
|
146
146
|
isDownloading = false,
|
|
147
147
|
downloadError = null,
|
|
148
148
|
latestManifest = event.manifest,
|
|
149
149
|
downloadedManifest = event.manifest,
|
|
150
|
+
rollback = null,
|
|
150
151
|
isUpdatePending = true,
|
|
151
152
|
isUpdateAvailable = true
|
|
152
153
|
)
|