expo-updates 0.14.6 → 0.15.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 +26 -6
- package/android/build.gradle +15 -2
- package/android/proguard-rules.pro +1 -1
- package/android/src/main/java/expo/modules/updates/UpdatesConfiguration.kt +11 -0
- package/android/src/main/java/expo/modules/updates/UpdatesController.kt +43 -1
- package/android/src/main/java/expo/modules/updates/UpdatesDevLauncherController.kt +17 -5
- package/android/src/main/java/expo/modules/updates/UpdatesInterface.kt +4 -0
- package/android/src/main/java/expo/modules/updates/UpdatesModule.kt +64 -0
- package/android/src/main/java/expo/modules/updates/UpdatesPackage.kt +9 -4
- package/android/src/main/java/expo/modules/updates/UpdatesService.kt +9 -2
- package/android/src/main/java/expo/modules/updates/UpdatesUtils.kt +3 -0
- package/android/src/main/java/expo/modules/updates/db/DatabaseHolder.kt +11 -0
- package/android/src/main/java/expo/modules/updates/db/Reaper.kt +6 -0
- package/android/src/main/java/expo/modules/updates/db/UpdatesDatabase.kt +25 -0
- package/android/src/main/java/expo/modules/updates/db/dao/AssetDao.kt +3 -0
- package/android/src/main/java/expo/modules/updates/db/dao/JSONDataDao.kt +3 -0
- package/android/src/main/java/expo/modules/updates/db/dao/UpdateDao.kt +3 -0
- package/android/src/main/java/expo/modules/updates/db/entity/AssetEntity.kt +8 -0
- package/android/src/main/java/expo/modules/updates/db/entity/JSONDataEntity.kt +10 -0
- package/android/src/main/java/expo/modules/updates/db/entity/UpdateAssetEntity.kt +7 -0
- package/android/src/main/java/expo/modules/updates/db/entity/UpdateEntity.kt +17 -0
- package/android/src/main/java/expo/modules/updates/errorrecovery/ErrorRecovery.kt +30 -9
- package/android/src/main/java/expo/modules/updates/errorrecovery/ErrorRecoveryDelegate.kt +4 -0
- package/android/src/main/java/expo/modules/updates/errorrecovery/ErrorRecoveryHandler.kt +54 -5
- package/android/src/main/java/expo/modules/updates/launcher/DatabaseLauncher.kt +21 -0
- package/android/src/main/java/expo/modules/updates/launcher/Launcher.kt +25 -0
- package/android/src/main/java/expo/modules/updates/launcher/NoDatabaseLauncher.kt +8 -0
- package/android/src/main/java/expo/modules/updates/loader/FileDownloader.kt +57 -34
- package/android/src/main/java/expo/modules/updates/loader/Loader.kt +7 -0
- package/android/src/main/java/expo/modules/updates/loader/LoaderTask.kt +19 -0
- package/android/src/main/java/expo/modules/updates/logging/UpdatesErrorCode.kt +16 -0
- package/android/src/main/java/expo/modules/updates/logging/UpdatesLogEntry.kt +62 -0
- package/android/src/main/java/expo/modules/updates/logging/UpdatesLogReader.kt +60 -0
- package/android/src/main/java/expo/modules/updates/logging/UpdatesLogger.kt +165 -0
- package/android/src/main/java/expo/modules/updates/manifest/BareUpdateManifest.kt +6 -0
- package/android/src/main/java/expo/modules/updates/manifest/EmbeddedManifest.kt +3 -0
- package/android/src/main/java/expo/modules/updates/manifest/LegacyUpdateManifest.kt +8 -0
- package/android/src/main/java/expo/modules/updates/manifest/ManifestFactory.kt +3 -0
- package/android/src/main/java/expo/modules/updates/manifest/ManifestMetadata.kt +4 -0
- package/android/src/main/java/expo/modules/updates/manifest/NewUpdateManifest.kt +4 -0
- package/android/src/main/java/expo/modules/updates/manifest/UpdateManifest.kt +4 -0
- package/android/src/main/java/expo/modules/updates/selectionpolicy/LauncherSelectionPolicyFilterAware.kt +3 -2
- package/android/src/main/java/expo/modules/updates/selectionpolicy/LoaderSelectionPolicyFilterAware.kt +2 -0
- package/android/src/main/java/expo/modules/updates/selectionpolicy/ReaperSelectionPolicyDevelopmentClient.kt +2 -0
- package/android/src/main/java/expo/modules/updates/selectionpolicy/ReaperSelectionPolicyFilterAware.kt +2 -0
- package/android/src/main/java/expo/modules/updates/selectionpolicy/SelectionPolicies.kt +3 -0
- package/android/src/main/java/expo/modules/updates/selectionpolicy/SelectionPolicy.kt +36 -0
- package/android/src/main/java/expo/modules/updates/selectionpolicy/SelectionPolicyFactory.kt +4 -0
- package/build/Updates.d.ts +24 -2
- package/build/Updates.d.ts.map +1 -1
- package/build/Updates.js +33 -1
- package/build/Updates.js.map +1 -1
- package/build/Updates.types.d.ts +105 -13
- package/build/Updates.types.d.ts.map +1 -1
- package/build/Updates.types.js +27 -0
- package/build/Updates.types.js.map +1 -1
- package/build-cli/configureCodeSigning.js +3 -0
- package/build-cli/configureCodeSigningAsync.d.ts +2 -1
- package/build-cli/configureCodeSigningAsync.js +2 -2
- package/cli/configureCodeSigning.ts +3 -0
- package/cli/configureCodeSigningAsync.ts +3 -3
- package/guides/examples.md +88 -0
- package/guides/general.md +33 -0
- package/guides/migrations.md +65 -0
- package/guides/releasing.md +18 -0
- package/ios/EXUpdates/AppLauncher/EXUpdatesAppLauncher.h +5 -0
- package/ios/EXUpdates/AppLauncher/EXUpdatesAppLauncherNoDatabase.m +8 -0
- package/ios/EXUpdates/AppLauncher/EXUpdatesAppLauncherWithDatabase.m +18 -0
- package/ios/EXUpdates/AppLoader/EXUpdatesAppLoader.m +7 -0
- package/ios/EXUpdates/AppLoader/EXUpdatesAppLoaderTask.m +38 -4
- package/ios/EXUpdates/AppLoader/EXUpdatesAsset.m +4 -0
- package/ios/EXUpdates/AppLoader/EXUpdatesCrypto.m +3 -0
- package/ios/EXUpdates/AppLoader/EXUpdatesEmbeddedAppLoader.m +10 -0
- package/ios/EXUpdates/AppLoader/EXUpdatesFileDownloader.m +66 -28
- package/ios/EXUpdates/AppLoader/EXUpdatesRemoteAppLoader.m +3 -0
- package/ios/EXUpdates/Database/EXUpdatesDatabase.h +24 -0
- package/ios/EXUpdates/Database/EXUpdatesDatabaseInitialization.m +3 -0
- package/ios/EXUpdates/Database/EXUpdatesDatabaseUtils.m +3 -0
- package/ios/EXUpdates/Database/EXUpdatesReaper.h +5 -0
- package/ios/EXUpdates/EXUpdatesAppController+Internal.h +1 -0
- package/ios/EXUpdates/EXUpdatesAppController.m +65 -2
- package/ios/EXUpdates/EXUpdatesConfig.m +11 -0
- package/ios/EXUpdates/EXUpdatesDevLauncherController.m +13 -0
- package/ios/EXUpdates/EXUpdatesErrorRecovery.m +48 -0
- package/ios/EXUpdates/EXUpdatesModule.m +47 -0
- package/ios/EXUpdates/EXUpdatesService.m +8 -0
- package/ios/EXUpdates/EXUpdatesUtils.h +2 -0
- package/ios/EXUpdates/EXUpdatesUtils.m +30 -1
- package/ios/EXUpdates/Logging/UpdatesErrorCode.swift +46 -0
- package/ios/EXUpdates/Logging/UpdatesLogEntry.swift +77 -0
- package/ios/EXUpdates/Logging/UpdatesLogReader.swift +91 -0
- package/ios/EXUpdates/Logging/UpdatesLogger.swift +176 -0
- package/ios/EXUpdates/ReactDelegateHandler/ExpoUpdatesAppDelegateSubscriber.swift +6 -1
- package/ios/EXUpdates/ReactDelegateHandler/ExpoUpdatesReactDelegateHandler.swift +8 -1
- package/ios/EXUpdates/SelectionPolicy/EXUpdatesLauncherSelectionPolicyFilterAware.h +4 -3
- package/ios/EXUpdates/SelectionPolicy/EXUpdatesLoaderSelectionPolicyFilterAware.h +2 -0
- package/ios/EXUpdates/SelectionPolicy/EXUpdatesReaperSelectionPolicyDevelopmentClient.h +2 -0
- package/ios/EXUpdates/SelectionPolicy/EXUpdatesReaperSelectionPolicyFilterAware.h +2 -0
- package/ios/EXUpdates/SelectionPolicy/EXUpdatesSelectionPolicies.m +3 -0
- package/ios/EXUpdates/SelectionPolicy/EXUpdatesSelectionPolicy.h +22 -0
- package/ios/EXUpdates/SelectionPolicy/EXUpdatesSelectionPolicyFactory.m +4 -0
- package/ios/EXUpdates/Update/EXUpdatesBareUpdate.m +7 -0
- package/ios/EXUpdates/Update/EXUpdatesLegacyUpdate.m +8 -0
- package/ios/EXUpdates/Update/EXUpdatesNewUpdate.m +5 -0
- package/ios/EXUpdates/Update/EXUpdatesUpdate.h +20 -0
- package/ios/EXUpdates/Update/EXUpdatesUpdate.m +5 -0
- package/ios/EXUpdates.podspec +10 -4
- package/ios/Tests/EXUpdatesFileDownloaderTests.m +26 -2
- package/ios/Tests/EXUpdatesLogReaderTests.swift +131 -0
- package/ios/Tests/EXUpdatesLoggerTests.swift +54 -0
- package/package.json +8 -8
- package/plugin/build/withUpdates.d.ts +1 -1
- package/plugin/build/withUpdates.js +2 -3
- package/plugin/src/withUpdates.ts +1 -1
- package/scripts/create-manifest-ios.sh +0 -1
- package/scripts/createManifest.js +18 -2
- package/src/Updates.ts +36 -1
- package/src/Updates.types.ts +111 -13
package/CHANGELOG.md
CHANGED
|
@@ -10,19 +10,39 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
-
## 0.
|
|
13
|
+
## 0.15.0 — 2022-10-25
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
### 🛠 Breaking changes
|
|
16
|
+
|
|
17
|
+
- [plugin] Upgrade minimum runtime requirement to Node 14 (LTS). ([#18204](https://github.com/expo/expo/pull/18204) by [@EvanBacon](https://github.com/EvanBacon))
|
|
18
|
+
- Bumped iOS deployment target to 13.0 and deprecated support for iOS 12. ([#18873](https://github.com/expo/expo/pull/18873) by [@tsapeta](https://github.com/tsapeta))
|
|
19
|
+
|
|
20
|
+
### 🎉 New features
|
|
16
21
|
|
|
17
|
-
|
|
22
|
+
- [iOS] New logger and log reader for unifying logging support in expo-updates. ([#18284](https://github.com/expo/expo/pull/18284) by [@douglowder](https://github.com/douglowder))
|
|
23
|
+
- [Android] New logger and log reader for unifying logging support in expo-updates. ([#18318](https://github.com/expo/expo/pull/18318) by [@douglowder](https://github.com/douglowder))
|
|
24
|
+
- Add JS methods to read and clear client logs. ([#18390](https://github.com/expo/expo/pull/18390) by [@douglowder](https://github.com/douglowder))
|
|
25
|
+
- Add Logger support for writing logs to a file; add Logger and associated classes to Android. ([#18513](https://github.com/expo/expo/pull/18513) by [@douglowder](https://github.com/douglowder))
|
|
26
|
+
- Make extra header processing code consistent between manifests and assets. ([#18564](https://github.com/expo/expo/pull/18564) by [@wschurman](https://github.com/wschurman))
|
|
27
|
+
- Type `UpdateCheckResult` and `UpdateFetchResult` to reflect when `manifest` is defined or not. ([#18577](https://github.com/expo/expo/pull/18577) by [@SimenB](https://github.com/SimenB))
|
|
18
28
|
|
|
19
29
|
### 🐛 Bug fixes
|
|
20
30
|
|
|
21
|
-
-
|
|
31
|
+
- Fix small race condition in recovery code on Android where in very rare scenarios, a bundle could be downloaded twice. ([#18377](https://github.com/expo/expo/pull/18377) by [@esamelson](https://github.com/esamelson))
|
|
32
|
+
- Fixed _with-node.sh_ doesn't keep quotes when passing arguments to Node.js and caused build errors when there are spaces in target name. ([#18741](https://github.com/expo/expo/pull/18741) by [@kudo](https://github.com/kudo))
|
|
22
33
|
|
|
23
|
-
|
|
34
|
+
### 💡 Others
|
|
24
35
|
|
|
25
|
-
|
|
36
|
+
- [plugin] Migrate import from @expo/config-plugins to expo/config-plugins and @expo/config-types to expo/config. ([#18855](https://github.com/expo/expo/pull/18855) by [@brentvatne](https://github.com/brentvatne))
|
|
37
|
+
- Update doc block link for manifests. ([#18981](https://github.com/expo/expo/pull/18981) by [@EvanBacon](https://github.com/EvanBacon))
|
|
38
|
+
- Drop `@expo/config-plugins` dependency in favor of peer dependency on `expo`. ([#18595](https://github.com/expo/expo/pull/18595) by [@EvanBacon](https://github.com/EvanBacon))
|
|
39
|
+
- Log various errors with the new Updates logger; add E2E tests for the logger. ([#18810](https://github.com/expo/expo/pull/18810) by [@douglowder](https://github.com/douglowder))
|
|
40
|
+
- [iOS] Flag to enable native debugging of updates. ([#19292](https://github.com/expo/expo/pull/19292) by [@douglowder](https://github.com/douglowder))
|
|
41
|
+
- [Android] Flag to enable native debugging of updates. ([#19441](https://github.com/expo/expo/pull/19441) by [@douglowder](https://github.com/douglowder))
|
|
42
|
+
|
|
43
|
+
### ⚠️ Notices
|
|
44
|
+
|
|
45
|
+
- Added support for React Native 0.70.x. ([#19261](https://github.com/expo/expo/pull/19261) by [@kudo](https://github.com/kudo))
|
|
26
46
|
|
|
27
47
|
## 0.14.3 — 2022-07-25
|
|
28
48
|
|
package/android/build.gradle
CHANGED
|
@@ -4,7 +4,19 @@ apply plugin: 'kotlin-kapt'
|
|
|
4
4
|
apply plugin: 'maven-publish'
|
|
5
5
|
|
|
6
6
|
group = 'host.exp.exponent'
|
|
7
|
-
version = '0.
|
|
7
|
+
version = '0.15.0'
|
|
8
|
+
|
|
9
|
+
def ex_updates_native_debug_env = System.getenv("EX_UPDATES_NATIVE_DEBUG") ?: "0"
|
|
10
|
+
def ex_updates_native_debug = ex_updates_native_debug_env == "1" ? "true" : "false"
|
|
11
|
+
|
|
12
|
+
// For native updates debugging, override these properties
|
|
13
|
+
if (findProject(":app")) {
|
|
14
|
+
def appProjectExt = project(":app").ext
|
|
15
|
+
if (appProjectExt.has("react") && ex_updates_native_debug) {
|
|
16
|
+
appProjectExt.react.bundleInDebug = true
|
|
17
|
+
appProjectExt.react.devDisabledInDebug = true
|
|
18
|
+
}
|
|
19
|
+
}
|
|
8
20
|
|
|
9
21
|
apply from: "../scripts/create-manifest-android.gradle"
|
|
10
22
|
|
|
@@ -77,9 +89,10 @@ android {
|
|
|
77
89
|
minSdkVersion safeExtGet("minSdkVersion", 21)
|
|
78
90
|
targetSdkVersion safeExtGet("targetSdkVersion", 31)
|
|
79
91
|
versionCode 31
|
|
80
|
-
versionName '0.
|
|
92
|
+
versionName '0.15.0'
|
|
81
93
|
consumerProguardFiles("proguard-rules.pro")
|
|
82
94
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
95
|
+
buildConfigField("boolean", "EX_UPDATES_NATIVE_DEBUG", ex_updates_native_debug)
|
|
83
96
|
// uncomment below to export the database schema when making changes
|
|
84
97
|
/* javaCompileOptions {
|
|
85
98
|
annotationProcessorOptions {
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
-keepclassmembers class com.facebook.react.devsupport.DisabledDevSupportManager {
|
|
6
|
-
private final com.facebook.react.bridge.
|
|
6
|
+
private final com.facebook.react.bridge.DefaultJSExceptionHandler mDefaultJSExceptionHandler;
|
|
7
7
|
}
|
|
@@ -6,6 +6,17 @@ import android.net.Uri
|
|
|
6
6
|
import android.util.Log
|
|
7
7
|
import expo.modules.updates.codesigning.CodeSigningConfiguration
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Holds global, immutable configuration values for updates, as well as doing some rudimentary
|
|
11
|
+
* validation.
|
|
12
|
+
*
|
|
13
|
+
* In most apps, these configuration values are baked into the build, and this class functions as a
|
|
14
|
+
* utility for reading and memoizing the values.
|
|
15
|
+
*
|
|
16
|
+
* In development clients (including Expo Go) where this configuration is intended to be dynamic at
|
|
17
|
+
* runtime and updates from multiple scopes can potentially be opened, multiple instances of this
|
|
18
|
+
* class may be created over the lifetime of the app, but only one should be active at a time.
|
|
19
|
+
*/
|
|
9
20
|
class UpdatesConfiguration private constructor (
|
|
10
21
|
val isEnabled: Boolean,
|
|
11
22
|
val expectsSignedManifest: Boolean,
|
|
@@ -30,12 +30,34 @@ import expo.modules.updates.loader.LoaderTask
|
|
|
30
30
|
import expo.modules.updates.loader.LoaderTask.BackgroundUpdateStatus
|
|
31
31
|
import expo.modules.updates.loader.LoaderTask.LoaderTaskCallback
|
|
32
32
|
import expo.modules.updates.loader.RemoteLoader
|
|
33
|
+
import expo.modules.updates.logging.UpdatesErrorCode
|
|
34
|
+
import expo.modules.updates.logging.UpdatesLogReader
|
|
35
|
+
import expo.modules.updates.logging.UpdatesLogger
|
|
33
36
|
import expo.modules.updates.manifest.UpdateManifest
|
|
34
37
|
import expo.modules.updates.selectionpolicy.SelectionPolicy
|
|
35
38
|
import expo.modules.updates.selectionpolicy.SelectionPolicyFactory
|
|
36
39
|
import java.io.File
|
|
37
40
|
import java.lang.ref.WeakReference
|
|
38
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Main entry point to expo-updates in normal release builds (development clients, including Expo
|
|
44
|
+
* Go, use a different entry point). Singleton that keeps track of updates state, holds references
|
|
45
|
+
* to instances of other updates classes, and is the central hub for all updates-related tasks.
|
|
46
|
+
*
|
|
47
|
+
* The `start` method in this class should be invoked early in the application lifecycle, via
|
|
48
|
+
* [UpdatesPackage]. It delegates to an instance of [LoaderTask] to start the process of loading and
|
|
49
|
+
* launching an update, then responds appropriately depending on the callbacks that are invoked.
|
|
50
|
+
*
|
|
51
|
+
* This class also provides getter methods to access information about the updates state, which are
|
|
52
|
+
* used by the exported [UpdatesModule] through [UpdatesService]. Such information includes
|
|
53
|
+
* references to: the database, the [UpdatesConfiguration] object, the path on disk to the updates
|
|
54
|
+
* directory, any currently active [LoaderTask], the current [SelectionPolicy], the error recovery
|
|
55
|
+
* handler, and the current launched update. This class is intended to be the source of truth for
|
|
56
|
+
* these objects, so other classes shouldn't retain any of them indefinitely.
|
|
57
|
+
*
|
|
58
|
+
* This class also optionally holds a reference to the app's [ReactNativeHost], which allows
|
|
59
|
+
* expo-updates to reload JS and send events through the bridge.
|
|
60
|
+
*/
|
|
39
61
|
class UpdatesController private constructor(
|
|
40
62
|
context: Context,
|
|
41
63
|
var updatesConfiguration: UpdatesConfiguration
|
|
@@ -62,6 +84,15 @@ class UpdatesController private constructor(
|
|
|
62
84
|
}
|
|
63
85
|
}
|
|
64
86
|
|
|
87
|
+
private fun purgeUpdatesLogsOlderThanOneDay(context: Context) {
|
|
88
|
+
UpdatesLogReader(context).purgeLogEntries {
|
|
89
|
+
if (it != null) {
|
|
90
|
+
Log.e(TAG, "UpdatesLogReader: error in purgeLogEntries", it)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private val logger = UpdatesLogger(context)
|
|
65
96
|
private var isStarted = false
|
|
66
97
|
private var loaderTask: LoaderTask? = null
|
|
67
98
|
private var remoteLoadStatus = ErrorRecoveryDelegate.RemoteLoadStatus.IDLE
|
|
@@ -71,7 +102,7 @@ class UpdatesController private constructor(
|
|
|
71
102
|
UpdatesUtils.getRuntimeVersion(updatesConfiguration)
|
|
72
103
|
)
|
|
73
104
|
val fileDownloader: FileDownloader = FileDownloader(context)
|
|
74
|
-
private val errorRecovery: ErrorRecovery = ErrorRecovery()
|
|
105
|
+
private val errorRecovery: ErrorRecovery = ErrorRecovery(context)
|
|
75
106
|
|
|
76
107
|
private fun setRemoteLoadStatus(status: ErrorRecoveryDelegate.RemoteLoadStatus) {
|
|
77
108
|
remoteLoadStatus = status
|
|
@@ -143,6 +174,10 @@ class UpdatesController private constructor(
|
|
|
143
174
|
val isUsingEmbeddedAssets: Boolean
|
|
144
175
|
get() = launcher?.isUsingEmbeddedAssets ?: false
|
|
145
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Any process that calls this *must* manually release the lock by calling `releaseDatabase()` in
|
|
179
|
+
* every possible case (success, error) as soon as it is finished.
|
|
180
|
+
*/
|
|
146
181
|
fun getDatabase(): UpdatesDatabase = databaseHolder.database
|
|
147
182
|
|
|
148
183
|
fun releaseDatabase() {
|
|
@@ -214,6 +249,8 @@ class UpdatesController private constructor(
|
|
|
214
249
|
return
|
|
215
250
|
}
|
|
216
251
|
|
|
252
|
+
purgeUpdatesLogsOlderThanOneDay(context)
|
|
253
|
+
|
|
217
254
|
initializeDatabaseHandler()
|
|
218
255
|
initializeErrorRecovery(context)
|
|
219
256
|
|
|
@@ -229,6 +266,7 @@ class UpdatesController private constructor(
|
|
|
229
266
|
selectionPolicy,
|
|
230
267
|
object : LoaderTaskCallback {
|
|
231
268
|
override fun onFailure(e: Exception) {
|
|
269
|
+
logger.error("UpdatesController loaderTask onFailure: ${e.localizedMessage}", UpdatesErrorCode.None)
|
|
232
270
|
launcher = NoDatabaseLauncher(context, updatesConfiguration, e)
|
|
233
271
|
isEmergencyLaunch = true
|
|
234
272
|
notifyController()
|
|
@@ -260,6 +298,7 @@ class UpdatesController private constructor(
|
|
|
260
298
|
if (exception == null) {
|
|
261
299
|
throw AssertionError("Background update with error status must have a nonnull exception object")
|
|
262
300
|
}
|
|
301
|
+
logger.error("UpdatesController onBackgroundUpdateFinished: Error: ${exception.localizedMessage}", UpdatesErrorCode.Unknown, exception)
|
|
263
302
|
remoteLoadStatus = ErrorRecoveryDelegate.RemoteLoadStatus.IDLE
|
|
264
303
|
val params = Arguments.createMap()
|
|
265
304
|
params.putString("message", exception.message)
|
|
@@ -270,12 +309,14 @@ class UpdatesController private constructor(
|
|
|
270
309
|
throw AssertionError("Background update with error status must have a nonnull update object")
|
|
271
310
|
}
|
|
272
311
|
remoteLoadStatus = ErrorRecoveryDelegate.RemoteLoadStatus.NEW_UPDATE_LOADED
|
|
312
|
+
logger.info("UpdatesController onBackgroundUpdateFinished: Update available", UpdatesErrorCode.None)
|
|
273
313
|
val params = Arguments.createMap()
|
|
274
314
|
params.putString("manifestString", update.manifest.toString())
|
|
275
315
|
UpdatesUtils.sendEventToReactNative(reactNativeHost, UPDATE_AVAILABLE_EVENT, params)
|
|
276
316
|
}
|
|
277
317
|
BackgroundUpdateStatus.NO_UPDATE_AVAILABLE -> {
|
|
278
318
|
remoteLoadStatus = ErrorRecoveryDelegate.RemoteLoadStatus.IDLE
|
|
319
|
+
logger.error("UpdatesController onBackgroundUpdateFinished: No update available", UpdatesErrorCode.NoUpdatesAvailable)
|
|
279
320
|
UpdatesUtils.sendEventToReactNative(
|
|
280
321
|
reactNativeHost,
|
|
281
322
|
UPDATE_NO_UPDATE_AVAILABLE_EVENT,
|
|
@@ -310,6 +351,7 @@ class UpdatesController private constructor(
|
|
|
310
351
|
val remoteLoader = RemoteLoader(context, updatesConfiguration, database, fileDownloader, updatesDirectory, launchedUpdate)
|
|
311
352
|
remoteLoader.start(object : Loader.LoaderCallback {
|
|
312
353
|
override fun onFailure(e: Exception) {
|
|
354
|
+
logger.error("UpdatesController loadRemoteUpdate onFailure: ${e.localizedMessage}", UpdatesErrorCode.UpdateFailedToLoad, launchedUpdate?.loggingId, null)
|
|
313
355
|
setRemoteLoadStatus(ErrorRecoveryDelegate.RemoteLoadStatus.IDLE)
|
|
314
356
|
releaseDatabase()
|
|
315
357
|
}
|
|
@@ -17,17 +17,25 @@ import expo.modules.updatesinterface.UpdatesInterface.UpdateCallback
|
|
|
17
17
|
import org.json.JSONObject
|
|
18
18
|
import java.util.*
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Main entry point to expo-updates in development builds with expo-dev-client. Singleton that still
|
|
22
|
+
* makes use of [UpdatesController] for keeping track of updates state, but provides capabilities
|
|
23
|
+
* that are not usually exposed but that expo-dev-client needs (launching and downloading a specific
|
|
24
|
+
* update by URL, allowing dynamic configuration, introspecting the database).
|
|
25
|
+
*
|
|
26
|
+
* Implements the external UpdatesInterface from the expo-updates-interface package. This allows
|
|
27
|
+
* expo-dev-client to compile without needing expo-updates to be installed.
|
|
28
|
+
*/
|
|
25
29
|
class UpdatesDevLauncherController : UpdatesInterface {
|
|
26
30
|
private var mTempConfiguration: UpdatesConfiguration? = null
|
|
27
31
|
override fun reset() {
|
|
28
32
|
UpdatesController.instance.setLauncher(null)
|
|
29
33
|
}
|
|
30
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Fetch an update using a dynamically generated configuration object (including a potentially
|
|
37
|
+
* different update URL than the one embedded in the build).
|
|
38
|
+
*/
|
|
31
39
|
override fun fetchUpdateWithConfiguration(
|
|
32
40
|
configuration: HashMap<String, Any>,
|
|
33
41
|
context: Context,
|
|
@@ -99,6 +107,10 @@ class UpdatesDevLauncherController : UpdatesInterface {
|
|
|
99
107
|
|
|
100
108
|
// ensure that we launch the update we want, even if it isn't the latest one
|
|
101
109
|
val currentSelectionPolicy = controller.selectionPolicy
|
|
110
|
+
// Calling `setNextSelectionPolicy` allows the Updates module's `reloadAsync` method to reload
|
|
111
|
+
// with a different (newer) update if one is downloaded, e.g. using `fetchUpdateAsync`. If we
|
|
112
|
+
// set the default selection policy here instead, the update we are launching here would keep
|
|
113
|
+
// being launched by `reloadAsync` even if a newer one is downloaded.
|
|
102
114
|
controller.setNextSelectionPolicy(
|
|
103
115
|
SelectionPolicy(
|
|
104
116
|
LauncherSelectionPolicySingleUpdate(update.id),
|
|
@@ -13,6 +13,10 @@ import java.io.File
|
|
|
13
13
|
import expo.modules.updates.UpdatesConfiguration
|
|
14
14
|
/* ktlint-enable no-unused-imports */
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Interface implemented by the [UpdatesService] internal module and used by [UpdatesModule] to
|
|
18
|
+
* search for the correct internal module in the registry.
|
|
19
|
+
*/
|
|
16
20
|
interface UpdatesInterface {
|
|
17
21
|
val configuration: UpdatesConfiguration
|
|
18
22
|
val selectionPolicy: SelectionPolicy
|
|
@@ -17,12 +17,26 @@ import expo.modules.updates.loader.FileDownloader.ManifestDownloadCallback
|
|
|
17
17
|
import expo.modules.updates.loader.Loader
|
|
18
18
|
import expo.modules.updates.loader.RemoteLoader
|
|
19
19
|
import expo.modules.updates.manifest.UpdateManifest
|
|
20
|
+
import expo.modules.updates.logging.UpdatesErrorCode
|
|
21
|
+
import expo.modules.updates.logging.UpdatesLogEntry
|
|
22
|
+
import expo.modules.updates.logging.UpdatesLogReader
|
|
23
|
+
import expo.modules.updates.logging.UpdatesLogger
|
|
24
|
+
import java.util.Date
|
|
20
25
|
|
|
21
26
|
// these unused imports must stay because of versioning
|
|
22
27
|
/* ktlint-disable no-unused-imports */
|
|
23
28
|
import expo.modules.updates.UpdatesConfiguration
|
|
24
29
|
/* ktlint-enable no-unused-imports */
|
|
25
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Exported module which provides to the JS runtime information about the currently running update
|
|
33
|
+
* and updates state, along with methods to check for and download new updates, reload with the
|
|
34
|
+
* newest downloaded update applied, and read/clear native log entries.
|
|
35
|
+
*
|
|
36
|
+
* Communicates with the updates hub ([UpdatesController] in most apps, [ExpoUpdatesAppLoader] in
|
|
37
|
+
* Expo Go and legacy standalone apps) via [UpdatesService], an internal module which is overridden
|
|
38
|
+
* by [UpdatesBinding], a scoped module, in Expo Go.
|
|
39
|
+
*/
|
|
26
40
|
class UpdatesModule(
|
|
27
41
|
context: Context,
|
|
28
42
|
private val moduleRegistryDelegate: ModuleRegistryDelegate = ModuleRegistryDelegate()
|
|
@@ -40,6 +54,7 @@ class UpdatesModule(
|
|
|
40
54
|
}
|
|
41
55
|
|
|
42
56
|
override fun getConstants(): Map<String, Any> {
|
|
57
|
+
UpdatesLogger(context).info("UpdatesModule: getConstants called", UpdatesErrorCode.None)
|
|
43
58
|
val constants = mutableMapOf<String, Any>()
|
|
44
59
|
try {
|
|
45
60
|
val updatesServiceLocal: UpdatesInterface? = updatesService
|
|
@@ -246,6 +261,55 @@ class UpdatesModule(
|
|
|
246
261
|
}
|
|
247
262
|
}
|
|
248
263
|
|
|
264
|
+
@ExpoMethod
|
|
265
|
+
fun readLogEntriesAsync(maxAge: Long, promise: Promise) {
|
|
266
|
+
AsyncTask.execute {
|
|
267
|
+
val reader = UpdatesLogReader(context)
|
|
268
|
+
val date = Date()
|
|
269
|
+
val epoch = Date(date.time - maxAge)
|
|
270
|
+
val results = reader.getLogEntries(epoch)
|
|
271
|
+
.mapNotNull { UpdatesLogEntry.create(it) }
|
|
272
|
+
.map { entry ->
|
|
273
|
+
Bundle().apply {
|
|
274
|
+
putLong("timestamp", entry.timestamp)
|
|
275
|
+
putString("message", entry.message)
|
|
276
|
+
putString("code", entry.code)
|
|
277
|
+
putString("level", entry.level)
|
|
278
|
+
if (entry.updateId != null) {
|
|
279
|
+
putString("updateId", entry.updateId)
|
|
280
|
+
}
|
|
281
|
+
if (entry.assetId != null) {
|
|
282
|
+
putString("assetId", entry.assetId)
|
|
283
|
+
}
|
|
284
|
+
if (entry.stacktrace != null) {
|
|
285
|
+
putStringArray("stacktrace", entry.stacktrace.toTypedArray())
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
promise.resolve(results)
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
@ExpoMethod
|
|
294
|
+
fun clearLogEntriesAsync(promise: Promise) {
|
|
295
|
+
AsyncTask.execute {
|
|
296
|
+
val reader = UpdatesLogReader(context)
|
|
297
|
+
reader.purgeLogEntries(
|
|
298
|
+
olderThan = Date()
|
|
299
|
+
) { error ->
|
|
300
|
+
if (error != null) {
|
|
301
|
+
promise.reject(
|
|
302
|
+
"ERR_UPDATES_READ_LOGS",
|
|
303
|
+
"There was an error when clearing the expo-updates log file",
|
|
304
|
+
error
|
|
305
|
+
)
|
|
306
|
+
} else {
|
|
307
|
+
promise.resolve(null)
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
249
313
|
companion object {
|
|
250
314
|
private const val NAME = "ExpoUpdates"
|
|
251
315
|
|
|
@@ -15,6 +15,10 @@ import expo.modules.core.interfaces.ReactNativeHostHandler
|
|
|
15
15
|
import expo.modules.updates.UpdatesController
|
|
16
16
|
/* ktlint-enable no-unused-imports */
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Defines the internal and exported modules for expo-updates, as well as the auto-setup behavior in
|
|
20
|
+
* applicable environments.
|
|
21
|
+
*/
|
|
18
22
|
class UpdatesPackage : Package {
|
|
19
23
|
override fun createInternalModules(context: Context): List<InternalModule> {
|
|
20
24
|
return listOf(UpdatesService(context) as InternalModule)
|
|
@@ -25,19 +29,20 @@ class UpdatesPackage : Package {
|
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
override fun createReactNativeHostHandlers(context: Context): List<ReactNativeHostHandler> {
|
|
32
|
+
val useNativeDebug = BuildConfig.EX_UPDATES_NATIVE_DEBUG
|
|
28
33
|
val handler: ReactNativeHostHandler = object : ReactNativeHostHandler {
|
|
29
34
|
private var mShouldAutoSetup: Boolean? = null
|
|
30
35
|
|
|
31
36
|
override fun getJSBundleFile(useDeveloperSupport: Boolean): String? {
|
|
32
|
-
return if (shouldAutoSetup(context) && !useDeveloperSupport) UpdatesController.instance.launchAssetFile else null
|
|
37
|
+
return if (shouldAutoSetup(context) && (useNativeDebug || !useDeveloperSupport)) UpdatesController.instance.launchAssetFile else null
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
override fun getBundleAssetName(useDeveloperSupport: Boolean): String? {
|
|
36
|
-
return if (shouldAutoSetup(context) && !useDeveloperSupport) UpdatesController.instance.bundleAssetName else null
|
|
41
|
+
return if (shouldAutoSetup(context) && (useNativeDebug || !useDeveloperSupport)) UpdatesController.instance.bundleAssetName else null
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
override fun onWillCreateReactInstanceManager(useDeveloperSupport: Boolean) {
|
|
40
|
-
if (shouldAutoSetup(context) && !useDeveloperSupport) {
|
|
45
|
+
if (shouldAutoSetup(context) && (useNativeDebug || !useDeveloperSupport)) {
|
|
41
46
|
UpdatesController.initialize(context)
|
|
42
47
|
}
|
|
43
48
|
}
|
|
@@ -45,7 +50,7 @@ class UpdatesPackage : Package {
|
|
|
45
50
|
override fun onDidCreateReactInstanceManager(reactInstanceManager: ReactInstanceManager, useDeveloperSupport: Boolean) {
|
|
46
51
|
// WHEN_VERSIONING_REMOVE_FROM_HERE
|
|
47
52
|
// This code path breaks versioning and is not necessary for Expo Go.
|
|
48
|
-
if (shouldAutoSetup(context) && !useDeveloperSupport) {
|
|
53
|
+
if (shouldAutoSetup(context) && (useNativeDebug || !useDeveloperSupport)) {
|
|
49
54
|
UpdatesController.instance.onDidCreateReactInstanceManager(reactInstanceManager)
|
|
50
55
|
}
|
|
51
56
|
// WHEN_VERSIONING_REMOVE_TO_HERE
|
|
@@ -7,6 +7,7 @@ import expo.modules.updates.db.entity.AssetEntity
|
|
|
7
7
|
import expo.modules.updates.db.entity.UpdateEntity
|
|
8
8
|
import expo.modules.updates.launcher.Launcher.LauncherCallback
|
|
9
9
|
import expo.modules.updates.loader.FileDownloader
|
|
10
|
+
import expo.modules.updates.manifest.EmbeddedManifest
|
|
10
11
|
import expo.modules.updates.selectionpolicy.SelectionPolicy
|
|
11
12
|
import java.io.File
|
|
12
13
|
|
|
@@ -14,10 +15,16 @@ import java.io.File
|
|
|
14
15
|
/* ktlint-disable no-unused-imports */
|
|
15
16
|
import expo.modules.updates.UpdatesConfiguration
|
|
16
17
|
import expo.modules.updates.UpdatesController
|
|
17
|
-
import expo.modules.updates.manifest.EmbeddedManifest
|
|
18
|
-
|
|
19
18
|
/* ktlint-enable no-unused-imports */
|
|
20
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Internal module whose purpose is to connect [UpdatesModule] with the central updates entry point.
|
|
22
|
+
* In most apps, this is [UpdatesController].
|
|
23
|
+
*
|
|
24
|
+
* In other cases, this module can be overridden at runtime to redirect [UpdatesModule] to a
|
|
25
|
+
* different entry point. This is the case in Expo Go, where this module is overridden by
|
|
26
|
+
* [UpdatesBinding] in order to get data from [ExpoUpdatesAppLoader].
|
|
27
|
+
*/
|
|
21
28
|
open class UpdatesService(protected var context: Context) : InternalModule, UpdatesInterface {
|
|
22
29
|
override fun getExportedInterfaces(): List<Class<*>> {
|
|
23
30
|
return listOf(UpdatesInterface::class.java as Class<*>)
|
|
@@ -29,6 +29,9 @@ import java.text.SimpleDateFormat
|
|
|
29
29
|
import java.util.*
|
|
30
30
|
import kotlin.experimental.and
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Miscellaneous helper functions that are used by multiple classes in the library.
|
|
34
|
+
*/
|
|
32
35
|
object UpdatesUtils {
|
|
33
36
|
private val TAG = UpdatesUtils::class.java.simpleName
|
|
34
37
|
|
|
@@ -2,6 +2,17 @@ package expo.modules.updates.db
|
|
|
2
2
|
|
|
3
3
|
import android.util.Log
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Wrapper class that provides a rudimentary locking mechanism for the database. This allows us to
|
|
7
|
+
* control what high-level operations involving the database can occur simultaneously. Most classes
|
|
8
|
+
* should access [UpdatesDatabase] through this class.
|
|
9
|
+
*
|
|
10
|
+
* Any process that calls `getDatabase` *must* manually release the lock by calling
|
|
11
|
+
* `releaseDatabase` in every possible case (success, error) as soon as it is finished.
|
|
12
|
+
*
|
|
13
|
+
* On iOS we use GCD queues as a more sophisticated way of achieving the same thing; we may also
|
|
14
|
+
* eventually want to migrate to a coroutine- or [Handler]-based system in lieu of this class.
|
|
15
|
+
*/
|
|
5
16
|
class DatabaseHolder(private val mDatabase: UpdatesDatabase) {
|
|
6
17
|
private var isInUse = false
|
|
7
18
|
|
|
@@ -8,6 +8,12 @@ import expo.modules.updates.manifest.ManifestMetadata
|
|
|
8
8
|
import expo.modules.updates.selectionpolicy.SelectionPolicy
|
|
9
9
|
import java.io.File
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Safely clears old, unused assets and updates from the filesystem and database.
|
|
13
|
+
*
|
|
14
|
+
* Should be run in a background process when no other updates-related events are occurring (e.g.
|
|
15
|
+
* update download).
|
|
16
|
+
*/
|
|
11
17
|
object Reaper {
|
|
12
18
|
private val TAG = Reaper::class.java.simpleName
|
|
13
19
|
|
|
@@ -16,6 +16,31 @@ import expo.modules.updates.db.entity.UpdateAssetEntity
|
|
|
16
16
|
import expo.modules.updates.db.entity.UpdateEntity
|
|
17
17
|
import java.util.*
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* SQLite database that keeps track of updates currently loaded/loading to disk, including the
|
|
21
|
+
* update manifest and metadata, status, and the individual assets (including bundles/bytecode) that
|
|
22
|
+
* comprise the update. (Assets themselves are stored on the device's file system, and a relative
|
|
23
|
+
* path is kept in SQLite.)
|
|
24
|
+
*
|
|
25
|
+
* SQLite allows a many-to-many relationship between updates and assets, which means we can keep
|
|
26
|
+
* only one copy of each asset on disk at a time while also being able to clear unused assets with
|
|
27
|
+
* relative ease (see [Reaper]).
|
|
28
|
+
*
|
|
29
|
+
* We use the Android Room library here, which provides a friendly abstraction over SQLite. The
|
|
30
|
+
* database schema is autogenerated from the `Entity` classes, and `DAO` classes provide access to
|
|
31
|
+
* the actual data.
|
|
32
|
+
*
|
|
33
|
+
* Occasionally it's necessary to add migrations when the data structures for updates or assets must
|
|
34
|
+
* change. Extra care must be taken here, since these migrations will happen on users' devices for
|
|
35
|
+
* apps we do not control. See
|
|
36
|
+
* https://github.com/expo/expo/blob/main/packages/expo-updates/guides/migrations.md for step by
|
|
37
|
+
* step instructions.
|
|
38
|
+
*
|
|
39
|
+
* [DatabaseHolder] provides a rudimentary locking mechanism, and most other classes access the
|
|
40
|
+
* database through this class. This allows control over what high-level operations involving the
|
|
41
|
+
* database can occur simultaneously - e.g. we don't want to be trying to download a new update at
|
|
42
|
+
* the same time the [Reaper] is running.
|
|
43
|
+
*/
|
|
19
44
|
@Database(
|
|
20
45
|
entities = [UpdateEntity::class, UpdateAssetEntity::class, AssetEntity::class, JSONDataEntity::class],
|
|
21
46
|
exportSchema = false,
|
|
@@ -6,6 +6,9 @@ import expo.modules.updates.db.entity.UpdateAssetEntity
|
|
|
6
6
|
import expo.modules.updates.db.entity.UpdateEntity
|
|
7
7
|
import java.util.*
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Utility class for accessing and modifying data in SQLite relating to assets.
|
|
11
|
+
*/
|
|
9
12
|
@Dao
|
|
10
13
|
abstract class AssetDao {
|
|
11
14
|
/**
|
|
@@ -6,6 +6,9 @@ import expo.modules.updates.db.entity.UpdateEntity
|
|
|
6
6
|
import expo.modules.updates.db.enums.UpdateStatus
|
|
7
7
|
import java.util.*
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Utility class for accessing and modifying data in SQLite relating to updates.
|
|
11
|
+
*/
|
|
9
12
|
@Dao
|
|
10
13
|
abstract class UpdateDao {
|
|
11
14
|
/**
|
|
@@ -6,6 +6,14 @@ import expo.modules.updates.db.enums.HashType
|
|
|
6
6
|
import org.json.JSONObject
|
|
7
7
|
import java.util.*
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Data class that represents a (potential) row in the `assets` table in SQLite. The table schema is
|
|
11
|
+
* autogenerated from this file.
|
|
12
|
+
*
|
|
13
|
+
* The `id` field here only has meaning within an individual SQLite instance, as a foreign key;
|
|
14
|
+
* unlike [UpdateEntity.id], it does *not* uniquely identify an asset across multiple installations
|
|
15
|
+
* of an app. [AssetEntity.hash] should be used in most places where a unique identifier is needed.
|
|
16
|
+
*/
|
|
9
17
|
@Entity(tableName = "assets", indices = [Index(value = ["key"], unique = true)])
|
|
10
18
|
class AssetEntity(@field:ColumnInfo(name = "key") var key: String?, var type: String?) {
|
|
11
19
|
@PrimaryKey(autoGenerate = true) // 0 is treated as unset while inserting the entity into the db
|
|
@@ -6,6 +6,16 @@ import androidx.room.Index
|
|
|
6
6
|
import androidx.room.PrimaryKey
|
|
7
7
|
import java.util.*
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Data class representing a (potential) row of arbitrary JSON data to be stored in the `json_data`
|
|
11
|
+
* table in SQLite. The table schema is autogenerated from this file.
|
|
12
|
+
*
|
|
13
|
+
* Used to store per-scope data that should be persisted and overridden via key, such as items in
|
|
14
|
+
* [ManifestMetadata].
|
|
15
|
+
*
|
|
16
|
+
* The `scopeKey` field is only relevant in environments such as Expo Go in which updates from
|
|
17
|
+
* multiple scopes can be launched.
|
|
18
|
+
*/
|
|
9
19
|
@Entity(tableName = "json_data", indices = [Index(value = ["scope_key"])])
|
|
10
20
|
class JSONDataEntity(
|
|
11
21
|
var key: String,
|
|
@@ -6,6 +6,13 @@ import androidx.room.ForeignKey
|
|
|
6
6
|
import androidx.room.Index
|
|
7
7
|
import java.util.*
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Data class that represents a (potential) row in the `updates_assets` table, the schema for which
|
|
11
|
+
* is autogenerated from this file.
|
|
12
|
+
*
|
|
13
|
+
* This entity exists only within the database framework, to represent the many-to-many relation
|
|
14
|
+
* between updates and assets. It should not be used by any other outside classes.
|
|
15
|
+
*/
|
|
9
16
|
@Entity(
|
|
10
17
|
tableName = "updates_assets",
|
|
11
18
|
primaryKeys = ["update_id", "asset_id"],
|
|
@@ -5,6 +5,18 @@ import expo.modules.updates.db.enums.UpdateStatus
|
|
|
5
5
|
import org.json.JSONObject
|
|
6
6
|
import java.util.*
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Data class that represents a (potential) row in the `updates` table in SQLite. The table schema
|
|
10
|
+
* is autogenerated from this file.
|
|
11
|
+
*
|
|
12
|
+
* expo-updates treats most fields (other than `status`, `keep`, `lastAccessed`, and the launch
|
|
13
|
+
* counts) as effectively immutable once in the database. This means an update server should never
|
|
14
|
+
* host two manifests with the same `id` that differ in any other field, as expo-updates will not
|
|
15
|
+
* take the difference into account.
|
|
16
|
+
*
|
|
17
|
+
* The `scopeKey` field is only relevant in environments such as Expo Go in which updates from
|
|
18
|
+
* multiple scopes can be launched.
|
|
19
|
+
*/
|
|
8
20
|
@Entity(
|
|
9
21
|
tableName = "updates",
|
|
10
22
|
foreignKeys = [
|
|
@@ -36,6 +48,11 @@ class UpdateEntity(
|
|
|
36
48
|
|
|
37
49
|
var keep = false
|
|
38
50
|
|
|
51
|
+
val loggingId: String
|
|
52
|
+
get() {
|
|
53
|
+
return id.toString().lowercase()
|
|
54
|
+
}
|
|
55
|
+
|
|
39
56
|
@ColumnInfo(name = "last_accessed")
|
|
40
57
|
var lastAccessed: Date = Date()
|
|
41
58
|
|