expo-updates 0.27.3 → 0.28.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.
Files changed (110) hide show
  1. package/CHANGELOG.md +51 -18
  2. package/android/build.gradle +39 -17
  3. package/android/src/main/java/expo/modules/updates/DisabledUpdatesController.kt +1 -1
  4. package/android/src/main/java/expo/modules/updates/EnabledUpdatesController.kt +8 -5
  5. package/android/src/main/java/expo/modules/updates/IUpdatesController.kt +1 -1
  6. package/android/src/main/java/expo/modules/updates/UpdatesController.kt +128 -118
  7. package/android/src/main/java/expo/modules/updates/UpdatesDevLauncherController.kt +6 -3
  8. package/android/src/main/java/expo/modules/updates/UpdatesModule.kt +34 -14
  9. package/android/src/main/java/expo/modules/updates/UpdatesPackage.kt +9 -6
  10. package/android/src/main/java/expo/modules/updates/errorrecovery/ErrorRecovery.kt +7 -9
  11. package/android/src/main/java/expo/modules/updates/launcher/NoDatabaseLauncher.kt +6 -3
  12. package/android/src/main/java/expo/modules/updates/loader/FileDownloader.kt +24 -23
  13. package/android/src/main/java/expo/modules/updates/loader/LoaderTask.kt +18 -16
  14. package/android/src/main/java/expo/modules/updates/logging/UpdatesLogReader.kt +3 -3
  15. package/android/src/main/java/expo/modules/updates/logging/UpdatesLogger.kt +8 -4
  16. package/android/src/main/java/expo/modules/updates/procedures/CheckForUpdateProcedure.kt +119 -121
  17. package/android/src/main/java/expo/modules/updates/procedures/FetchUpdateProcedure.kt +71 -74
  18. package/android/src/main/java/expo/modules/updates/procedures/RecreateReactContextProcedure.kt +2 -2
  19. package/android/src/main/java/expo/modules/updates/procedures/RelaunchProcedure.kt +10 -13
  20. package/android/src/main/java/expo/modules/updates/procedures/StartupProcedure.kt +5 -2
  21. package/android/src/main/java/expo/modules/updates/procedures/StateMachineProcedure.kt +4 -3
  22. package/android/src/main/java/expo/modules/updates/procedures/StateMachineSerialExecutorQueue.kt +57 -56
  23. package/android/src/main/java/expo/modules/updates/statemachine/UpdatesStateContext.kt +19 -2
  24. package/android/src/main/java/expo/modules/updates/statemachine/UpdatesStateEvent.kt +9 -7
  25. package/android/src/main/java/expo/modules/updates/statemachine/UpdatesStateEventType.kt +2 -0
  26. package/android/src/main/java/expo/modules/updates/statemachine/UpdatesStateMachine.kt +13 -5
  27. package/build/ExpoUpdates.web.d.ts.map +1 -1
  28. package/build/ExpoUpdates.web.js +2 -0
  29. package/build/ExpoUpdates.web.js.map +1 -1
  30. package/build/Updates.types.d.ts +2 -8
  31. package/build/Updates.types.d.ts.map +1 -1
  32. package/build/Updates.types.js.map +1 -1
  33. package/build/UpdatesEmitter.d.ts +5 -1
  34. package/build/UpdatesEmitter.d.ts.map +1 -1
  35. package/build/UpdatesEmitter.js +8 -4
  36. package/build/UpdatesEmitter.js.map +1 -1
  37. package/build/UseUpdates.d.ts.map +1 -1
  38. package/build/UseUpdates.js +1 -1
  39. package/build/UseUpdates.js.map +1 -1
  40. package/build/UseUpdates.types.d.ts +14 -5
  41. package/build/UseUpdates.types.d.ts.map +1 -1
  42. package/build/UseUpdates.types.js.map +1 -1
  43. package/build/UseUpdatesUtils.d.ts +2 -14
  44. package/build/UseUpdatesUtils.d.ts.map +1 -1
  45. package/build/UseUpdatesUtils.js +4 -1
  46. package/build/UseUpdatesUtils.js.map +1 -1
  47. package/cli/build/syncConfigurationToNativeAsync.js +6 -5
  48. package/cli/src/syncConfigurationToNativeAsync.ts +6 -5
  49. package/e2e/fixtures/App.tsx +18 -0
  50. package/e2e/fixtures/Updates-error-recovery.e2e.ts +2 -2
  51. package/e2e/fixtures/Updates-startup.e2e.ts +18 -3
  52. package/e2e/fixtures/Updates.e2e.ts +3 -0
  53. package/e2e/fixtures/custom_init/AppDelegate.swift +141 -0
  54. package/e2e/fixtures/custom_init/MainActivity.kt +49 -0
  55. package/e2e/fixtures/custom_init/MainApplication.kt +48 -0
  56. package/e2e/fixtures/project_files/eas.json +2 -7
  57. package/e2e/setup/create-eas-project-custom-init.ts +42 -0
  58. package/e2e/setup/project.ts +110 -12
  59. package/e2e-cli/jest.config.js +8 -0
  60. package/expo-module.config.json +1 -3
  61. package/expo-updates-gradle-plugin/build.gradle.kts +1 -1
  62. package/expo-updates-gradle-plugin/src/main/kotlin/expo/modules/updates/ExpoUpdatesPlugin.kt +9 -1
  63. package/ios/EXUpdates/AppController.swift +6 -4
  64. package/ios/EXUpdates/AppLauncher/AppLauncherWithDatabase.swift +3 -3
  65. package/ios/EXUpdates/AppLoader/AppLoaderTask.swift +9 -11
  66. package/ios/EXUpdates/AppLoader/FileDownloader.swift +4 -4
  67. package/ios/EXUpdates/AppLoader/RemoteAppLoader.swift +1 -1
  68. package/ios/EXUpdates/Database/UpdatesDatabase.swift +2 -2
  69. package/ios/EXUpdates/Database/UpdatesDatabaseInitialization.swift +14 -6
  70. package/ios/EXUpdates/Database/UpdatesReaper.swift +4 -3
  71. package/ios/EXUpdates/DevLauncherAppController.swift +4 -2
  72. package/ios/EXUpdates/DisabledAppController.swift +5 -1
  73. package/ios/EXUpdates/EnabledAppController.swift +1 -5
  74. package/ios/EXUpdates/ErrorRecovery.swift +4 -2
  75. package/ios/EXUpdates/Logging/UpdatesLogger.swift +4 -2
  76. package/ios/EXUpdates/Procedures/CheckForUpdateProcedure.swift +11 -13
  77. package/ios/EXUpdates/Procedures/FetchUpdateProcedure.swift +6 -6
  78. package/ios/EXUpdates/Procedures/RecreateReactContextProcedure.swift +2 -2
  79. package/ios/EXUpdates/Procedures/RelaunchProcedure.swift +6 -4
  80. package/ios/EXUpdates/Procedures/StartupProcedure.swift +16 -14
  81. package/ios/EXUpdates/Procedures/StateMachineProcedure.swift +9 -9
  82. package/ios/EXUpdates/Procedures/StateMachineSerialExecutorQueue.swift +2 -2
  83. package/ios/EXUpdates/ReactDelegateHandler/ExpoUpdatesReactDelegateHandler.swift +13 -3
  84. package/ios/EXUpdates/UpdatesConfig.swift +1 -1
  85. package/ios/EXUpdates/UpdatesStateMachine.swift +126 -155
  86. package/ios/EXUpdates/UpdatesUtils.swift +9 -1
  87. package/ios/EXUpdates.podspec +30 -9
  88. package/ios/Tests/AppLauncherWithDatabaseSpec.swift +3 -2
  89. package/ios/Tests/DatabaseInitializationSpec.swift +37 -16
  90. package/ios/Tests/DatabaseIntegrityCheckSpec.swift +1 -1
  91. package/ios/Tests/ErrorRecoverySpec.swift +1 -1
  92. package/ios/Tests/FileDownloaderManifestParsingSpec.swift +24 -24
  93. package/ios/Tests/FileDownloaderSpec.swift +9 -9
  94. package/ios/Tests/UpdatesBuildDataSpec.swift +1 -1
  95. package/ios/Tests/UpdatesDatabaseSpec.swift +1 -1
  96. package/ios/Tests/UpdatesLoggerSpec.swift +29 -9
  97. package/ios/Tests/UpdatesStateMachineSpec.swift +69 -31
  98. package/package.json +12 -13
  99. package/src/ExpoUpdates.web.ts +2 -0
  100. package/src/Updates.types.ts +2 -10
  101. package/src/UpdatesEmitter.ts +13 -6
  102. package/src/UseUpdates.ts +1 -2
  103. package/src/UseUpdates.types.ts +14 -5
  104. package/src/UseUpdatesUtils.ts +10 -17
  105. package/utils/build/resolveRuntimeVersionAsync.js +3 -0
  106. package/utils/build/vcs.js +3 -3
  107. package/utils/build/workflow.js +2 -2
  108. package/utils/src/resolveRuntimeVersionAsync.ts +5 -0
  109. package/utils/src/vcs.ts +3 -3
  110. package/utils/src/workflow.ts +2 -2
