expo-updates 1.0.0-canary-20250303-4dba60e → 1.0.0-canary-20250304-8a21aa7
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/android/build.gradle +1 -0
- package/android/src/main/java/expo/modules/updates/DisabledUpdatesController.kt +1 -1
- package/android/src/main/java/expo/modules/updates/EnabledUpdatesController.kt +2 -2
- package/android/src/main/java/expo/modules/updates/UpdatesController.kt +128 -118
- package/android/src/main/java/expo/modules/updates/UpdatesDevLauncherController.kt +1 -1
- package/android/src/main/java/expo/modules/updates/UpdatesModule.kt +34 -14
- package/android/src/main/java/expo/modules/updates/logging/UpdatesLogReader.kt +3 -3
- package/android/src/main/java/expo/modules/updates/logging/UpdatesLogger.kt +3 -3
- package/package.json +10 -10
package/android/build.gradle
CHANGED
|
@@ -138,6 +138,7 @@ dependencies {
|
|
|
138
138
|
androidTestImplementation 'androidx.test:rules:1.5.0'
|
|
139
139
|
androidTestImplementation "io.mockk:mockk-android:$mockk_version"
|
|
140
140
|
androidTestImplementation "androidx.room:room-testing:$room_version"
|
|
141
|
+
androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3'
|
|
141
142
|
androidTestImplementation "org.jetbrains.kotlin:kotlin-test-junit:${kotlinVersion}"
|
|
142
143
|
|
|
143
144
|
implementation "org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}"
|
|
@@ -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
|
|
@@ -44,7 +44,7 @@ class EnabledUpdatesController(
|
|
|
44
44
|
) : IUpdatesController {
|
|
45
45
|
/** Keep the activity for [RelaunchProcedure] to relaunch the app. */
|
|
46
46
|
private var weakActivity: WeakReference<Activity>? = null
|
|
47
|
-
private val logger = UpdatesLogger(context)
|
|
47
|
+
private val logger = UpdatesLogger(context.filesDir)
|
|
48
48
|
override val eventManager: IUpdatesEventManager = UpdatesEventManager(logger)
|
|
49
49
|
|
|
50
50
|
private val fileDownloader = FileDownloader(context, updatesConfiguration, logger)
|
|
@@ -56,7 +56,7 @@ class EnabledUpdatesController(
|
|
|
56
56
|
private val controllerScope = CoroutineScope(Dispatchers.IO)
|
|
57
57
|
|
|
58
58
|
private fun purgeUpdatesLogsOlderThanOneDay() {
|
|
59
|
-
UpdatesLogReader(context).purgeLogEntries {
|
|
59
|
+
UpdatesLogReader(context.filesDir).purgeLogEntries {
|
|
60
60
|
if (it != null) {
|
|
61
61
|
logger.error("UpdatesLogReader: error in purgeLogEntries", it, UpdatesErrorCode.Unknown)
|
|
62
62
|
}
|
|
@@ -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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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 && !BuildConfig.EX_UPDATES_NATIVE_DEBUG) {
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
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
|
-
|
|
50
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
+
singletonInstance = if (updatesConfiguration != null) {
|
|
88
|
+
EnabledUpdatesController(context, updatesConfiguration, updatesDirectory)
|
|
89
|
+
} else {
|
|
90
|
+
DisabledUpdatesController(context, null)
|
|
87
91
|
}
|
|
92
|
+
}
|
|
88
93
|
|
|
89
|
-
|
|
90
|
-
|
|
94
|
+
private fun initializeAsDevLauncherWithoutStarting(context: Context): UpdatesDevLauncherController {
|
|
95
|
+
check(singletonInstance == null) { "UpdatesController must not be initialized prior to calling initializeAsDevLauncherWithoutStarting" }
|
|
91
96
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
|
|
160
|
-
|
|
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
|
|
@@ -2,11 +2,11 @@ package expo.modules.updates
|
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
4
|
import android.net.Uri
|
|
5
|
-
import android.os.AsyncTask
|
|
6
5
|
import android.os.Bundle
|
|
7
6
|
import expo.modules.kotlin.Promise
|
|
8
7
|
import expo.modules.kotlin.exception.CodedException
|
|
9
8
|
import expo.modules.kotlin.exception.Exceptions
|
|
9
|
+
import expo.modules.kotlin.functions.Coroutine
|
|
10
10
|
import expo.modules.kotlin.modules.Module
|
|
11
11
|
import expo.modules.kotlin.modules.ModuleDefinition
|
|
12
12
|
import expo.modules.kotlin.records.Field
|
|
@@ -18,6 +18,12 @@ import expo.modules.updates.logging.UpdatesLogEntry
|
|
|
18
18
|
import expo.modules.updates.logging.UpdatesLogReader
|
|
19
19
|
import expo.modules.updates.logging.UpdatesLogger
|
|
20
20
|
import expo.modules.updates.statemachine.UpdatesStateContext
|
|
21
|
+
import kotlinx.coroutines.CoroutineScope
|
|
22
|
+
import kotlinx.coroutines.Dispatchers
|
|
23
|
+
import kotlinx.coroutines.cancel
|
|
24
|
+
import kotlinx.coroutines.launch
|
|
25
|
+
import kotlinx.coroutines.withContext
|
|
26
|
+
import java.io.File
|
|
21
27
|
import java.lang.ref.WeakReference
|
|
22
28
|
import java.util.Date
|
|
23
29
|
|
|
@@ -32,18 +38,20 @@ enum class UpdatesJSEvent(val eventName: String) : Enumerable {
|
|
|
32
38
|
*/
|
|
33
39
|
class UpdatesModule : Module(), IUpdatesEventManagerObserver {
|
|
34
40
|
private val logger: UpdatesLogger
|
|
35
|
-
get() = UpdatesLogger(context)
|
|
41
|
+
get() = UpdatesLogger(context.filesDir)
|
|
36
42
|
|
|
37
43
|
private val context: Context
|
|
38
44
|
get() = appContext.reactContext ?: throw Exceptions.ReactContextLost()
|
|
39
45
|
|
|
46
|
+
private val moduleScope = CoroutineScope(Dispatchers.IO)
|
|
47
|
+
|
|
40
48
|
override fun definition() = ModuleDefinition {
|
|
41
49
|
Name("ExpoUpdates")
|
|
42
50
|
|
|
43
51
|
Events<UpdatesJSEvent>()
|
|
44
52
|
|
|
45
53
|
Constants {
|
|
46
|
-
UpdatesLogger(context).info("UpdatesModule: getConstants called", UpdatesErrorCode.None)
|
|
54
|
+
UpdatesLogger(context.filesDir).info("UpdatesModule: getConstants called", UpdatesErrorCode.None)
|
|
47
55
|
UpdatesController.instance.getConstantsForModule().toModuleConstantsMap()
|
|
48
56
|
}
|
|
49
57
|
|
|
@@ -81,6 +89,7 @@ class UpdatesModule : Module(), IUpdatesEventManagerObserver {
|
|
|
81
89
|
is IUpdatesController.CheckForUpdateResult.ErrorResult -> {
|
|
82
90
|
promise.reject("ERR_UPDATES_CHECK", "Failed to check for update", result.error)
|
|
83
91
|
}
|
|
92
|
+
|
|
84
93
|
is IUpdatesController.CheckForUpdateResult.NoUpdateAvailable -> {
|
|
85
94
|
promise.resolve(
|
|
86
95
|
Bundle().apply {
|
|
@@ -90,6 +99,7 @@ class UpdatesModule : Module(), IUpdatesEventManagerObserver {
|
|
|
90
99
|
}
|
|
91
100
|
)
|
|
92
101
|
}
|
|
102
|
+
|
|
93
103
|
is IUpdatesController.CheckForUpdateResult.RollBackToEmbedded -> {
|
|
94
104
|
promise.resolve(
|
|
95
105
|
Bundle().apply {
|
|
@@ -98,6 +108,7 @@ class UpdatesModule : Module(), IUpdatesEventManagerObserver {
|
|
|
98
108
|
}
|
|
99
109
|
)
|
|
100
110
|
}
|
|
111
|
+
|
|
101
112
|
is IUpdatesController.CheckForUpdateResult.UpdateAvailable -> {
|
|
102
113
|
promise.resolve(
|
|
103
114
|
Bundle().apply {
|
|
@@ -128,6 +139,7 @@ class UpdatesModule : Module(), IUpdatesEventManagerObserver {
|
|
|
128
139
|
is IUpdatesController.FetchUpdateResult.ErrorResult -> {
|
|
129
140
|
promise.reject("ERR_UPDATES_FETCH", "Failed to download new update", result.error)
|
|
130
141
|
}
|
|
142
|
+
|
|
131
143
|
is IUpdatesController.FetchUpdateResult.Failure -> {
|
|
132
144
|
promise.resolve(
|
|
133
145
|
Bundle().apply {
|
|
@@ -136,6 +148,7 @@ class UpdatesModule : Module(), IUpdatesEventManagerObserver {
|
|
|
136
148
|
}
|
|
137
149
|
)
|
|
138
150
|
}
|
|
151
|
+
|
|
139
152
|
is IUpdatesController.FetchUpdateResult.RollBackToEmbedded -> {
|
|
140
153
|
promise.resolve(
|
|
141
154
|
Bundle().apply {
|
|
@@ -144,6 +157,7 @@ class UpdatesModule : Module(), IUpdatesEventManagerObserver {
|
|
|
144
157
|
}
|
|
145
158
|
)
|
|
146
159
|
}
|
|
160
|
+
|
|
147
161
|
is IUpdatesController.FetchUpdateResult.Success -> {
|
|
148
162
|
promise.resolve(
|
|
149
163
|
Bundle().apply {
|
|
@@ -193,15 +207,13 @@ class UpdatesModule : Module(), IUpdatesEventManagerObserver {
|
|
|
193
207
|
)
|
|
194
208
|
}
|
|
195
209
|
|
|
196
|
-
AsyncFunction("readLogEntriesAsync") { maxAge: Long
|
|
197
|
-
|
|
198
|
-
promise.resolve(readLogEntries(context, maxAge))
|
|
199
|
-
}
|
|
210
|
+
AsyncFunction("readLogEntriesAsync") Coroutine { maxAge: Long ->
|
|
211
|
+
return@Coroutine readLogEntries(context.filesDir, maxAge)
|
|
200
212
|
}
|
|
201
213
|
|
|
202
214
|
AsyncFunction("clearLogEntriesAsync") { promise: Promise ->
|
|
203
|
-
|
|
204
|
-
clearLogEntries(context) { error ->
|
|
215
|
+
moduleScope.launch {
|
|
216
|
+
clearLogEntries(context.filesDir) { error ->
|
|
205
217
|
if (error != null) {
|
|
206
218
|
promise.reject(
|
|
207
219
|
"ERR_UPDATES_READ_LOGS",
|
|
@@ -218,16 +230,24 @@ class UpdatesModule : Module(), IUpdatesEventManagerObserver {
|
|
|
218
230
|
Function("setUpdateURLAndRequestHeadersOverride") { configOverride: UpdatesConfigurationOverrideParam? ->
|
|
219
231
|
UpdatesController.instance.setUpdateURLAndRequestHeadersOverride(configOverride?.toUpdatesConfigurationOverride())
|
|
220
232
|
}
|
|
233
|
+
|
|
234
|
+
OnDestroy {
|
|
235
|
+
try {
|
|
236
|
+
moduleScope.cancel()
|
|
237
|
+
} catch (e: IllegalStateException) {
|
|
238
|
+
logger.error("The scope does not have a job in it", e)
|
|
239
|
+
}
|
|
240
|
+
}
|
|
221
241
|
}
|
|
222
242
|
|
|
223
243
|
companion object {
|
|
224
244
|
private val TAG = UpdatesModule::class.java.simpleName
|
|
225
245
|
|
|
226
|
-
internal fun readLogEntries(
|
|
227
|
-
val reader = UpdatesLogReader(
|
|
246
|
+
internal suspend fun readLogEntries(filesDirectory: File, maxAge: Long) = withContext(Dispatchers.IO) {
|
|
247
|
+
val reader = UpdatesLogReader(filesDirectory)
|
|
228
248
|
val date = Date()
|
|
229
249
|
val epoch = Date(date.time - maxAge)
|
|
230
|
-
|
|
250
|
+
reader.getLogEntries(epoch)
|
|
231
251
|
.mapNotNull { UpdatesLogEntry.create(it) }
|
|
232
252
|
.map { entry ->
|
|
233
253
|
Bundle().apply {
|
|
@@ -248,8 +268,8 @@ class UpdatesModule : Module(), IUpdatesEventManagerObserver {
|
|
|
248
268
|
}
|
|
249
269
|
}
|
|
250
270
|
|
|
251
|
-
internal fun clearLogEntries(
|
|
252
|
-
val reader = UpdatesLogReader(
|
|
271
|
+
internal suspend fun clearLogEntries(filesDirectory: File, completionHandler: (_: Exception?) -> Unit) {
|
|
272
|
+
val reader = UpdatesLogReader(filesDirectory)
|
|
253
273
|
reader.purgeLogEntries(
|
|
254
274
|
olderThan = Date(),
|
|
255
275
|
completionHandler
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
package expo.modules.updates.logging
|
|
2
2
|
|
|
3
|
-
import android.content.Context
|
|
4
3
|
import expo.modules.core.logging.PersistentFileLog
|
|
5
4
|
import expo.modules.updates.logging.UpdatesLogger.Companion.EXPO_UPDATES_LOGGING_TAG
|
|
5
|
+
import java.io.File
|
|
6
6
|
import java.lang.Long.max
|
|
7
7
|
import java.util.*
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@ import java.util.*
|
|
|
10
10
|
* Class for reading expo-updates logs
|
|
11
11
|
*/
|
|
12
12
|
class UpdatesLogReader(
|
|
13
|
-
|
|
13
|
+
filesDirectory: File
|
|
14
14
|
) {
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -37,7 +37,7 @@ class UpdatesLogReader(
|
|
|
37
37
|
.filter { entryString -> isEntryStringLaterThanTimestamp(entryString, epochTimestamp) }
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
private val persistentLog = PersistentFileLog(EXPO_UPDATES_LOGGING_TAG,
|
|
40
|
+
private val persistentLog = PersistentFileLog(EXPO_UPDATES_LOGGING_TAG, filesDirectory)
|
|
41
41
|
|
|
42
42
|
private fun isEntryStringLaterThanTimestamp(entryString: String, timestamp: Long): Boolean {
|
|
43
43
|
val entry = UpdatesLogEntry.create(entryString) ?: return false
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
package expo.modules.updates.logging
|
|
2
2
|
|
|
3
|
-
import android.content.Context
|
|
4
3
|
import expo.modules.core.logging.LogHandlers
|
|
5
4
|
import expo.modules.core.logging.LogType
|
|
6
5
|
import expo.modules.core.logging.Logger
|
|
7
6
|
import expo.modules.core.logging.LoggerTimer
|
|
7
|
+
import java.io.File
|
|
8
8
|
import java.util.Date
|
|
9
9
|
|
|
10
10
|
interface IUpdatesLogger {
|
|
@@ -14,7 +14,7 @@ interface IUpdatesLogger {
|
|
|
14
14
|
/**
|
|
15
15
|
* Class that implements logging for expo-updates with its own logcat tag
|
|
16
16
|
*/
|
|
17
|
-
class UpdatesLogger(
|
|
17
|
+
class UpdatesLogger(filesDirectory: File) : IUpdatesLogger {
|
|
18
18
|
|
|
19
19
|
fun trace(
|
|
20
20
|
message: String,
|
|
@@ -127,7 +127,7 @@ class UpdatesLogger(context: Context) : IUpdatesLogger {
|
|
|
127
127
|
private val logger = Logger(
|
|
128
128
|
listOf(
|
|
129
129
|
LogHandlers.createOSLogHandler(EXPO_UPDATES_LOGGING_TAG),
|
|
130
|
-
LogHandlers.createPersistentFileLogHandler(
|
|
130
|
+
LogHandlers.createPersistentFileLogHandler(filesDirectory, EXPO_UPDATES_LOGGING_TAG)
|
|
131
131
|
)
|
|
132
132
|
)
|
|
133
133
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-updates",
|
|
3
|
-
"version": "1.0.0-canary-
|
|
3
|
+
"version": "1.0.0-canary-20250304-8a21aa7",
|
|
4
4
|
"description": "Fetches and manages remotely-hosted assets and updates to your app's JS bundle.",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -39,15 +39,15 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@expo/code-signing-certificates": "0.0.5",
|
|
42
|
-
"@expo/config": "11.0.0-canary-
|
|
43
|
-
"@expo/config-plugins": "9.1.0-canary-
|
|
42
|
+
"@expo/config": "11.0.0-canary-20250304-8a21aa7",
|
|
43
|
+
"@expo/config-plugins": "9.1.0-canary-20250304-8a21aa7",
|
|
44
44
|
"@expo/spawn-async": "^1.7.2",
|
|
45
45
|
"arg": "4.1.0",
|
|
46
46
|
"chalk": "^4.1.2",
|
|
47
|
-
"expo-eas-client": "0.13.4-canary-
|
|
48
|
-
"expo-manifests": "0.15.8-canary-
|
|
49
|
-
"expo-structured-headers": "4.0.1-canary-
|
|
50
|
-
"expo-updates-interface": "1.0.1-canary-
|
|
47
|
+
"expo-eas-client": "0.13.4-canary-20250304-8a21aa7",
|
|
48
|
+
"expo-manifests": "0.15.8-canary-20250304-8a21aa7",
|
|
49
|
+
"expo-structured-headers": "4.0.1-canary-20250304-8a21aa7",
|
|
50
|
+
"expo-updates-interface": "1.0.1-canary-20250304-8a21aa7",
|
|
51
51
|
"fbemitter": "^3.0.0",
|
|
52
52
|
"glob": "^10.4.2",
|
|
53
53
|
"ignore": "^5.3.1",
|
|
@@ -57,15 +57,15 @@
|
|
|
57
57
|
"@types/jest": "^29.2.1",
|
|
58
58
|
"@types/node": "^18.19.34",
|
|
59
59
|
"@types/node-forge": "^1.0.0",
|
|
60
|
-
"expo-module-scripts": "4.0.5-canary-
|
|
60
|
+
"expo-module-scripts": "4.0.5-canary-20250304-8a21aa7",
|
|
61
61
|
"express": "^4.21.1",
|
|
62
62
|
"form-data": "^4.0.0",
|
|
63
63
|
"memfs": "^3.2.0",
|
|
64
64
|
"xstate": "^4.37.2"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
|
-
"expo": "53.0.0-canary-
|
|
67
|
+
"expo": "53.0.0-canary-20250304-8a21aa7",
|
|
68
68
|
"react": "*"
|
|
69
69
|
},
|
|
70
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "8a21aa734aadf339bb2778a80d32602ed561405b"
|
|
71
71
|
}
|