expo-updates 0.10.15 → 0.11.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 +27 -23
- package/android/build.gradle +9 -4
- package/android/src/main/java/expo/modules/updates/UpdatesConfiguration.kt +195 -0
- package/android/src/main/java/expo/modules/updates/UpdatesController.kt +367 -0
- package/android/src/main/java/expo/modules/updates/UpdatesDevLauncherController.kt +161 -0
- package/android/src/main/java/expo/modules/updates/UpdatesInterface.kt +31 -0
- package/android/src/main/java/expo/modules/updates/UpdatesModule.kt +246 -0
- package/android/src/main/java/expo/modules/updates/UpdatesPackage.kt +61 -0
- package/android/src/main/java/expo/modules/updates/UpdatesService.kt +54 -0
- package/android/src/main/java/expo/modules/updates/UpdatesUtils.kt +251 -0
- package/android/src/main/java/expo/modules/updates/db/BuildData.kt +104 -0
- package/android/src/main/java/expo/modules/updates/db/Converters.kt +107 -0
- package/android/src/main/java/expo/modules/updates/db/DatabaseHolder.kt +31 -0
- package/android/src/main/java/expo/modules/updates/db/DatabaseIntegrityCheck.kt +41 -0
- package/android/src/main/java/expo/modules/updates/db/Reaper.kt +82 -0
- package/android/src/main/java/expo/modules/updates/db/UpdatesDatabase.kt +165 -0
- package/android/src/main/java/expo/modules/updates/db/dao/AssetDao.kt +135 -0
- package/android/src/main/java/expo/modules/updates/db/dao/JSONDataDao.kt +51 -0
- package/android/src/main/java/expo/modules/updates/db/dao/UpdateDao.kt +106 -0
- package/android/src/main/java/expo/modules/updates/db/entity/AssetEntity.kt +51 -0
- package/android/src/main/java/expo/modules/updates/db/entity/JSONDataEntity.kt +18 -0
- package/android/src/main/java/expo/modules/updates/db/entity/UpdateAssetEntity.kt +30 -0
- package/android/src/main/java/expo/modules/updates/db/entity/UpdateEntity.kt +47 -0
- package/android/src/main/java/expo/modules/updates/db/enums/HashType.kt +5 -0
- package/android/src/main/java/expo/modules/updates/db/enums/{UpdateStatus.java → UpdateStatus.kt} +2 -2
- package/android/src/main/java/expo/modules/updates/launcher/DatabaseLauncher.kt +217 -0
- package/android/src/main/java/expo/modules/updates/launcher/Launcher.kt +17 -0
- package/android/src/main/java/expo/modules/updates/launcher/NoDatabaseLauncher.kt +81 -0
- package/android/src/main/java/expo/modules/updates/loader/Crypto.kt +107 -0
- package/android/src/main/java/expo/modules/updates/loader/EmbeddedLoader.kt +123 -0
- package/android/src/main/java/expo/modules/updates/loader/FileDownloader.kt +365 -0
- package/android/src/main/java/expo/modules/updates/loader/Loader.kt +305 -0
- package/android/src/main/java/expo/modules/updates/loader/LoaderFiles.kt +78 -0
- package/android/src/main/java/expo/modules/updates/loader/LoaderTask.kt +368 -0
- package/android/src/main/java/expo/modules/updates/loader/RemoteLoader.kt +61 -0
- package/android/src/main/java/expo/modules/updates/manifest/BareUpdateManifest.kt +4 -3
- package/android/src/main/java/expo/modules/updates/manifest/EmbeddedManifest.kt +36 -0
- package/android/src/main/java/expo/modules/updates/manifest/LegacyUpdateManifest.kt +3 -3
- package/android/src/main/java/expo/modules/updates/manifest/ManifestFactory.kt +1 -1
- package/android/src/main/java/expo/modules/updates/manifest/ManifestMetadata.kt +60 -0
- package/android/src/main/java/expo/modules/updates/manifest/ManifestResponse.kt +18 -0
- package/android/src/main/java/expo/modules/updates/manifest/NewUpdateManifest.kt +1 -1
- package/android/src/main/java/expo/modules/updates/manifest/UpdateManifest.kt +1 -1
- package/android/src/main/java/expo/modules/updates/selectionpolicy/LauncherSelectionPolicy.kt +11 -0
- package/android/src/main/java/expo/modules/updates/selectionpolicy/LauncherSelectionPolicyFilterAware.kt +29 -0
- package/android/src/main/java/expo/modules/updates/selectionpolicy/LauncherSelectionPolicySingleUpdate.kt +17 -0
- package/android/src/main/java/expo/modules/updates/selectionpolicy/LoaderSelectionPolicy.kt +17 -0
- package/android/src/main/java/expo/modules/updates/selectionpolicy/{LoaderSelectionPolicyFilterAware.java → LoaderSelectionPolicyFilterAware.kt} +15 -16
- package/android/src/main/java/expo/modules/updates/selectionpolicy/ReaperSelectionPolicy.kt +16 -0
- package/android/src/main/java/expo/modules/updates/selectionpolicy/ReaperSelectionPolicyDevelopmentClient.kt +57 -0
- package/android/src/main/java/expo/modules/updates/selectionpolicy/{ReaperSelectionPolicyFilterAware.java → ReaperSelectionPolicyFilterAware.kt} +24 -27
- package/android/src/main/java/expo/modules/updates/selectionpolicy/SelectionPolicies.kt +41 -0
- package/android/src/main/java/expo/modules/updates/selectionpolicy/SelectionPolicy.kt +30 -0
- package/android/src/main/java/expo/modules/updates/selectionpolicy/SelectionPolicyFactory.kt +19 -0
- package/build/ExpoUpdates.js +1 -1
- package/build/ExpoUpdates.js.map +1 -1
- package/build/Updates.d.ts +45 -37
- package/build/Updates.js +46 -49
- package/build/Updates.js.map +1 -1
- package/build/Updates.types.d.ts +20 -10
- package/build/Updates.types.js +4 -2
- package/build/Updates.types.js.map +1 -1
- package/expo-module.config.json +7 -0
- package/ios/EXUpdates/AppLauncher/EXUpdatesAppLauncher.h +2 -0
- package/ios/EXUpdates/AppLauncher/EXUpdatesAppLauncherNoDatabase.h +0 -2
- package/ios/EXUpdates/AppLauncher/EXUpdatesAppLauncherNoDatabase.m +0 -59
- package/ios/EXUpdates/AppLauncher/EXUpdatesAppLauncherWithDatabase.h +0 -1
- package/ios/EXUpdates/AppLoader/EXUpdatesAppLoaderTask.h +2 -0
- package/ios/EXUpdates/AppLoader/EXUpdatesAppLoaderTask.m +9 -1
- package/ios/EXUpdates/AppLoader/EXUpdatesFileDownloader.m +2 -2
- package/ios/EXUpdates/Database/EXUpdatesBuildData+Tests.h +14 -0
- package/ios/EXUpdates/Database/EXUpdatesBuildData.h +14 -0
- package/ios/EXUpdates/Database/EXUpdatesBuildData.m +102 -0
- package/ios/EXUpdates/Database/EXUpdatesDatabase.h +4 -0
- package/ios/EXUpdates/Database/EXUpdatesDatabase.m +36 -4
- package/ios/EXUpdates/Database/EXUpdatesDatabaseInitialization.m +3 -1
- package/ios/EXUpdates/Database/Migrations/EXUpdatesDatabaseMigration6To7.h +11 -0
- package/ios/EXUpdates/Database/Migrations/EXUpdatesDatabaseMigration6To7.m +64 -0
- package/ios/EXUpdates/Database/Migrations/EXUpdatesDatabaseMigrationRegistry.m +3 -2
- package/ios/EXUpdates/EXUpdates.h +5 -0
- package/ios/EXUpdates/EXUpdatesAppController.m +123 -19
- package/ios/EXUpdates/EXUpdatesConfig.h +2 -1
- package/ios/EXUpdates/EXUpdatesConfig.m +3 -0
- package/ios/EXUpdates/EXUpdatesErrorRecovery.h +52 -0
- package/ios/EXUpdates/EXUpdatesErrorRecovery.m +377 -0
- package/ios/EXUpdates/EXUpdatesUtils.h +0 -1
- package/ios/EXUpdates/EXUpdatesUtils.m +3 -21
- package/ios/EXUpdates/ReactDelegateHandler/DeferredRCTBridge.h +14 -0
- package/ios/EXUpdates/ReactDelegateHandler/DeferredRCTBridge.m +44 -0
- package/ios/EXUpdates/ReactDelegateHandler/DeferredRCTRootView.h +14 -0
- package/ios/EXUpdates/ReactDelegateHandler/DeferredRCTRootView.m +47 -0
- package/ios/EXUpdates/ReactDelegateHandler/ExpoUpdatesReactDelegateHandler.swift +109 -0
- package/ios/EXUpdates/Update/EXUpdatesUpdate.h +31 -3
- package/ios/EXUpdates/Update/EXUpdatesUpdate.m +2 -0
- package/ios/EXUpdates.podspec +5 -2
- package/ios/Tests/EXUpdatesBuildDataTests.m +263 -0
- package/ios/Tests/EXUpdatesDatabaseInitializationTests.m +163 -2
- package/ios/Tests/EXUpdatesDatabaseTests.m +1 -0
- package/ios/Tests/EXUpdatesErrorRecoveryTests.m +428 -0
- package/package.json +9 -7
- package/plugin/build/withUpdates.js +2 -2
- package/scripts/create-manifest-android.gradle +2 -2
- package/scripts/create-manifest-ios.sh +6 -3
- package/scripts/createManifest.js +7 -5
- package/scripts/source-login-scripts.sh +47 -0
- package/src/ExpoUpdates.ts +1 -1
- package/src/Updates.ts +47 -50
- package/src/Updates.types.ts +22 -15
- package/src/ts-declarations/lib.dom.d.ts +14 -0
- package/android/src/main/java/expo/modules/updates/UpdatesConfiguration.java +0 -249
- package/android/src/main/java/expo/modules/updates/UpdatesController.java +0 -398
- package/android/src/main/java/expo/modules/updates/UpdatesDevLauncherController.java +0 -150
- package/android/src/main/java/expo/modules/updates/UpdatesInterface.java +0 -32
- package/android/src/main/java/expo/modules/updates/UpdatesModule.java +0 -236
- package/android/src/main/java/expo/modules/updates/UpdatesPackage.java +0 -93
- package/android/src/main/java/expo/modules/updates/UpdatesService.java +0 -98
- package/android/src/main/java/expo/modules/updates/UpdatesUtils.java +0 -238
- package/android/src/main/java/expo/modules/updates/db/Converters.java +0 -137
- package/android/src/main/java/expo/modules/updates/db/DatabaseHolder.java +0 -33
- package/android/src/main/java/expo/modules/updates/db/DatabaseIntegrityCheck.java +0 -46
- package/android/src/main/java/expo/modules/updates/db/Reaper.java +0 -70
- package/android/src/main/java/expo/modules/updates/db/UpdatesDatabase.java +0 -129
- package/android/src/main/java/expo/modules/updates/db/dao/AssetDao.java +0 -144
- package/android/src/main/java/expo/modules/updates/db/dao/JSONDataDao.java +0 -58
- package/android/src/main/java/expo/modules/updates/db/dao/UpdateDao.java +0 -114
- package/android/src/main/java/expo/modules/updates/db/entity/AssetEntity.java +0 -74
- package/android/src/main/java/expo/modules/updates/db/entity/JSONDataEntity.java +0 -38
- package/android/src/main/java/expo/modules/updates/db/entity/UpdateAssetEntity.java +0 -38
- package/android/src/main/java/expo/modules/updates/db/entity/UpdateEntity.java +0 -69
- package/android/src/main/java/expo/modules/updates/db/enums/HashType.java +0 -5
- package/android/src/main/java/expo/modules/updates/launcher/DatabaseLauncher.java +0 -245
- package/android/src/main/java/expo/modules/updates/launcher/Launcher.java +0 -21
- package/android/src/main/java/expo/modules/updates/launcher/NoDatabaseLauncher.java +0 -104
- package/android/src/main/java/expo/modules/updates/loader/Crypto.java +0 -106
- package/android/src/main/java/expo/modules/updates/loader/EmbeddedLoader.java +0 -243
- package/android/src/main/java/expo/modules/updates/loader/FileDownloader.java +0 -335
- package/android/src/main/java/expo/modules/updates/loader/LoaderTask.java +0 -340
- package/android/src/main/java/expo/modules/updates/loader/RemoteLoader.java +0 -266
- package/android/src/main/java/expo/modules/updates/manifest/ManifestMetadata.java +0 -51
- package/android/src/main/java/expo/modules/updates/manifest/ManifestResponse.java +0 -27
- package/android/src/main/java/expo/modules/updates/selectionpolicy/LauncherSelectionPolicy.java +0 -14
- package/android/src/main/java/expo/modules/updates/selectionpolicy/LauncherSelectionPolicyFilterAware.java +0 -40
- package/android/src/main/java/expo/modules/updates/selectionpolicy/LauncherSelectionPolicySingleUpdate.java +0 -30
- package/android/src/main/java/expo/modules/updates/selectionpolicy/LoaderSelectionPolicy.java +0 -14
- package/android/src/main/java/expo/modules/updates/selectionpolicy/ReaperSelectionPolicy.java +0 -15
- package/android/src/main/java/expo/modules/updates/selectionpolicy/ReaperSelectionPolicyDevelopmentClient.java +0 -67
- package/android/src/main/java/expo/modules/updates/selectionpolicy/SelectionPolicies.java +0 -46
- package/android/src/main/java/expo/modules/updates/selectionpolicy/SelectionPolicy.java +0 -46
- package/android/src/main/java/expo/modules/updates/selectionpolicy/SelectionPolicyFactory.java +0 -22
- package/ios/EXUpdates/EXUpdatesAppDelegate.h +0 -14
- package/ios/EXUpdates/EXUpdatesAppDelegate.m +0 -169
- package/src/.gitkeep +0 -0
- package/unimodule.json +0 -4
package/CHANGELOG.md
CHANGED
|
@@ -10,39 +10,43 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
-
## 0.
|
|
13
|
+
## 0.11.0 — 2021-12-03
|
|
14
14
|
|
|
15
|
-
###
|
|
16
|
-
|
|
17
|
-
- Fix iOS auto-layout breaking for RCTRootView. on a iPad simulator, the view is not updated after rotation. ([#15100](https://github.com/expo/expo/pull/15100) by [@kudo](https://github.com/kudo))
|
|
18
|
-
|
|
19
|
-
## 0.10.14 — 2021-11-09
|
|
20
|
-
|
|
21
|
-
### 🐛 Bug fixes
|
|
22
|
-
|
|
23
|
-
- Retain embedded asset fields when merging existing asset entities on Android. ([#15123](https://github.com/expo/expo/pull/15123) by [@esamelson](https://github.com/esamelson))
|
|
24
|
-
|
|
25
|
-
## 0.10.13 — 2021-11-05
|
|
26
|
-
|
|
27
|
-
### 🐛 Bug fixes
|
|
28
|
-
|
|
29
|
-
- Fix issue with assets that are duplicated in the local SQLite db being reaped when they are still in use. ([#15049](https://github.com/expo/expo/pull/15049) by [@esamelson](https://github.com/esamelson))
|
|
30
|
-
|
|
31
|
-
## 0.10.12 — 2021-11-04
|
|
15
|
+
### 🛠 Breaking changes
|
|
32
16
|
|
|
33
|
-
|
|
17
|
+
- Add local SQLite fields for error recovery manager on iOS. ([#14610](https://github.com/expo/expo/pull/14610) by [@esamelson](https://github.com/esamelson))
|
|
18
|
+
- Add DB migration for above. ([#14718](https://github.com/expo/expo/pull/14718) by [@esamelson](https://github.com/esamelson))
|
|
19
|
+
- Add local SQLite fields and DB migration for error recovery manager on Android. ([#15218](https://github.com/expo/expo/pull/15218) by [@esamelson](https://github.com/esamelson))
|
|
20
|
+
- Add DEFAULT 0 to new error recovery DB columns. ([#15360](https://github.com/expo/expo/pull/15360) by [@esamelson](https://github.com/esamelson))
|
|
34
21
|
|
|
35
|
-
|
|
22
|
+
### 🎉 New features
|
|
36
23
|
|
|
37
|
-
|
|
24
|
+
- Add error recovery manager on iOS. ([#14397](https://github.com/expo/expo/pull/14397) by [@esamelson](https://github.com/esamelson))
|
|
25
|
+
- Hook up error recovery manager to rest of module on iOS. ([#14398](https://github.com/expo/expo/pull/14398) by [@esamelson](https://github.com/esamelson))
|
|
26
|
+
- Move persisted error log to EXUpdatesErrorRecovery on iOS. ([#14399](https://github.com/expo/expo/pull/14399) by [@esamelson](https://github.com/esamelson))
|
|
27
|
+
- Add native EXUpdatesCheckOnLaunch: ERROR_RECOVERY_ONLY setting on iOS. ([#14673](https://github.com/expo/expo/pull/14673) by [@esamelson](https://github.com/esamelson))
|
|
28
|
+
- Small fixes for error recovery manager on iOS. ([#15223](https://github.com/expo/expo/pull/15223) by [@esamelson](https://github.com/esamelson))
|
|
29
|
+
- Add native checkOnLaunch: ERROR_RECOVERY_ONLY setting on Android. ([#15219](https://github.com/expo/expo/pull/15219) by [@esamelson](https://github.com/esamelson))
|
|
30
|
+
- Enhance node binary resolution for Xcode build phases scripts by the vendoring source-login-scripts.sh. ([#15336](https://github.com/expo/expo/pull/15336) by [@kudo](https://github.com/kudo))
|
|
38
31
|
|
|
39
32
|
### 🐛 Bug fixes
|
|
40
33
|
|
|
34
|
+
- Fix auto setup `EXUpdatesAppDelegate` breaking reanimated installation. ([#14755](https://github.com/expo/expo/pull/14755) by [@kudo](https://github.com/kudo))
|
|
35
|
+
- Fix support for `react.entryFile` gradle config. ([#14934](https://github.com/expo/expo/pull/14934) by [@EvanBacon](https://github.com/EvanBacon))
|
|
36
|
+
- Fix Android app.manifest not generated when in OneSignal gradle plugin integration. ([#14938](https://github.com/expo/expo/pull/14938) by [@kudo](https://github.com/kudo))
|
|
37
|
+
- Fix Android app.manifest not generated from [#14938](https://github.com/expo/expo/pull/14938) regression. ([#14953](https://github.com/expo/expo/pull/14953) by [@kudo](https://github.com/kudo))
|
|
38
|
+
- Fix iOS app.manifest generation error in `eas build --local` mode. ([#14956](https://github.com/expo/expo/pull/14956) by [@kudo](https://github.com/kudo))
|
|
41
39
|
- Fix handling of unexpectedly missing assets on iOS. ([#15008](https://github.com/expo/expo/pull/15008) by [@esamelson](https://github.com/esamelson))
|
|
40
|
+
- Fix issue with assets that are duplicated in the local SQLite db being reaped when they are still in use. ([#15049](https://github.com/expo/expo/pull/15049) by [@esamelson](https://github.com/esamelson))
|
|
41
|
+
- Retain embedded asset fields when merging existing asset entities on Android. ([#15123](https://github.com/expo/expo/pull/15123) by [@esamelson](https://github.com/esamelson))
|
|
42
|
+
- Fix `RCTBridge` initialized twice on startup. ([#15142](https://github.com/expo/expo/pull/15142) by [@kudo](https://github.com/kudo))
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
### 💡 Others
|
|
44
45
|
|
|
45
|
-
|
|
46
|
+
- Add error when entryfile is not found in expo-updates scripts. ([#15234](https://github.com/expo/expo/pull/15234) by [@AamuLumi](https://github.com/AamuLumi))
|
|
47
|
+
- Update `@expo/config` and `@expo/metro-config` dependencies. ([#14801](https://github.com/expo/expo/pull/14801) by [@Simek](https://github.com/Simek))
|
|
48
|
+
- Refactor and unify Loader classes on Android. ([#14334](https://github.com/expo/expo/pull/14334) by [@esamelson](https://github.com/esamelson))
|
|
49
|
+
- Kotlinize expo-updates. ([#14818](https://github.com/expo/expo/pull/14334) by [@wschurman](https://github.com/wschurman))
|
|
46
50
|
|
|
47
51
|
## 0.10.9 — 2021-10-29
|
|
48
52
|
|
package/android/build.gradle
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
apply plugin: 'com.android.library'
|
|
2
2
|
apply plugin: 'kotlin-android'
|
|
3
|
+
apply plugin: 'kotlin-kapt'
|
|
3
4
|
apply plugin: 'maven'
|
|
4
5
|
|
|
5
6
|
group = 'host.exp.exponent'
|
|
6
|
-
version = '0.
|
|
7
|
+
version = '0.11.0'
|
|
7
8
|
|
|
8
9
|
apply from: "../scripts/create-manifest-android.gradle"
|
|
9
10
|
|
|
@@ -55,11 +56,15 @@ android {
|
|
|
55
56
|
targetCompatibility JavaVersion.VERSION_1_8
|
|
56
57
|
}
|
|
57
58
|
|
|
59
|
+
kotlinOptions {
|
|
60
|
+
jvmTarget = JavaVersion.VERSION_1_8
|
|
61
|
+
}
|
|
62
|
+
|
|
58
63
|
defaultConfig {
|
|
59
64
|
minSdkVersion safeExtGet("minSdkVersion", 21)
|
|
60
65
|
targetSdkVersion safeExtGet("targetSdkVersion", 30)
|
|
61
66
|
versionCode 31
|
|
62
|
-
versionName '0.
|
|
67
|
+
versionName '0.11.0'
|
|
63
68
|
consumerProguardFiles("proguard-rules.pro")
|
|
64
69
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
65
70
|
// uncomment below to export the database schema when making changes
|
|
@@ -90,10 +95,10 @@ dependencies {
|
|
|
90
95
|
//noinspection GradleDynamicVersion
|
|
91
96
|
implementation "com.facebook.react:react-native:+"
|
|
92
97
|
|
|
93
|
-
def room_version = "2.
|
|
98
|
+
def room_version = "2.3.0"
|
|
94
99
|
|
|
95
100
|
implementation "androidx.room:room-runtime:$room_version"
|
|
96
|
-
|
|
101
|
+
kapt "androidx.room:room-compiler:$room_version"
|
|
97
102
|
|
|
98
103
|
implementation("com.squareup.okhttp3:okhttp:3.12.1")
|
|
99
104
|
implementation("com.squareup.okhttp3:okhttp-urlconnection:3.12.1")
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
package expo.modules.updates
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.content.pm.PackageManager
|
|
5
|
+
import android.net.Uri
|
|
6
|
+
import android.util.Log
|
|
7
|
+
|
|
8
|
+
class UpdatesConfiguration {
|
|
9
|
+
enum class CheckAutomaticallyConfiguration {
|
|
10
|
+
NEVER, ERROR_RECOVERY_ONLY, WIFI_ONLY, ALWAYS
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
var isEnabled = false
|
|
14
|
+
private set
|
|
15
|
+
var expectsSignedManifest = false
|
|
16
|
+
private set
|
|
17
|
+
var scopeKey: String? = null
|
|
18
|
+
private set
|
|
19
|
+
var updateUrl: Uri? = null
|
|
20
|
+
private set
|
|
21
|
+
var sdkVersion: String? = null
|
|
22
|
+
private set
|
|
23
|
+
var runtimeVersion: String? = null
|
|
24
|
+
private set
|
|
25
|
+
var releaseChannel = UPDATES_CONFIGURATION_RELEASE_CHANNEL_DEFAULT_VALUE
|
|
26
|
+
private set
|
|
27
|
+
var launchWaitMs = UPDATES_CONFIGURATION_LAUNCH_WAIT_MS_DEFAULT_VALUE
|
|
28
|
+
private set
|
|
29
|
+
var checkOnLaunch = CheckAutomaticallyConfiguration.ALWAYS
|
|
30
|
+
private set
|
|
31
|
+
var hasEmbeddedUpdate = true
|
|
32
|
+
var requestHeaders = mapOf<String, String>()
|
|
33
|
+
private set
|
|
34
|
+
|
|
35
|
+
val isMissingRuntimeVersion: Boolean
|
|
36
|
+
get() = (runtimeVersion == null || runtimeVersion!!.isEmpty()) &&
|
|
37
|
+
(sdkVersion == null || sdkVersion!!.isEmpty())
|
|
38
|
+
|
|
39
|
+
fun loadValuesFromMetadata(context: Context): UpdatesConfiguration {
|
|
40
|
+
try {
|
|
41
|
+
val ai = context.packageManager.getApplicationInfo(context.packageName, PackageManager.GET_META_DATA)
|
|
42
|
+
updateUrl = ai.metaData.getString("expo.modules.updates.EXPO_UPDATE_URL")?.let { Uri.parse(it) }
|
|
43
|
+
scopeKey = ai.metaData.getString("expo.modules.updates.EXPO_SCOPE_KEY")
|
|
44
|
+
maybeSetDefaultScopeKey()
|
|
45
|
+
isEnabled = ai.metaData.getBoolean("expo.modules.updates.ENABLED", true)
|
|
46
|
+
sdkVersion = ai.metaData.getString("expo.modules.updates.EXPO_SDK_VERSION")
|
|
47
|
+
releaseChannel = ai.metaData.getString("expo.modules.updates.EXPO_RELEASE_CHANNEL", "default")
|
|
48
|
+
launchWaitMs = ai.metaData.getInt("expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS", 0)
|
|
49
|
+
runtimeVersion = ai.metaData["expo.modules.updates.EXPO_RUNTIME_VERSION"]?.toString()?.replaceFirst("^string:".toRegex(), "")
|
|
50
|
+
|
|
51
|
+
val checkOnLaunchString = ai.metaData.getString("expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH", "ALWAYS")
|
|
52
|
+
checkOnLaunch = try {
|
|
53
|
+
CheckAutomaticallyConfiguration.valueOf(checkOnLaunchString)
|
|
54
|
+
} catch (e: IllegalArgumentException) {
|
|
55
|
+
Log.e(
|
|
56
|
+
TAG,
|
|
57
|
+
"Invalid value $checkOnLaunchString for expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH in AndroidManifest; defaulting to ALWAYS"
|
|
58
|
+
)
|
|
59
|
+
CheckAutomaticallyConfiguration.ALWAYS
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
requestHeaders = UpdatesUtils.getHeadersMapFromJSONString(
|
|
63
|
+
ai.metaData.getString(
|
|
64
|
+
"expo.modules.updates.UPDATES_CONFIGURATION_REQUEST_HEADERS_KEY",
|
|
65
|
+
"{}"
|
|
66
|
+
)
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
// used only for expo-updates development
|
|
70
|
+
hasEmbeddedUpdate = ai.metaData.getBoolean("expo.modules.updates.HAS_EMBEDDED_UPDATE", true)
|
|
71
|
+
} catch (e: Exception) {
|
|
72
|
+
Log.e(TAG, "Could not read expo-updates configuration data in AndroidManifest", e)
|
|
73
|
+
}
|
|
74
|
+
return this
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
fun loadValuesFromMap(map: Map<String, Any>): UpdatesConfiguration {
|
|
78
|
+
val isEnabledFromMap = map.readValueCheckingType<Boolean>(UPDATES_CONFIGURATION_ENABLED_KEY)
|
|
79
|
+
if (isEnabledFromMap != null) {
|
|
80
|
+
isEnabled = isEnabledFromMap
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
expectsSignedManifest = map.readValueCheckingType("expectsSignedManifest") ?: false
|
|
84
|
+
|
|
85
|
+
val updateUrlFromMap = map.readValueCheckingType<Uri>(UPDATES_CONFIGURATION_UPDATE_URL_KEY)
|
|
86
|
+
if (updateUrlFromMap != null) {
|
|
87
|
+
updateUrl = updateUrlFromMap
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
val scopeKeyFromMap = map.readValueCheckingType<String>(UPDATES_CONFIGURATION_SCOPE_KEY_KEY)
|
|
91
|
+
if (scopeKeyFromMap != null) {
|
|
92
|
+
scopeKey = scopeKeyFromMap
|
|
93
|
+
}
|
|
94
|
+
maybeSetDefaultScopeKey()
|
|
95
|
+
|
|
96
|
+
val requestHeadersFromMap = map.readValueCheckingType<Map<String, String>>(UPDATES_CONFIGURATION_REQUEST_HEADERS_KEY)
|
|
97
|
+
if (requestHeadersFromMap != null) {
|
|
98
|
+
requestHeaders = requestHeadersFromMap
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
val releaseChannelFromMap = map.readValueCheckingType<String>(UPDATES_CONFIGURATION_RELEASE_CHANNEL_KEY)
|
|
102
|
+
if (releaseChannelFromMap != null) {
|
|
103
|
+
releaseChannel = releaseChannelFromMap
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
val sdkVersionFromMap = map.readValueCheckingType<String>(UPDATES_CONFIGURATION_SDK_VERSION_KEY)
|
|
107
|
+
if (sdkVersionFromMap != null) {
|
|
108
|
+
sdkVersion = sdkVersionFromMap
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
val runtimeVersionFromMap = map.readValueCheckingType<String>(UPDATES_CONFIGURATION_RUNTIME_VERSION_KEY)
|
|
112
|
+
if (runtimeVersionFromMap != null) {
|
|
113
|
+
runtimeVersion = runtimeVersionFromMap
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
val checkOnLaunchFromMap = map.readValueCheckingType<String>(UPDATES_CONFIGURATION_CHECK_ON_LAUNCH_KEY)
|
|
117
|
+
if (checkOnLaunchFromMap != null) {
|
|
118
|
+
try {
|
|
119
|
+
checkOnLaunch = CheckAutomaticallyConfiguration.valueOf(checkOnLaunchFromMap)
|
|
120
|
+
} catch (e: IllegalArgumentException) {
|
|
121
|
+
throw AssertionError("UpdatesConfiguration failed to initialize: invalid value $checkOnLaunchFromMap provided for checkOnLaunch")
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
val launchWaitMsFromMap = map.readValueCheckingType<Int>(UPDATES_CONFIGURATION_LAUNCH_WAIT_MS_KEY)
|
|
126
|
+
if (launchWaitMsFromMap != null) {
|
|
127
|
+
launchWaitMs = launchWaitMsFromMap
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
val hasEmbeddedUpdateFromMap = map.readValueCheckingType<Boolean>(UPDATES_CONFIGURATION_HAS_EMBEDDED_UPDATE_KEY)
|
|
131
|
+
if (hasEmbeddedUpdateFromMap != null) {
|
|
132
|
+
hasEmbeddedUpdate = hasEmbeddedUpdateFromMap
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return this
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private inline fun <reified T : Any> Map<String, Any>.readValueCheckingType(key: String): T? {
|
|
139
|
+
if (!containsKey(key)) {
|
|
140
|
+
return null
|
|
141
|
+
}
|
|
142
|
+
val value = this[key]
|
|
143
|
+
return if (value is T) {
|
|
144
|
+
value
|
|
145
|
+
} else {
|
|
146
|
+
throw AssertionError("UpdatesConfiguration failed to initialize: bad value of type " + value!!.javaClass.simpleName + " provided for key " + key)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private fun maybeSetDefaultScopeKey() {
|
|
151
|
+
// set updateUrl as the default value if none is provided
|
|
152
|
+
if (scopeKey == null) {
|
|
153
|
+
if (updateUrl != null) {
|
|
154
|
+
scopeKey = getNormalizedUrlOrigin(updateUrl!!)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
companion object {
|
|
160
|
+
private val TAG = UpdatesConfiguration::class.java.simpleName
|
|
161
|
+
|
|
162
|
+
const val UPDATES_CONFIGURATION_ENABLED_KEY = "enabled"
|
|
163
|
+
const val UPDATES_CONFIGURATION_SCOPE_KEY_KEY = "scopeKey"
|
|
164
|
+
const val UPDATES_CONFIGURATION_UPDATE_URL_KEY = "updateUrl"
|
|
165
|
+
const val UPDATES_CONFIGURATION_REQUEST_HEADERS_KEY = "requestHeaders"
|
|
166
|
+
const val UPDATES_CONFIGURATION_RELEASE_CHANNEL_KEY = "releaseChannel"
|
|
167
|
+
const val UPDATES_CONFIGURATION_SDK_VERSION_KEY = "sdkVersion"
|
|
168
|
+
const val UPDATES_CONFIGURATION_RUNTIME_VERSION_KEY = "runtimeVersion"
|
|
169
|
+
const val UPDATES_CONFIGURATION_CHECK_ON_LAUNCH_KEY = "checkOnLaunch"
|
|
170
|
+
const val UPDATES_CONFIGURATION_LAUNCH_WAIT_MS_KEY = "launchWaitMs"
|
|
171
|
+
const val UPDATES_CONFIGURATION_HAS_EMBEDDED_UPDATE_KEY = "hasEmbeddedUpdate"
|
|
172
|
+
private const val UPDATES_CONFIGURATION_RELEASE_CHANNEL_DEFAULT_VALUE = "default"
|
|
173
|
+
private const val UPDATES_CONFIGURATION_LAUNCH_WAIT_MS_DEFAULT_VALUE = 0
|
|
174
|
+
|
|
175
|
+
internal fun getNormalizedUrlOrigin(url: Uri): String {
|
|
176
|
+
val scheme = url.scheme
|
|
177
|
+
var port = url.port
|
|
178
|
+
if (port == getDefaultPortForScheme(scheme)) {
|
|
179
|
+
port = -1
|
|
180
|
+
}
|
|
181
|
+
return if (port > -1) "$scheme://${url.host}:$port" else "$scheme://${url.host}"
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private fun getDefaultPortForScheme(scheme: String?): Int {
|
|
185
|
+
if ("http" == scheme || "ws" == scheme) {
|
|
186
|
+
return 80
|
|
187
|
+
} else if ("https" == scheme || "wss" == scheme) {
|
|
188
|
+
return 443
|
|
189
|
+
} else if ("ftp" == scheme) {
|
|
190
|
+
return 21
|
|
191
|
+
}
|
|
192
|
+
return -1
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
package expo.modules.updates
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.net.Uri
|
|
5
|
+
import android.os.AsyncTask
|
|
6
|
+
import android.os.Handler
|
|
7
|
+
import android.os.Looper
|
|
8
|
+
import android.util.Log
|
|
9
|
+
import com.facebook.react.ReactApplication
|
|
10
|
+
import com.facebook.react.ReactNativeHost
|
|
11
|
+
import com.facebook.react.bridge.Arguments
|
|
12
|
+
import com.facebook.react.bridge.JSBundleLoader
|
|
13
|
+
import expo.modules.updates.db.BuildData
|
|
14
|
+
import expo.modules.updates.db.DatabaseHolder
|
|
15
|
+
import expo.modules.updates.db.Reaper
|
|
16
|
+
import expo.modules.updates.db.UpdatesDatabase
|
|
17
|
+
import expo.modules.updates.db.entity.AssetEntity
|
|
18
|
+
import expo.modules.updates.db.entity.UpdateEntity
|
|
19
|
+
import expo.modules.updates.launcher.DatabaseLauncher
|
|
20
|
+
import expo.modules.updates.launcher.Launcher
|
|
21
|
+
import expo.modules.updates.launcher.Launcher.LauncherCallback
|
|
22
|
+
import expo.modules.updates.launcher.NoDatabaseLauncher
|
|
23
|
+
import expo.modules.updates.loader.FileDownloader
|
|
24
|
+
import expo.modules.updates.loader.LoaderTask
|
|
25
|
+
import expo.modules.updates.loader.LoaderTask.BackgroundUpdateStatus
|
|
26
|
+
import expo.modules.updates.loader.LoaderTask.LoaderTaskCallback
|
|
27
|
+
import expo.modules.updates.manifest.UpdateManifest
|
|
28
|
+
import expo.modules.updates.selectionpolicy.SelectionPolicy
|
|
29
|
+
import expo.modules.updates.selectionpolicy.SelectionPolicyFactory
|
|
30
|
+
import java.io.File
|
|
31
|
+
import java.lang.ref.WeakReference
|
|
32
|
+
|
|
33
|
+
class UpdatesController private constructor(
|
|
34
|
+
context: Context,
|
|
35
|
+
var updatesConfiguration: UpdatesConfiguration
|
|
36
|
+
) {
|
|
37
|
+
private var reactNativeHost: WeakReference<ReactNativeHost>? = if (context is ReactApplication) {
|
|
38
|
+
WeakReference((context as ReactApplication).reactNativeHost)
|
|
39
|
+
} else {
|
|
40
|
+
null
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
var updatesDirectory: File? = null
|
|
44
|
+
var updatesDirectoryException: Exception? = null
|
|
45
|
+
|
|
46
|
+
private var launcher: Launcher? = null
|
|
47
|
+
val databaseHolder = DatabaseHolder(UpdatesDatabase.getInstance(context))
|
|
48
|
+
|
|
49
|
+
private var mSelectionPolicy: SelectionPolicy? = null
|
|
50
|
+
private var defaultSelectionPolicy: SelectionPolicy = SelectionPolicyFactory.createFilterAwarePolicy(
|
|
51
|
+
UpdatesUtils.getRuntimeVersion(updatesConfiguration)
|
|
52
|
+
)
|
|
53
|
+
val fileDownloader: FileDownloader = FileDownloader(context)
|
|
54
|
+
|
|
55
|
+
// launch conditions
|
|
56
|
+
private var isLoaderTaskFinished = false
|
|
57
|
+
var isEmergencyLaunch = false
|
|
58
|
+
private set
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* If UpdatesController.initialize() is not provided with a [ReactApplication], this method
|
|
62
|
+
* can be used to set a [ReactNativeHost] on the class. This is optional, but required in
|
|
63
|
+
* order for `Updates.reload()` and some Updates module events to work.
|
|
64
|
+
* @param reactNativeHost the ReactNativeHost of the application running the Updates module
|
|
65
|
+
*/
|
|
66
|
+
fun setReactNativeHost(reactNativeHost: ReactNativeHost) {
|
|
67
|
+
this.reactNativeHost = WeakReference(reactNativeHost)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Returns the path on disk to the launch asset (JS bundle) file for the React Native host to use.
|
|
72
|
+
* Blocks until the configured timeout runs out, or a new update has been downloaded and is ready
|
|
73
|
+
* to use (whichever comes sooner). ReactNativeHost.getJSBundleFile() should call into this.
|
|
74
|
+
*
|
|
75
|
+
* If this returns null, something has gone wrong and expo-updates has not been able to launch or
|
|
76
|
+
* find an update to use. In (and only in) this case, `getBundleAssetName()` will return a nonnull
|
|
77
|
+
* fallback value to use.
|
|
78
|
+
*/
|
|
79
|
+
@get:Synchronized
|
|
80
|
+
val launchAssetFile: String?
|
|
81
|
+
get() {
|
|
82
|
+
while (!isLoaderTaskFinished) {
|
|
83
|
+
try {
|
|
84
|
+
(this as java.lang.Object).wait()
|
|
85
|
+
} catch (e: InterruptedException) {
|
|
86
|
+
Log.e(TAG, "Interrupted while waiting for launch asset file", e)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return launcher?.launchAssetFile
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Returns the filename of the launch asset (JS bundle) file embedded in the APK bundle, which can
|
|
94
|
+
* be read using `context.getAssets()`. This is only nonnull if `getLaunchAssetFile` is null and
|
|
95
|
+
* should only be used in such a situation. ReactNativeHost.getBundleAssetName() should call into
|
|
96
|
+
* this.
|
|
97
|
+
*/
|
|
98
|
+
val bundleAssetName: String?
|
|
99
|
+
get() = launcher?.bundleAssetName
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Returns a map of the locally downloaded assets for the current update. Keys are the remote URLs
|
|
103
|
+
* of the assets and values are local paths. This should be exported by the Updates JS module and
|
|
104
|
+
* can be used by `expo-asset` or a similar module to override React Native's asset resolution and
|
|
105
|
+
* use the locally downloaded assets.
|
|
106
|
+
*/
|
|
107
|
+
val localAssetFiles: Map<AssetEntity, String>?
|
|
108
|
+
get() = launcher?.localAssetFiles
|
|
109
|
+
|
|
110
|
+
val isUsingEmbeddedAssets: Boolean
|
|
111
|
+
get() = launcher?.isUsingEmbeddedAssets ?: false
|
|
112
|
+
|
|
113
|
+
val database: UpdatesDatabase
|
|
114
|
+
get() = databaseHolder.database
|
|
115
|
+
|
|
116
|
+
fun releaseDatabase() {
|
|
117
|
+
databaseHolder.releaseDatabase()
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
val updateUrl: Uri?
|
|
121
|
+
get() = updatesConfiguration.updateUrl
|
|
122
|
+
|
|
123
|
+
val launchedUpdate: UpdateEntity?
|
|
124
|
+
get() = launcher?.launchedUpdate
|
|
125
|
+
|
|
126
|
+
val selectionPolicy: SelectionPolicy
|
|
127
|
+
get() = mSelectionPolicy ?: defaultSelectionPolicy
|
|
128
|
+
|
|
129
|
+
// Internal Setters
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* For external modules that want to modify the selection policy used at runtime.
|
|
133
|
+
*
|
|
134
|
+
* This method does not provide any guarantees about how long the provided selection policy will
|
|
135
|
+
* persist; sometimes expo-updates will reset the selection policy in situations where it makes
|
|
136
|
+
* sense to have explicit control (e.g. if the developer/user has programmatically fetched an
|
|
137
|
+
* update, expo-updates will reset the selection policy so the new update is launched on th
|
|
138
|
+
* next reload).
|
|
139
|
+
* @param selectionPolicy The SelectionPolicy to use next, until overridden by expo-updates
|
|
140
|
+
*/
|
|
141
|
+
fun setNextSelectionPolicy(selectionPolicy: SelectionPolicy?) {
|
|
142
|
+
mSelectionPolicy = selectionPolicy
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
fun resetSelectionPolicyToDefault() {
|
|
146
|
+
mSelectionPolicy = null
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
fun setDefaultSelectionPolicy(selectionPolicy: SelectionPolicy) {
|
|
150
|
+
defaultSelectionPolicy = selectionPolicy
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
fun setLauncher(launcher: Launcher?) {
|
|
154
|
+
this.launcher = launcher
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Starts the update process to launch a previously-loaded update and (if configured to do so)
|
|
159
|
+
* check for a new update from the server. This method should be called as early as possible in
|
|
160
|
+
* the application's lifecycle.
|
|
161
|
+
* @param context the base context of the application, ideally a [ReactApplication]
|
|
162
|
+
*/
|
|
163
|
+
@Synchronized
|
|
164
|
+
fun start(context: Context) {
|
|
165
|
+
if (!updatesConfiguration.isEnabled) {
|
|
166
|
+
launcher = NoDatabaseLauncher(context, updatesConfiguration)
|
|
167
|
+
}
|
|
168
|
+
if (updatesConfiguration.updateUrl == null || updatesConfiguration.scopeKey == null) {
|
|
169
|
+
throw AssertionError("expo-updates is enabled, but no valid URL is configured in AndroidManifest.xml. If you are making a release build for the first time, make sure you have run `expo publish` at least once.")
|
|
170
|
+
}
|
|
171
|
+
if (updatesDirectory == null) {
|
|
172
|
+
launcher = NoDatabaseLauncher(context, updatesConfiguration, updatesDirectoryException)
|
|
173
|
+
isEmergencyLaunch = true
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
val databaseLocal = database
|
|
177
|
+
BuildData.ensureBuildDataIsConsistent(updatesConfiguration, databaseLocal)
|
|
178
|
+
releaseDatabase()
|
|
179
|
+
|
|
180
|
+
LoaderTask(
|
|
181
|
+
updatesConfiguration,
|
|
182
|
+
databaseHolder,
|
|
183
|
+
updatesDirectory,
|
|
184
|
+
fileDownloader,
|
|
185
|
+
selectionPolicy,
|
|
186
|
+
object : LoaderTaskCallback {
|
|
187
|
+
override fun onFailure(e: Exception) {
|
|
188
|
+
launcher = NoDatabaseLauncher(context, updatesConfiguration, e)
|
|
189
|
+
isEmergencyLaunch = true
|
|
190
|
+
notifyController()
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
override fun onCachedUpdateLoaded(update: UpdateEntity): Boolean {
|
|
194
|
+
return true
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
override fun onRemoteUpdateManifestLoaded(updateManifest: UpdateManifest) {}
|
|
198
|
+
override fun onSuccess(launcher: Launcher, isUpToDate: Boolean) {
|
|
199
|
+
this@UpdatesController.launcher = launcher
|
|
200
|
+
notifyController()
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
override fun onBackgroundUpdateFinished(
|
|
204
|
+
status: BackgroundUpdateStatus,
|
|
205
|
+
update: UpdateEntity?,
|
|
206
|
+
exception: Exception?
|
|
207
|
+
) {
|
|
208
|
+
when (status) {
|
|
209
|
+
BackgroundUpdateStatus.ERROR -> {
|
|
210
|
+
if (exception == null) {
|
|
211
|
+
throw AssertionError("Background update with error status must have a nonnull exception object")
|
|
212
|
+
}
|
|
213
|
+
val params = Arguments.createMap()
|
|
214
|
+
params.putString("message", exception.message)
|
|
215
|
+
UpdatesUtils.sendEventToReactNative(reactNativeHost, UPDATE_ERROR_EVENT, params)
|
|
216
|
+
}
|
|
217
|
+
BackgroundUpdateStatus.UPDATE_AVAILABLE -> {
|
|
218
|
+
if (update == null) {
|
|
219
|
+
throw AssertionError("Background update with error status must have a nonnull update object")
|
|
220
|
+
}
|
|
221
|
+
val params = Arguments.createMap()
|
|
222
|
+
params.putString("manifestString", update.manifest.toString())
|
|
223
|
+
UpdatesUtils.sendEventToReactNative(reactNativeHost, UPDATE_AVAILABLE_EVENT, params)
|
|
224
|
+
}
|
|
225
|
+
BackgroundUpdateStatus.NO_UPDATE_AVAILABLE -> {
|
|
226
|
+
UpdatesUtils.sendEventToReactNative(
|
|
227
|
+
reactNativeHost,
|
|
228
|
+
UPDATE_NO_UPDATE_AVAILABLE_EVENT,
|
|
229
|
+
null
|
|
230
|
+
)
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
).start(context)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
@Synchronized
|
|
239
|
+
private fun notifyController() {
|
|
240
|
+
isLoaderTaskFinished = true
|
|
241
|
+
(this as java.lang.Object).notify()
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
fun runReaper() {
|
|
245
|
+
AsyncTask.execute {
|
|
246
|
+
val databaseLocal = database
|
|
247
|
+
Reaper.reapUnusedUpdates(
|
|
248
|
+
updatesConfiguration,
|
|
249
|
+
databaseLocal,
|
|
250
|
+
updatesDirectory,
|
|
251
|
+
launchedUpdate,
|
|
252
|
+
selectionPolicy
|
|
253
|
+
)
|
|
254
|
+
releaseDatabase()
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
fun relaunchReactApplication(context: Context, callback: LauncherCallback) {
|
|
259
|
+
val host = reactNativeHost?.get()
|
|
260
|
+
if (host == null) {
|
|
261
|
+
callback.onFailure(Exception("Could not reload application. Ensure you have passed the correct instance of ReactApplication into UpdatesController.initialize()."))
|
|
262
|
+
return
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
val oldLaunchAssetFile = launcher!!.launchAssetFile
|
|
266
|
+
|
|
267
|
+
val databaseLocal = database
|
|
268
|
+
val newLauncher = DatabaseLauncher(
|
|
269
|
+
updatesConfiguration,
|
|
270
|
+
updatesDirectory!!,
|
|
271
|
+
fileDownloader,
|
|
272
|
+
selectionPolicy
|
|
273
|
+
)
|
|
274
|
+
newLauncher.launch(
|
|
275
|
+
databaseLocal, context,
|
|
276
|
+
object : LauncherCallback {
|
|
277
|
+
override fun onFailure(e: Exception) {
|
|
278
|
+
callback.onFailure(e)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
override fun onSuccess() {
|
|
282
|
+
launcher = newLauncher
|
|
283
|
+
releaseDatabase()
|
|
284
|
+
|
|
285
|
+
val instanceManager = host.reactInstanceManager
|
|
286
|
+
|
|
287
|
+
val newLaunchAssetFile = launcher!!.launchAssetFile
|
|
288
|
+
if (newLaunchAssetFile != null && newLaunchAssetFile != oldLaunchAssetFile) {
|
|
289
|
+
// Unfortunately, even though RN exposes a way to reload an application,
|
|
290
|
+
// it assumes that the JS bundle will stay at the same location throughout
|
|
291
|
+
// the entire lifecycle of the app. Since we need to change the location of
|
|
292
|
+
// the bundle, we need to use reflection to set an otherwise inaccessible
|
|
293
|
+
// field of the ReactInstanceManager.
|
|
294
|
+
try {
|
|
295
|
+
val newJSBundleLoader = JSBundleLoader.createFileLoader(newLaunchAssetFile)
|
|
296
|
+
val jsBundleLoaderField = instanceManager.javaClass.getDeclaredField("mBundleLoader")
|
|
297
|
+
jsBundleLoaderField.isAccessible = true
|
|
298
|
+
jsBundleLoaderField[instanceManager] = newJSBundleLoader
|
|
299
|
+
} catch (e: Exception) {
|
|
300
|
+
Log.e(TAG, "Could not reset JSBundleLoader in ReactInstanceManager", e)
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
callback.onSuccess()
|
|
304
|
+
val handler = Handler(Looper.getMainLooper())
|
|
305
|
+
handler.post { instanceManager.recreateReactContextInBackground() }
|
|
306
|
+
runReaper()
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
companion object {
|
|
313
|
+
private val TAG = UpdatesController::class.java.simpleName
|
|
314
|
+
|
|
315
|
+
private const val UPDATE_AVAILABLE_EVENT = "updateAvailable"
|
|
316
|
+
private const val UPDATE_NO_UPDATE_AVAILABLE_EVENT = "noUpdateAvailable"
|
|
317
|
+
private const val UPDATE_ERROR_EVENT = "error"
|
|
318
|
+
|
|
319
|
+
private var singletonInstance: UpdatesController? = null
|
|
320
|
+
@JvmStatic val instance: UpdatesController
|
|
321
|
+
get() {
|
|
322
|
+
return checkNotNull(singletonInstance) { "UpdatesController.instance was called before the module was initialized" }
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
@JvmStatic fun initializeWithoutStarting(context: Context) {
|
|
326
|
+
if (singletonInstance == null) {
|
|
327
|
+
val updatesConfiguration = UpdatesConfiguration().loadValuesFromMetadata(context)
|
|
328
|
+
singletonInstance = UpdatesController(context, updatesConfiguration)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Initializes the UpdatesController singleton. This should be called as early as possible in the
|
|
334
|
+
* application's lifecycle.
|
|
335
|
+
* @param context the base context of the application, ideally a [ReactApplication]
|
|
336
|
+
*/
|
|
337
|
+
@JvmStatic fun initialize(context: Context) {
|
|
338
|
+
initializeWithoutStarting(context)
|
|
339
|
+
singletonInstance!!.start(context)
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Initializes the UpdatesController singleton. This should be called as early as possible in the
|
|
344
|
+
* application's lifecycle. Use this method to set or override configuration values at runtime
|
|
345
|
+
* rather than from AndroidManifest.xml.
|
|
346
|
+
* @param context the base context of the application, ideally a [ReactApplication]
|
|
347
|
+
*/
|
|
348
|
+
@JvmStatic fun initialize(context: Context, configuration: Map<String, Any>) {
|
|
349
|
+
if (singletonInstance == null) {
|
|
350
|
+
val updatesConfiguration = UpdatesConfiguration()
|
|
351
|
+
.loadValuesFromMetadata(context)
|
|
352
|
+
.loadValuesFromMap(configuration)
|
|
353
|
+
singletonInstance = UpdatesController(context, updatesConfiguration)
|
|
354
|
+
singletonInstance!!.start(context)
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
init {
|
|
360
|
+
try {
|
|
361
|
+
updatesDirectory = UpdatesUtils.getOrCreateUpdatesDirectory(context)
|
|
362
|
+
} catch (e: Exception) {
|
|
363
|
+
updatesDirectoryException = e
|
|
364
|
+
updatesDirectory = null
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|