package/CHANGELOG.md CHANGED
@@ -10,76 +10,109 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
- ## 0.27.3 — 2025-03-11
13
+ ## 0.28.0 — 2025-04-04
14
+
15
+ ### 🛠 Breaking changes
16
+
17
+ - upgrade RN to 0.78 ([#35050](https://github.com/expo/expo/pull/35050) by [@vonovak](https://github.com/vonovak))
18
+ - Remove a few long-deprecated typescript types. ([#34215](https://github.com/expo/expo/pull/34215) by [@wschurman](https://github.com/wschurman))
19
+
20
+ ### 🎉 New features
21
+
22
+ - Add new state machine context about startup procedure. ([#32433](https://github.com/expo/expo/pull/32433) by [@wschurman](https://github.com/wschurman))
23
+ - Support for updates.useNativeDebug. ([#35468](https://github.com/expo/expo/pull/35468) by [@douglowder](https://github.com/douglowder))
24
+
25
+ ### 🐛 Bug fixes
26
+
27
+ - [android] Use more robust mechanism for determining empty multipart bodies. ([#33977](https://github.com/expo/expo/pull/33977) by [@wschurman](https://github.com/wschurman))
28
+ - fix E2E tests in Detox debug build ([#32951](https://github.com/expo/expo/pull/32951) by [@matejkriz](https://github.com/matejkriz))
29
+ - Fix runtime version validation warning ([#35188](https://github.com/expo/expo/pull/35188) by [@gabrieldonadel](https://github.com/gabrieldonadel))
30
+
31
+ ### 💡 Others
32
+
33
+ - [Android] Made ReactNativeFeatureFlags a parameter to the constructor of the ErrorRecovery class to be able to make tests pass ([#34363](https://github.com/expo/expo/pull/34363) by [@chrfalch](https://github.com/chrfalch))
34
+ - [iOS] Inject logger from controllers down to dependent objects. ([#34035](https://github.com/expo/expo/pull/34035) by [@wschurman](https://github.com/wschurman))
35
+ - [apple] Migrate remaining `expo-module.config.json` to unified platform syntax. ([#34445](https://github.com/expo/expo/pull/34445) by [@reichhartd](https://github.com/reichhartd))
36
+ - Fixed build error on iOS Expo Go. ([#34485](https://github.com/expo/expo/pull/34485) by [@kudo](https://github.com/kudo))
37
+ - Fixed Android unit test errors in BuilDataTest. ([#34510](https://github.com/expo/expo/pull/34510) by [@kudo](https://github.com/kudo))
38
+ - [Android] Started using expo modules gradle plugin. ([#34806](https://github.com/expo/expo/pull/34806) by [@lukmccall](https://github.com/lukmccall))
39
+ - Drop `fs-extra` in favor of `fs`. ([#35036](https://github.com/expo/expo/pull/35036) by [@kitten](https://github.com/kitten))
40
+ - Drop `fast-glob` in favor of `glob`. ([#35082](https://github.com/expo/expo/pull/35082) by [@kitten](https://github.com/kitten))
41
+ - Drop `fbemitter` in favor of custom emitter. ([#35317](https://github.com/expo/expo/pull/35317) by [@kitten](https://github.com/kitten))
42
+ - E2E tests for custom init. ([#35569](https://github.com/expo/expo/pull/35569) by [@douglowder](https://github.com/douglowder))
43
+ - Refactored `RCTReactNativeFactory` integration. ([#35679](https://github.com/expo/expo/pull/35679) by [@kudo](https://github.com/kudo))
44
+
45
+ ## 0.27.4 - 2025-03-18
46
+
47
+ ### 🎉 New features
48
+
49
+ - Support brownfield apps with EX_UPDATES_CUSTOM_INIT flag. ([#35391](https://github.com/expo/expo/pull/35391) by [@douglowder](https://github.com/douglowder))
50
+
51
+ ## 0.27.3 - 2025-03-11
14
52
 
15
53
  ### 🐛 Bug fixes
16
54
 
17
55
  - Pass through the package version to config plugin sync utilities ([#35372](https://github.com/expo/expo/pull/35372) by [@brentvatne](https://github.com/brentvatne))
18
56
 
19
- ## 0.27.2 2025-02-26
57
+ ## 0.27.2 - 2025-02-26
20
58
 
21
59
  ### 💡 Others
22
60
 
23
61
  - Add update id headers to asset requests ([#34453](https://github.com/expo/expo/pull/34453) by [@gabrieldonadel](https://github.com/gabrieldonadel))
24
62
 
25
- ## 0.27.1 2025-02-21
63
+ ## 0.27.1 - 2025-02-21
26
64
 
27
65
  ### 🎉 New features
28
66
 
29
67
  - Add `Updates.setUpdateURLAndRequestHeadersOverride()` to allow overriding update URL configuration from the JS API. ([#34422](https://github.com/expo/expo/pull/34422), [#34423](https://github.com/expo/expo/pull/34423), [#34425](https://github.com/expo/expo/pull/34425), [#34426](https://github.com/expo/expo/pull/34426), [#34454](https://github.com/expo/expo/pull/34454), [#34455](https://github.com/expo/expo/pull/34455), [#34428](https://github.com/expo/expo/pull/34428), [#34404](https://github.com/expo/expo/pull/34404) by [@kudo](https://github.com/kudo), [@wschurman](https://github.com/wschurman))
30
68
 
31
- ### 🐛 Bug fixes
32
-
33
- - Fixed build error on iOS Expo Go. ([#34485](https://github.com/expo/expo/pull/34485) by [@kudo](https://github.com/kudo))
34
- - Fixed Android unit test errors in BuilDataTest. ([#34510](https://github.com/expo/expo/pull/34510) by [@kudo](https://github.com/kudo))
35
-
36
- ## 0.26.19 — 2025-02-19
69
+ ## 0.26.19 - 2025-02-19
37
70
 
38
71
  ### 💡 Others
39
72
 
40
73
  - Fixed incorrect error log on Android. ([#34785](https://github.com/expo/expo/pull/34785) by [@kudo](https://github.com/kudo))
41
74
 
42
- ## 0.26.18 2025-02-12
75
+ ## 0.26.18 - 2025-02-12
43
76
 
44
77
  ### 🐛 Bug fixes
45
78
 
46
79
  - [Android] Fix `bytesToHex` `ArrayIndexOutOfBoundsException` during conversion. ([#34855](https://github.com/expo/expo/pull/34855) by [@gabrieldonadel](https://github.com/gabrieldonadel))
47
80
 
48
- ## 0.26.17 2025-02-06
81
+ ## 0.26.17 - 2025-02-06
49
82
 
50
83
  _This version does not introduce any user-facing changes._
51
84
 
52
- ## 0.26.16 2025-02-04
85
+ ## 0.26.16 - 2025-02-04
53
86
 
54
87
  ### 🐛 Bug fixes
55
88
 
56
89
  - Removed Apache Commons IO dependency and fixed crash issue on Android 7. ([#34638](https://github.com/expo/expo/pull/34638) by [@kudo](https://github.com/kudo))
57
90
 
58
- ## 0.26.15 2025-01-31
91
+ ## 0.26.15 - 2025-01-31
59
92
 
60
93
  ### 🐛 Bug fixes
61
94
 
62
95
  - Fix issue where syncing codesigning config for bare projects would clobber existing Expo.plist config ([#34597](https://github.com/expo/expo/pull/34597) by [@brentvatne](https://github.com/brentvatne))
63
96
 
64
- ## 0.26.14 2025-01-31
97
+ ## 0.26.14 - 2025-01-31
65
98
 
66
99
  _This version does not introduce any user-facing changes._
67
100
 
68
- ## 0.26.13 2025-01-19
101
+ ## 0.26.13 - 2025-01-19
69
102
 
70
103
  _This version does not introduce any user-facing changes._
71
104
 
72
- ## 0.26.12 2025-01-10
105
+ ## 0.26.12 - 2025-01-10
73
106
 
74
107
  _This version does not introduce any user-facing changes._
75
108
 
76
- ## 0.26.11 2025-01-08
109
+ ## 0.26.11 - 2025-01-08
77
110
 
78
111
  ### 🐛 Bug fixes
79
112
 
80
113
  - Fix an issue where `launchFallbackUpdateFromDisk` is called from a foreground thread leading to ANRs. ([#33693](https://github.com/expo/expo/pull/33693) by [@alanjhughes](https://github.com/alanjhughes))
81
114
 
82
- ## 0.26.10 2024-12-05
115
+ ## 0.26.10 - 2024-12-05
83
116
 
84
117
  ### 🐛 Bug fixes
85
118
 
@@ -1,30 +1,45 @@
1
1
  buildscript {
2
- def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
3
- apply from: expoModulesCorePlugin
4
- applyKotlinExpoModulesCorePlugin()
2
+ ext {
3
+ boolish = { value ->
4
+ return value.toString().toBoolean()
5
+ }
6
+ getKspVersion = {
7
+ if (rootProject.hasProperty("kspVersion")) {
8
+ return rootProject["kspVersion"]
9
+ }
10
+
11
+ // We can remove this path once we update the test environment
12
+ // to use the same version of Kotlin as the `expo/expo` repo.
13
+ def kotlinVersion = rootProject["kotlinVersion"]
14
+ if (kotlinVersion == "2.0.21") {
15
+ return "2.0.21-1.0.28"
16
+ } else if (kotlinVersion == "1.9.25") {
17
+ return "1.9.25-1.0.20"
18
+ }
19
+
20
+ return "1.9.24-1.0.20"
21
+ }
22
+ }
5
23
 
6
24
  repositories {
7
25
  mavenCentral()
8
26
  }
9
27
 
10
28
  dependencies {
11
- classpath "com.google.devtools.ksp:symbol-processing-gradle-plugin:${kspVersion()}"
29
+ classpath "com.google.devtools.ksp:symbol-processing-gradle-plugin:${getKspVersion()}"
12
30
  }
13
31
  }
14
32
 
15
33
  apply plugin: 'com.android.library'
34
+ apply plugin: 'expo-module-gradle-plugin'
16
35
  apply plugin: 'com.google.devtools.ksp'
17
36
 
18
- group = 'host.exp.exponent'
19
- version = '0.27.3'
37
+ expoModule {
38
+ canBePublished false
39
+ }
20
40
 
21
- def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
22
- apply from: expoModulesCorePlugin
23
- applyKotlinExpoModulesCorePlugin()
24
- applyKspJvmToolchain()
25
- useCoreDependencies()
26
- useDefaultAndroidSdkVersions()
27
- useExpoPublishing()
41
+ group = 'host.exp.exponent'
42
+ version = '0.28.0'
28
43
 
29
44
  // Utility method to derive boolean values from the environment or from Java properties,
30
45
  // and return them as strings to be used in BuildConfig fields
@@ -49,6 +64,10 @@ def getBoolStringFromPropOrEnv(String name, Boolean defaultValue) {
49
64
  // debug builds. (default false)
50
65
  def exUpdatesNativeDebug = getBoolStringFromPropOrEnv("EX_UPDATES_NATIVE_DEBUG", false)
51
66
 
67
+ // If true, app is using custom code to initialize expo-updates, so default initialization code
68
+ // will be disabled.
69
+ def exUpdatesCustomInit = getBoolStringFromPropOrEnv("EX_UPDATES_CUSTOM_INIT", false)
70
+
52
71
  // If true, code will run that delays app loading until updates is initialized, to prevent ANR issues.
53
72
  // (default true)
54
73
  def exUpdatesAndroidDelayLoadApp = getBoolStringFromPropOrEnv("EX_UPDATES_ANDROID_DELAY_LOAD_APP", true)
@@ -63,11 +82,12 @@ android {
63
82
  namespace "expo.modules.updates"
64
83
  defaultConfig {
65
84
  versionCode 31
66
- versionName '0.27.3'
85
+ versionName '0.28.0'
67
86
  consumerProguardFiles("proguard-rules.pro")
68
87
  testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
69
88
 
70
89
  buildConfigField("boolean", "EX_UPDATES_NATIVE_DEBUG", exUpdatesNativeDebug)
90
+ buildConfigField("boolean", "EX_UPDATES_CUSTOM_INIT", exUpdatesCustomInit)
71
91
  buildConfigField("boolean", "EX_UPDATES_ANDROID_DELAY_LOAD_APP", exUpdatesAndroidDelayLoadApp)
72
92
  buildConfigField("boolean", "USE_DEV_CLIENT", useDevClient.toString())
73
93
  }
@@ -117,7 +137,8 @@ dependencies {
117
137
  testImplementation 'junit:junit:4.13.2'
118
138
  testImplementation 'androidx.test:core:1.5.0'
119
139
  testImplementation "io.mockk:mockk:$mockk_version"
120
- testImplementation "org.jetbrains.kotlin:kotlin-test-junit:${kotlinVersion()}"
140
+ testImplementation "org.jetbrains.kotlin:kotlin-test-junit:${kotlinVersion}"
141
+ testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3'
121
142
  testImplementation 'org.robolectric:robolectric:4.14.1'
122
143
 
123
144
  androidTestImplementation 'com.squareup.okio:okio:2.9.0'
@@ -126,7 +147,8 @@ dependencies {
126
147
  androidTestImplementation 'androidx.test:rules:1.5.0'
127
148
  androidTestImplementation "io.mockk:mockk-android:$mockk_version"
128
149
  androidTestImplementation "androidx.room:room-testing:$room_version"
129
- androidTestImplementation "org.jetbrains.kotlin:kotlin-test-junit:${kotlinVersion()}"
150
+ androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3'
151
+ androidTestImplementation "org.jetbrains.kotlin:kotlin-test-junit:${kotlinVersion}"
130
152
 
131
- implementation "org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion()}"
153
+ implementation "org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}"
132
154
  }
@@ -35,7 +35,7 @@ class DisabledUpdatesController(
35
35
  /** Keep the activity for [RecreateReactContextProcedure] to relaunch the app. */
36
36
  private var weakActivity: WeakReference<Activity>? = null
37
37
 
38
- private val logger = UpdatesLogger(context)
38
+ private val logger = UpdatesLogger(context.filesDir)
39
39
  override val eventManager: IUpdatesEventManager = UpdatesEventManager(logger)
40
40
 
41
41
  // disabled controller state machine can only be idle or restarting
@@ -2,7 +2,6 @@ package expo.modules.updates
2
2
 
3
3
  import android.app.Activity
4
4
  import android.content.Context
5
- import android.os.AsyncTask
6
5
  import android.os.Bundle
7
6
  import com.facebook.react.bridge.ReactContext
8
7
  import com.facebook.react.devsupport.interfaces.DevSupportManager
@@ -27,6 +26,9 @@ import expo.modules.updates.procedures.StartupProcedure
27
26
  import expo.modules.updates.selectionpolicy.SelectionPolicyFactory
28
27
  import expo.modules.updates.statemachine.UpdatesStateMachine
29
28
  import expo.modules.updates.statemachine.UpdatesStateValue
29
+ import kotlinx.coroutines.CoroutineScope
30
+ import kotlinx.coroutines.Dispatchers
31
+ import kotlinx.coroutines.launch
30
32
  import java.io.File
31
33
  import java.lang.ref.WeakReference
32
34
  import kotlin.time.DurationUnit
@@ -42,7 +44,7 @@ class EnabledUpdatesController(
42
44
  ) : IUpdatesController {
43
45
  /** Keep the activity for [RelaunchProcedure] to relaunch the app. */
44
46
  private var weakActivity: WeakReference<Activity>? = null
45
- private val logger = UpdatesLogger(context)
47
+ private val logger = UpdatesLogger(context.filesDir)
46
48
  override val eventManager: IUpdatesEventManager = UpdatesEventManager(logger)
47
49
 
48
50
  private val fileDownloader = FileDownloader(context, updatesConfiguration, logger)
@@ -51,9 +53,10 @@ class EnabledUpdatesController(
51
53
  )
52
54
  private val stateMachine = UpdatesStateMachine(logger, eventManager, UpdatesStateValue.entries.toSet())
53
55
  private val databaseHolder = DatabaseHolder(UpdatesDatabase.getInstance(context))
56
+ private val controllerScope = CoroutineScope(Dispatchers.IO)
54
57
 
55
58
  private fun purgeUpdatesLogsOlderThanOneDay() {
56
- UpdatesLogReader(context).purgeLogEntries {
59
+ UpdatesLogReader(context.filesDir).purgeLogEntries {
57
60
  if (it != null) {
58
61
  logger.error("UpdatesLogReader: error in purgeLogEntries", it, UpdatesErrorCode.Unknown)
59
62
  }
@@ -219,7 +222,7 @@ class EnabledUpdatesController(
219
222
  }
220
223
 
221
224
  override fun getExtraParams(callback: IUpdatesController.ModuleCallback<Bundle>) {
222
- AsyncTask.execute {
225
+ controllerScope.launch {
223
226
  try {
224
227
  val result = ManifestMetadata.getExtraParams(
225
228
  databaseHolder.database,
@@ -245,7 +248,7 @@ class EnabledUpdatesController(
245
248
  }
246
249
 
247
250
  override fun setExtraParam(key: String, value: String?, callback: IUpdatesController.ModuleCallback<Unit>) {
248
- AsyncTask.execute {
251
+ controllerScope.launch {
249
252
  try {
250
253
  ManifestMetadata.setExtraParam(
251
254
  databaseHolder.database,
@@ -108,7 +108,7 @@ interface IUpdatesController {
108
108
  this["runtimeVersion"] = runtimeVersion ?: ""
109
109
  this["checkAutomatically"] = checkOnLaunch.toJSString()
110
110
  this["channel"] = requestHeaders["expo-channel-name"] ?: ""
111
- this["shouldDeferToNativeForAPIMethodAvailabilityInDevelopment"] = shouldDeferToNativeForAPIMethodAvailabilityInDevelopment || BuildConfig.EX_UPDATES_NATIVE_DEBUG
111
+ this["shouldDeferToNativeForAPIMethodAvailabilityInDevelopment"] = shouldDeferToNativeForAPIMethodAvailabilityInDevelopment || UpdatesPackage.isUsingNativeDebug
112
112
  this["initialContext"] = initialContext.bundle
113
113
 
114
114
  if (launchedUpdate != null) {
@@ -18,146 +18,156 @@ import java.lang.ref.WeakReference
18
18
  * start the process of loading and launching an update, then responds appropriately depending on
19
19
  * the callbacks that are invoked.
20
20
  */
21
- class UpdatesController {
22
- companion object {
23
- private var singletonInstance: IUpdatesController? = null
24
- private var overrideConfiguration: UpdatesConfiguration? = null
25
-
26
- @JvmStatic val instance: IUpdatesController
27
- get() {
28
- return checkNotNull(singletonInstance) { "UpdatesController.instance was called before the module was initialized" }
29
- }
21
+ object UpdatesController {
22
+ private var singletonInstance: IUpdatesController? = null
23
+ private var overrideConfiguration: UpdatesConfiguration? = null
24
+
25
+ @JvmStatic
26
+ val instance: IUpdatesController
27
+ get() {
28
+ return checkNotNull(singletonInstance) { "UpdatesController.instance was called before the module was initialized" }
29
+ }
30
30
 
31
- @JvmStatic fun initializeWithoutStarting(context: Context) {
32
- if (singletonInstance != null) {
33
- return
31
+ @JvmStatic
32
+ fun initializeWithoutStarting(context: Context) {
33
+ if (singletonInstance != null) {
34
+ return
35
+ }
36
+ val useDeveloperSupport =
37
+ (context as? ReactApplication)?.reactNativeHost?.useDeveloperSupport ?: false
38
+ if (useDeveloperSupport && !UpdatesPackage.isUsingNativeDebug) {
39
+ if (BuildConfig.USE_DEV_CLIENT) {
40
+ val devLauncherController = initializeAsDevLauncherWithoutStarting(context)
41
+ singletonInstance = devLauncherController
42
+ UpdatesControllerRegistry.controller = WeakReference(devLauncherController)
43
+ } else {
44
+ singletonInstance = DisabledUpdatesController(context, null)
34
45
  }
35
- val useDeveloperSupport = (context as? ReactApplication)?.reactNativeHost?.useDeveloperSupport ?: false
36
- if (useDeveloperSupport && !BuildConfig.EX_UPDATES_NATIVE_DEBUG) {
37
- if (BuildConfig.USE_DEV_CLIENT) {
38
- val devLauncherController = initializeAsDevLauncherWithoutStarting(context)
39
- singletonInstance = devLauncherController
40
- UpdatesControllerRegistry.controller = WeakReference(devLauncherController)
41
- } else {
42
- singletonInstance = DisabledUpdatesController(context, null)
46
+ return
47
+ }
48
+
49
+ val logger = UpdatesLogger(context.filesDir)
50
+
51
+ val updatesDirectory = try {
52
+ UpdatesUtils.getOrCreateUpdatesDirectory(context)
53
+ } catch (e: Exception) {
54
+ logger.error(
55
+ "The expo-updates system is disabled due to a storage access error",
56
+ e,
57
+ UpdatesErrorCode.InitializationError
58
+ )
59
+ singletonInstance = DisabledUpdatesController(context, e)
60
+ return
61
+ }
62
+
63
+ val updatesConfiguration: UpdatesConfiguration? = overrideConfiguration ?: run {
64
+ when (UpdatesConfiguration.getUpdatesConfigurationValidationResult(context, null)) {
65
+ UpdatesConfigurationValidationResult.VALID -> {
66
+ return@run UpdatesConfiguration(context, null)
43
67
  }
44
- return
45
- }
46
68
 
47
- val logger = UpdatesLogger(context)
69
+ UpdatesConfigurationValidationResult.INVALID_NOT_ENABLED -> logger.warn(
70
+ "The expo-updates system is explicitly disabled. To enable it, set the enabled setting to true.",
71
+ UpdatesErrorCode.InitializationError
72
+ )
48
73
 
49
- val updatesDirectory = try {
50
- UpdatesUtils.getOrCreateUpdatesDirectory(context)
51
- } catch (e: Exception) {
52
- logger.error(
53
- "The expo-updates system is disabled due to a storage access error",
54
- e,
74
+ UpdatesConfigurationValidationResult.INVALID_MISSING_URL -> logger.warn(
75
+ "The expo-updates system is disabled due to an invalid configuration. Ensure a valid URL is supplied.",
55
76
  UpdatesErrorCode.InitializationError
56
77
  )
57
- singletonInstance = DisabledUpdatesController(context, e)
58
- return
59
- }
60
78
 
61
- val updatesConfiguration: UpdatesConfiguration? = overrideConfiguration ?: run {
62
- when (UpdatesConfiguration.getUpdatesConfigurationValidationResult(context, null)) {
63
- UpdatesConfigurationValidationResult.VALID -> {
64
- return@run UpdatesConfiguration(context, null)
65
- }
66
- UpdatesConfigurationValidationResult.INVALID_NOT_ENABLED -> logger.warn(
67
- "The expo-updates system is explicitly disabled. To enable it, set the enabled setting to true.",
68
- UpdatesErrorCode.InitializationError
69
- )
70
- UpdatesConfigurationValidationResult.INVALID_MISSING_URL -> logger.warn(
71
- "The expo-updates system is disabled due to an invalid configuration. Ensure a valid URL is supplied.",
72
- UpdatesErrorCode.InitializationError
73
- )
74
- UpdatesConfigurationValidationResult.INVALID_MISSING_RUNTIME_VERSION -> logger.warn(
75
- "The expo-updates system is disabled due to an invalid configuration. Ensure a runtime version is supplied.",
76
- UpdatesErrorCode.InitializationError
77
- )
78
- }
79
- return@run null
79
+ UpdatesConfigurationValidationResult.INVALID_MISSING_RUNTIME_VERSION -> logger.warn(
80
+ "The expo-updates system is disabled due to an invalid configuration. Ensure a runtime version is supplied.",
81
+ UpdatesErrorCode.InitializationError
82
+ )
80
83
  }
84
+ return@run null
85
+ }
81
86
 
82
- singletonInstance = if (updatesConfiguration != null) {
83
- EnabledUpdatesController(context, updatesConfiguration, updatesDirectory)
84
- } else {
85
- DisabledUpdatesController(context, null)
86
- }
87
+ singletonInstance = if (updatesConfiguration != null) {
88
+ EnabledUpdatesController(context, updatesConfiguration, updatesDirectory)
89
+ } else {
90
+ DisabledUpdatesController(context, null)
87
91
  }
92
+ }
88
93
 
89
- private fun initializeAsDevLauncherWithoutStarting(context: Context): UpdatesDevLauncherController {
90
- check(singletonInstance == null) { "UpdatesController must not be initialized prior to calling initializeAsDevLauncherWithoutStarting" }
94
+ private fun initializeAsDevLauncherWithoutStarting(context: Context): UpdatesDevLauncherController {
95
+ check(singletonInstance == null) { "UpdatesController must not be initialized prior to calling initializeAsDevLauncherWithoutStarting" }
91
96
 
92
- var updatesDirectoryException: Exception? = null
93
- val updatesDirectory = try {
94
- UpdatesUtils.getOrCreateUpdatesDirectory(context)
95
- } catch (e: Exception) {
96
- updatesDirectoryException = e
97
- null
98
- }
97
+ var updatesDirectoryException: Exception? = null
98
+ val updatesDirectory = try {
99
+ UpdatesUtils.getOrCreateUpdatesDirectory(context)
100
+ } catch (e: Exception) {
101
+ updatesDirectoryException = e
102
+ null
103
+ }
99
104
 
100
- val initialUpdatesConfiguration = overrideConfiguration ?: run {
101
- if (UpdatesConfiguration.getUpdatesConfigurationValidationResult(context, null) == UpdatesConfigurationValidationResult.VALID) {
102
- UpdatesConfiguration(context, null)
103
- } else {
105
+ val initialUpdatesConfiguration = overrideConfiguration ?: run {
106
+ if (UpdatesConfiguration.getUpdatesConfigurationValidationResult(
107
+ context,
104
108
  null
105
- }
109
+ ) == UpdatesConfigurationValidationResult.VALID
110
+ ) {
111
+ UpdatesConfiguration(context, null)
112
+ } else {
113
+ null
106
114
  }
107
-
108
- val instance = UpdatesDevLauncherController(
109
- context,
110
- initialUpdatesConfiguration,
111
- updatesDirectory,
112
- updatesDirectoryException
113
- )
114
- singletonInstance = instance
115
- return instance
116
115
  }
117
116
 
118
- /**
119
- * Initializes the UpdatesController singleton. This should be called as early as possible in the
120
- * application's lifecycle. Can pass additional configuration to this method to set or override
121
- * configuration values at runtime rather than just AndroidManifest.xml.
122
- * @param context the base context of the application, ideally a [ReactApplication]
123
- */
124
- @JvmStatic fun initialize(context: Context) {
125
- if (singletonInstance == null) {
126
- initializeWithoutStarting(context)
127
- singletonInstance!!.start()
128
- }
129
- }
117
+ val instance = UpdatesDevLauncherController(
118
+ context,
119
+ initialUpdatesConfiguration,
120
+ updatesDirectory,
121
+ updatesDirectoryException
122
+ )
123
+ singletonInstance = instance
124
+ return instance
125
+ }
130
126
 
131
- /**
132
- * Overrides the [UpdatesConfiguration] that will be used inside [UpdatesController]
133
- * This should be called as early as possible in the application's lifecycle.
134
- * Can pass additional configuration to this method to set or override
135
- * configuration values at runtime rather than just AndroidManifest.xml.
136
- *
137
- * @param context the base context of the application, ideally a [ReactApplication]
138
- * @param configuration map of configuration pairs to override those from AndroidManifest.xml
139
- */
140
- @JvmStatic
141
- fun overrideConfiguration(context: Context, configuration: Map<String, Any>) {
142
- if (singletonInstance != null) {
143
- throw AssertionError("The method should be called before UpdatesController.initialize()")
144
- }
145
- val updatesConfigurationValidationResult = UpdatesConfiguration.getUpdatesConfigurationValidationResult(context, configuration)
146
- if (updatesConfigurationValidationResult == UpdatesConfigurationValidationResult.VALID) {
147
- overrideConfiguration = UpdatesConfiguration(context, configuration)
148
- } else {
149
- val logger = UpdatesLogger(context)
150
- logger.warn("Failed to overrideConfiguration: invalid configuration: ${updatesConfigurationValidationResult.name}")
151
- }
127
+ /**
128
+ * Initializes the UpdatesController singleton. This should be called as early as possible in the
129
+ * application's lifecycle. Can pass additional configuration to this method to set or override
130
+ * configuration values at runtime rather than just AndroidManifest.xml.
131
+ * @param context the base context of the application, ideally a [ReactApplication]
132
+ */
133
+ @JvmStatic
134
+ fun initialize(context: Context) {
135
+ if (singletonInstance == null) {
136
+ initializeWithoutStarting(context)
137
+ singletonInstance!!.start()
152
138
  }
139
+ }
153
140
 
154
- internal fun setUpdatesEventManagerObserver(observer: WeakReference<IUpdatesEventManagerObserver>) {
155
- singletonInstance?.eventManager?.observer = observer
156
- singletonInstance?.onEventListenerStartObserving()
141
+ /**
142
+ * Overrides the [UpdatesConfiguration] that will be used inside [UpdatesController]
143
+ * This should be called as early as possible in the application's lifecycle.
144
+ * Can pass additional configuration to this method to set or override
145
+ * configuration values at runtime rather than just AndroidManifest.xml.
146
+ *
147
+ * @param context the base context of the application, ideally a [ReactApplication]
148
+ * @param configuration map of configuration pairs to override those from AndroidManifest.xml
149
+ */
150
+ @JvmStatic
151
+ fun overrideConfiguration(context: Context, configuration: Map<String, Any>) {
152
+ if (singletonInstance != null) {
153
+ throw AssertionError("The method should be called before UpdatesController.initialize()")
157
154
  }
158
-
159
- internal fun removeUpdatesEventManagerObserver() {
160
- singletonInstance?.eventManager?.observer = null
155
+ val updatesConfigurationValidationResult =
156
+ UpdatesConfiguration.getUpdatesConfigurationValidationResult(context, configuration)
157
+ if (updatesConfigurationValidationResult == UpdatesConfigurationValidationResult.VALID) {
158
+ overrideConfiguration = UpdatesConfiguration(context, configuration)
159
+ } else {
160
+ val logger = UpdatesLogger(context.filesDir)
161
+ logger.warn("Failed to overrideConfiguration: invalid configuration: ${updatesConfigurationValidationResult.name}")
161
162
  }
162
163
  }
164
+
165
+ internal fun setUpdatesEventManagerObserver(observer: WeakReference<IUpdatesEventManagerObserver>) {
166
+ singletonInstance?.eventManager?.observer = observer
167
+ singletonInstance?.onEventListenerStartObserving()
168
+ }
169
+
170
+ internal fun removeUpdatesEventManagerObserver() {
171
+ singletonInstance?.eventManager?.observer = null
172
+ }
163
173
  }
@@ -54,7 +54,7 @@ class UpdatesDevLauncherController(
54
54
 
55
55
  private var launcher: Launcher? = null
56
56
 
57
- private val logger = UpdatesLogger(context)
57
+ private val logger = UpdatesLogger(context.filesDir)
58
58
 
59
59
  private var previousUpdatesConfiguration: UpdatesConfiguration? = null
60
60
  private var updatesConfiguration: UpdatesConfiguration? = initialUpdatesConfiguration
@@ -78,8 +78,11 @@ class UpdatesDevLauncherController(
78
78
  }
79
79
 
80
80
  @get:Synchronized
81
- override val launchAssetFile: String
82
- get() = throw Exception("IUpdatesController.launchAssetFile should not be called in dev client")
81
+ override val launchAssetFile: String?
82
+ get() {
83
+ logger.warn("launchAssetFile should not be called from expo-dev-client build, except for Detox testing")
84
+ return null
85
+ }
83
86
 
84
87
  override val bundleAssetName: String
85
88
  get() = throw Exception("IUpdatesController.bundleAssetName should not be called in dev client")