expo-background-task 0.2.6 → 0.2.7

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 (44) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/expo/modules/backgroundtask/BackgroundTaskConsumer.kt +2 -2
  4. package/android/src/main/java/expo/modules/backgroundtask/BackgroundTaskModule.kt +5 -15
  5. package/android/src/main/java/expo/modules/backgroundtask/BackgroundTaskScheduler.kt +48 -13
  6. package/android/src/main/java/expo/modules/backgroundtask/BackgroundTaskWork.kt +0 -7
  7. package/build/BackgroundTask.d.ts +2 -1
  8. package/build/BackgroundTask.d.ts.map +1 -1
  9. package/build/BackgroundTask.js +13 -12
  10. package/build/BackgroundTask.js.map +1 -1
  11. package/build/BackgroundTask.types.d.ts +5 -3
  12. package/build/BackgroundTask.types.d.ts.map +1 -1
  13. package/build/BackgroundTask.types.js.map +1 -1
  14. package/expo-module.config.json +1 -7
  15. package/ios/BackgroundTaskModule.swift +1 -23
  16. package/ios/BackgroundTaskScheduler.swift +11 -0
  17. package/package.json +3 -3
  18. package/src/BackgroundTask.ts +12 -12
  19. package/src/BackgroundTask.types.ts +5 -3
  20. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6-sources.jar +0 -0
  21. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6-sources.jar.md5 +0 -1
  22. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6-sources.jar.sha1 +0 -1
  23. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6-sources.jar.sha256 +0 -1
  24. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6-sources.jar.sha512 +0 -1
  25. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6.aar +0 -0
  26. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6.aar.md5 +0 -1
  27. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6.aar.sha1 +0 -1
  28. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6.aar.sha256 +0 -1
  29. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6.aar.sha512 +0 -1
  30. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6.module +0 -98
  31. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6.module.md5 +0 -1
  32. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6.module.sha1 +0 -1
  33. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6.module.sha256 +0 -1
  34. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6.module.sha512 +0 -1
  35. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6.pom +0 -46
  36. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6.pom.md5 +0 -1
  37. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6.pom.sha1 +0 -1
  38. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6.pom.sha256 +0 -1
  39. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/0.2.6/expo.modules.backgroundtask-0.2.6.pom.sha512 +0 -1
  40. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/maven-metadata.xml +0 -13
  41. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/maven-metadata.xml.md5 +0 -1
  42. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/maven-metadata.xml.sha1 +0 -1
  43. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/maven-metadata.xml.sha256 +0 -1
  44. package/local-maven-repo/host/exp/exponent/expo.modules.backgroundtask/maven-metadata.xml.sha512 +0 -1
package/CHANGELOG.md CHANGED
@@ -10,6 +10,13 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 0.2.7 — 2025-05-08
14
+
15
+ ### 💡 Others
16
+
17
+ - Exposed testing method for background tasks on both iOS and Android ([#36732](https://github.com/expo/expo/pull/36732) by [@chrfalch](https://github.com/chrfalch))
18
+ - Simplified how workers are started and stopped. Removed battery constraint on Android. ([#36705](https://github.com/expo/expo/pull/36705) by [@chrfalch](https://github.com/chrfalch))
19
+
13
20
  ## 0.2.6 — 2025-04-30
14
21
 
15
22
  _This version does not introduce any user-facing changes._
@@ -4,7 +4,7 @@ plugins {
4
4
  }
5
5
 
6
6
  group = 'host.exp.exponent'
7
- version = '0.2.6'
7
+ version = '0.2.7'
8
8
 
9
9
  dependencies {
10
10
  implementation 'androidx.work:work-runtime-ktx:2.9.1'
@@ -15,7 +15,7 @@ android {
15
15
  namespace "expo.modules.backgroundtask"
16
16
  defaultConfig {
17
17
  versionCode 23
18
- versionName "0.2.6"
18
+ versionName "0.2.7"
19
19
  consumerProguardFiles("proguard-rules.pro")
20
20
  }
21
21
  }
@@ -37,13 +37,13 @@ class BackgroundTaskConsumer(context: Context?, taskManagerUtils: TaskManagerUti
37
37
  this.task = task
38
38
 
39
39
  val intervalMinutes = getIntervalMinutes()
40
- BackgroundTaskScheduler.registerTask(intervalMinutes)
40
+ BackgroundTaskScheduler.registerTask(context, intervalMinutes)
41
41
  }
42
42
 
43
43
  override fun didUnregister() {
44
44
  Log.d(TAG, "didUnregister: ${task?.name}")
45
45
  this.task = null
46
- BackgroundTaskScheduler.unregisterTask()
46
+ BackgroundTaskScheduler.unregisterTask(context)
47
47
  }
48
48
 
49
49
  private fun getIntervalMinutes(): Long {
@@ -6,7 +6,6 @@ import expo.modules.interfaces.taskManager.TaskManagerInterface
6
6
  import expo.modules.kotlin.functions.Coroutine
7
7
  import expo.modules.kotlin.modules.Module
8
8
  import expo.modules.kotlin.modules.ModuleDefinition
9
- import kotlinx.coroutines.runBlocking
10
9
 
11
10
  class BackgroundTaskModule : Module() {
12
11
  companion object {
@@ -37,7 +36,7 @@ class BackgroundTaskModule : Module() {
37
36
  }
38
37
 
39
38
  AsyncFunction("registerTaskAsync") { taskName: String, options: Map<String, Any?> ->
40
- Log.d(TAG, "registerTaskAsync: $taskName")
39
+ Log.d(TAG, "registerTaskAsync: $taskName with options $options")
41
40
  taskManager.registerTask(taskName, BackgroundTaskConsumer::class.java, options)
42
41
  }
43
42
 
@@ -46,21 +45,12 @@ class BackgroundTaskModule : Module() {
46
45
  taskManager.unregisterTask(taskName, BackgroundTaskConsumer::class.java)
47
46
  }
48
47
 
49
- OnActivityEntersBackground {
50
- appContext.reactContext?.let {
51
- runBlocking {
52
- val appScopeKey = it.packageName
53
- BackgroundTaskScheduler.scheduleWorker(it, appScopeKey)
54
- }
55
- } ?: throw MissingContextException()
48
+ OnActivityEntersForeground {
49
+ BackgroundTaskScheduler.inForeground = true
56
50
  }
57
51
 
58
- OnActivityEntersForeground {
59
- appContext.reactContext?.let {
60
- runBlocking {
61
- BackgroundTaskScheduler.stopWorker(it)
62
- }
63
- } ?: throw MissingContextException()
52
+ OnActivityEntersBackground {
53
+ BackgroundTaskScheduler.inForeground = false
64
54
  }
65
55
  }
66
56
  }
@@ -19,6 +19,7 @@ import kotlinx.coroutines.CancellationException
19
19
  import kotlinx.coroutines.CompletableDeferred
20
20
  import kotlinx.coroutines.Dispatchers
21
21
  import kotlinx.coroutines.awaitAll
22
+ import kotlinx.coroutines.runBlocking
22
23
  import kotlinx.coroutines.withContext
23
24
  import java.time.Duration
24
25
  import java.util.concurrent.TimeUnit
@@ -39,25 +40,40 @@ object BackgroundTaskScheduler {
39
40
  // Interval
40
41
  private var intervalMinutes: Long = DEFAULT_INTERVAL_MINUTES
41
42
 
43
+ // Tracks whether in foreground
44
+ var inForeground: Boolean = false
45
+
42
46
  /**
43
47
  * Call when a task is registered
44
48
  */
45
- fun registerTask(intervalMinutes: Long) {
49
+ fun registerTask(context: Context, intervalMinutes: Long) {
46
50
  numberOfRegisteredTasksOfThisType += 1
47
51
  this.intervalMinutes = intervalMinutes
52
+
53
+ if (numberOfRegisteredTasksOfThisType == 1) {
54
+ runBlocking {
55
+ scheduleWorker(context, context.packageName)
56
+ }
57
+ }
48
58
  }
49
59
 
50
60
  /**
51
61
  * Call when a task is unregistered
52
62
  */
53
- fun unregisterTask() {
63
+ fun unregisterTask(context: Context) {
54
64
  numberOfRegisteredTasksOfThisType -= 1
65
+
66
+ if (numberOfRegisteredTasksOfThisType == 0) {
67
+ runBlocking {
68
+ stopWorker(context)
69
+ }
70
+ }
55
71
  }
56
72
 
57
73
  /**
58
74
  * Schedules the worker task to run. The worker should run periodically.
59
75
  */
60
- suspend fun scheduleWorker(context: Context, appScopeKey: String, cancelExisting: Boolean = true): Boolean {
76
+ private suspend fun scheduleWorker(context: Context, appScopeKey: String, cancelExisting: Boolean = true, overriddenIntervalMinutes: Long = intervalMinutes): Boolean {
61
77
  if (numberOfRegisteredTasksOfThisType == 0) {
62
78
  Log.d(TAG, "Will not enqueue worker. No registered tasks to run.")
63
79
  return false
@@ -68,14 +84,13 @@ object BackgroundTaskScheduler {
68
84
  stopWorker(context)
69
85
  }
70
86
 
71
- Log.d(TAG, "Enqueuing worker with identifier $WORKER_IDENTIFIER")
87
+ Log.d(TAG, "Enqueuing worker with identifier $WORKER_IDENTIFIER and '$overriddenIntervalMinutes' minutes delay.")
72
88
 
73
89
  // Build the work request
74
90
  val data = Data.Builder()
75
91
  .putString("appScopeKey", appScopeKey)
76
92
  .build()
77
93
  val constraints = Constraints.Builder()
78
- .setRequiresBatteryNotLow(true)
79
94
  .setRequiredNetworkType(NetworkType.CONNECTED)
80
95
  .build()
81
96
 
@@ -95,7 +110,7 @@ object BackgroundTaskScheduler {
95
110
  .setConstraints(constraints)
96
111
 
97
112
  // Add minimum interval here as well so that the work doesn't start immediately
98
- builder.setInitialDelay(Duration.ofMinutes(intervalMinutes))
113
+ builder.setInitialDelay(Duration.ofMinutes(overriddenIntervalMinutes))
99
114
 
100
115
  // Create work request
101
116
  val workRequest = builder.build()
@@ -144,7 +159,7 @@ object BackgroundTaskScheduler {
144
159
  /**
145
160
  * Cancels the worker task
146
161
  */
147
- suspend fun stopWorker(context: Context): Boolean {
162
+ private suspend fun stopWorker(context: Context): Boolean {
148
163
  if (!isWorkerRunning(context)) {
149
164
  return false
150
165
  }
@@ -173,7 +188,7 @@ object BackgroundTaskScheduler {
173
188
  /**
174
189
  * Runs tasks with the given appScopeKey
175
190
  */
176
- suspend fun runTasks(context: Context, appScopeKey: String): Boolean {
191
+ suspend fun runTasks(context: Context, appScopeKey: String) {
177
192
  // Get task service
178
193
  val taskService = TaskServiceProviderHelper.getTaskServiceImpl(context)
179
194
  ?: throw MissingTaskServiceException()
@@ -185,22 +200,42 @@ object BackgroundTaskScheduler {
185
200
  Log.d(TAG, "runTasks: number of consumers ${consumers.size}")
186
201
 
187
202
  if (consumers.isEmpty()) {
188
- return false
203
+ return
204
+ }
205
+
206
+ // Make sure we're in the background before running a task
207
+ if (inForeground) {
208
+ // Schedule task in an hour (or at least minimumInterval) - the app is foregrounded and
209
+ // we don't want to run anything to avoid performance issues.
210
+ Log.d(TAG, "runTasks: App is in the foreground")
211
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
212
+ scheduleWorker(context, appScopeKey, false, 60L.coerceAtMost(intervalMinutes))
213
+ Log.d(TAG, "runTasks: Scheduled new worker in $intervalMinutes minutes")
214
+ }
215
+ return
189
216
  }
190
217
 
191
218
  val tasks = consumers.filterIsInstance<BackgroundTaskConsumer>()
192
219
  .map { bgTaskConsumer ->
193
220
  Log.d(TAG, "runTasks: executing tasks for consumer of type ${bgTaskConsumer.taskType()}")
194
221
  val taskCompletion = CompletableDeferred<Unit>()
195
- bgTaskConsumer.executeTask {
196
- Log.d(TAG, "Task successfully finished")
197
- taskCompletion.complete(Unit)
222
+ try {
223
+ bgTaskConsumer.executeTask {
224
+ Log.d(TAG, "Task successfully finished")
225
+ taskCompletion.complete(Unit)
226
+ }
227
+ } catch (e: Exception) {
228
+ Log.e(TAG, "Task failed: ${e.message}")
198
229
  }
199
230
  taskCompletion
200
231
  }
201
232
  // Await all tasks to complete
202
233
  tasks.awaitAll()
203
- return true
234
+
235
+ // Schedule next task
236
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
237
+ scheduleWorker(context, appScopeKey, false)
238
+ }
204
239
  }
205
240
 
206
241
  /**
@@ -1,7 +1,6 @@
1
1
  package expo.modules.backgroundtask
2
2
 
3
3
  import android.content.Context
4
- import android.os.Build
5
4
  import android.util.Log
6
5
  import androidx.work.CoroutineWorker
7
6
  import androidx.work.Data
@@ -25,12 +24,6 @@ class BackgroundTaskWork(context: Context, params: WorkerParameters) : Coroutine
25
24
  // Run tasks async using the task service. This call will return when the task has finished
26
25
  // ie. When JS task executor has notified the task manager that it is done.
27
26
  BackgroundTaskScheduler.runTasks(applicationContext, appScopeKey)
28
- // If we are on a newer Android version we're using a One time request and need to spawn new
29
- // requests for each run (and also ask to not try to cancel the work, since we're already
30
- // finishing the work item when this function returns.
31
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
32
- BackgroundTaskScheduler.scheduleWorker(applicationContext, appScopeKey, false)
33
- }
34
27
  } catch (e: Exception) {
35
28
  // Wrap exception in Data:
36
29
  val outputData = Data.Builder()
@@ -44,8 +44,9 @@ export declare function unregisterTaskAsync(taskName: string): Promise<void>;
44
44
  /**
45
45
  * When in debug mode this function will trigger running the background tasks.
46
46
  * This function will only work for apps built in debug mode.
47
- * @todo(chrfalch): When we have a usable devtools plugin we can enable this function.
47
+ * This method is only available in development mode. It will not work in production builds.
48
48
  * @returns A promise which fulfils when the task is triggered.
49
49
  */
50
+ export declare function triggerTaskWorkerForTestingAsync(): Promise<boolean>;
50
51
  export { BackgroundTaskStatus, BackgroundTaskResult, BackgroundTaskOptions, } from './BackgroundTask.types';
51
52
  //# sourceMappingURL=BackgroundTask.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"BackgroundTask.d.ts","sourceRoot":"","sources":["../src/BackgroundTask.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAwBrF;;;;;GAKG;AACH,eAAO,MAAM,cAAc,QAAa,OAAO,CAAC,oBAAoB,CAQnE,CAAC;AAGF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,IAAI,CAAC,CA0Bf;AAGD;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CASzE;AAGD;;;;;GAKG;AAcH,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"BackgroundTask.d.ts","sourceRoot":"","sources":["../src/BackgroundTask.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAwBrF;;;;;GAKG;AACH,eAAO,MAAM,cAAc,QAAa,OAAO,CAAC,oBAAoB,CAQnE,CAAC;AAGF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,IAAI,CAAC,CA0Bf;AAGD;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CASzE;AAGD;;;;;GAKG;AACH,wBAAsB,gCAAgC,IAAI,OAAO,CAAC,OAAO,CAAC,CAUzE;AAGD,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC"}
@@ -106,20 +106,21 @@ export async function unregisterTaskAsync(taskName) {
106
106
  /**
107
107
  * When in debug mode this function will trigger running the background tasks.
108
108
  * This function will only work for apps built in debug mode.
109
- * @todo(chrfalch): When we have a usable devtools plugin we can enable this function.
109
+ * This method is only available in development mode. It will not work in production builds.
110
110
  * @returns A promise which fulfils when the task is triggered.
111
111
  */
112
- // export async function triggerTaskWorkerForTestingAsync(): Promise<boolean> {
113
- // if (__DEV__) {
114
- // if (!ExpoBackgroundTaskModule.triggerTaskWorkerForTestingAsync) {
115
- // throw new UnavailabilityError('BackgroundTask', 'triggerTaskWorkerForTestingAsync');
116
- // }
117
- // console.log('Calling triggerTaskWorkerForTestingAsync');
118
- // return await ExpoBackgroundTaskModule.triggerTaskWorkerForTestingAsync();
119
- // } else {
120
- // return Promise.resolve(false);
121
- // }
122
- // }
112
+ export async function triggerTaskWorkerForTestingAsync() {
113
+ if (__DEV__) {
114
+ if (!ExpoBackgroundTaskModule.triggerTaskWorkerForTestingAsync) {
115
+ throw new UnavailabilityError('BackgroundTask', 'triggerTaskWorkerForTestingAsync');
116
+ }
117
+ console.log('Calling triggerTaskWorkerForTestingAsync');
118
+ return await ExpoBackgroundTaskModule.triggerTaskWorkerForTestingAsync();
119
+ }
120
+ else {
121
+ return Promise.resolve(false);
122
+ }
123
+ }
123
124
  // Export types
124
125
  export { BackgroundTaskStatus, BackgroundTaskResult, } from './BackgroundTask.types';
125
126
  //# sourceMappingURL=BackgroundTask.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BackgroundTask.js","sourceRoot":"","sources":["../src/BackgroundTask.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAyB,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACrF,OAAO,wBAAwB,MAAM,4BAA4B,CAAC;AAElE,gDAAgD;AAChD,IAAI,8BAA8B,GAAG,KAAK,CAAC;AAE3C,IAAI,iBAAiB,GAAG,KAAK,CAAC;AAE9B,SAAS,SAAS,CAAC,QAAiB;IAClC,IAAI,iBAAiB,EAAE,EAAE,CAAC;QACxB,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACvB,MAAM,OAAO,GACX,gEAAgE;gBAChE,+FAA+F,CAAC;YAClG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACtB,iBAAiB,GAAG,IAAI,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC9C,MAAM,IAAI,SAAS,CAAC,wCAAwC,CAAC,CAAC;IAChE,CAAC;AACH,CAAC;AAED,cAAc;AACd;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,IAAmC,EAAE;IACtE,IAAI,CAAC,wBAAwB,CAAC,cAAc,EAAE,CAAC;QAC7C,MAAM,IAAI,mBAAmB,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC;IACpE,CAAC;IAED,OAAO,iBAAiB,EAAE;QACxB,CAAC,CAAC,oBAAoB,CAAC,UAAU;QACjC,CAAC,CAAC,wBAAwB,CAAC,cAAc,EAAE,CAAC;AAChD,CAAC,CAAC;AAEF,cAAc;AACd;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,QAAgB,EAChB,UAAiC,EAAE;IAEnC,IAAI,CAAC,wBAAwB,CAAC,iBAAiB,EAAE,CAAC;QAChD,MAAM,IAAI,mBAAmB,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CACb,SAAS,QAAQ,2FAA2F,CAC7G,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,MAAM,wBAAwB,CAAC,cAAc,EAAE,CAAC,KAAK,oBAAoB,CAAC,UAAU,EAAE,CAAC;QAC1F,IAAI,CAAC,8BAA8B,EAAE,CAAC;YACpC,MAAM,OAAO,GACX,QAAQ,CAAC,EAAE,KAAK,KAAK;gBACnB,CAAC,CAAC,mFAAmF,QAAQ,GAAG;gBAChG,CAAC,CAAC,4FAA4F,QAAQ,GAAG,CAAC;YAC9G,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACtB,8BAA8B,GAAG,IAAI,CAAC;QACxC,CAAC;QACD,OAAO;IACT,CAAC;IACD,SAAS,CAAC,QAAQ,CAAC,CAAC;IACpB,IAAI,MAAM,WAAW,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtD,OAAO;IACT,CAAC;IACD,MAAM,wBAAwB,CAAC,iBAAiB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AACtE,CAAC;AAED,cAAc;AACd;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,QAAgB;IACxD,IAAI,CAAC,wBAAwB,CAAC,mBAAmB,EAAE,CAAC;QAClD,MAAM,IAAI,mBAAmB,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,CAAC;IACzE,CAAC;IACD,SAAS,CAAC,QAAQ,CAAC,CAAC;IACpB,IAAI,CAAC,CAAC,MAAM,WAAW,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;QACzD,OAAO;IACT,CAAC;IACD,MAAM,wBAAwB,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;AAC/D,CAAC;AAED,cAAc;AACd;;;;;GAKG;AACH,+EAA+E;AAC/E,mBAAmB;AACnB,wEAAwE;AACxE,6FAA6F;AAC7F,QAAQ;AACR,+DAA+D;AAC/D,gFAAgF;AAChF,aAAa;AACb,qCAAqC;AACrC,MAAM;AACN,IAAI;AAEJ,eAAe;AACf,OAAO,EACL,oBAAoB,EACpB,oBAAoB,GAErB,MAAM,wBAAwB,CAAC","sourcesContent":["import { isRunningInExpoGo } from 'expo';\nimport { Platform, UnavailabilityError } from 'expo-modules-core';\nimport * as TaskManager from 'expo-task-manager';\n\nimport { BackgroundTaskOptions, BackgroundTaskStatus } from './BackgroundTask.types';\nimport ExpoBackgroundTaskModule from './ExpoBackgroundTaskModule';\n\n// Flag to warn about running on Apple simulator\nlet warnAboutRunningOniOSSimulator = false;\n\nlet warnedAboutExpoGo = false;\n\nfunction _validate(taskName: unknown) {\n if (isRunningInExpoGo()) {\n if (!warnedAboutExpoGo) {\n const message =\n '`Background Task` functionality is not available in Expo Go:\\n' +\n 'Please use a development build to avoid limitations. Learn more: https://expo.fyi/dev-client.';\n console.warn(message);\n warnedAboutExpoGo = true;\n }\n }\n if (!taskName || typeof taskName !== 'string') {\n throw new TypeError('`taskName` must be a non-empty string.');\n }\n}\n\n// @needsAudit\n/**\n * Returns the status for the Background Task API. On web, it always returns `BackgroundTaskStatus.Restricted`,\n * while on native platforms it returns `BackgroundTaskStatus.Available`.\n *\n * @returns A BackgroundTaskStatus enum value or `null` if not available.\n */\nexport const getStatusAsync = async (): Promise<BackgroundTaskStatus> => {\n if (!ExpoBackgroundTaskModule.getStatusAsync) {\n throw new UnavailabilityError('BackgroundTask', 'getStatusAsync');\n }\n\n return isRunningInExpoGo()\n ? BackgroundTaskStatus.Restricted\n : ExpoBackgroundTaskModule.getStatusAsync();\n};\n\n// @needsAudit\n/**\n * Registers a background task with the given name. Registered tasks are saved in persistent storage and restored once the app is initialized.\n * @param taskName Name of the task to register. The task needs to be defined first - see [`TaskManager.defineTask`](task-manager/#taskmanagerdefinetasktaskname-taskexecutor)\n * for more details.\n * @param options An object containing the background task options.\n *\n * @example\n * ```ts\n * import * as TaskManager from 'expo-task-manager';\n *\n * // Register the task outside of the component\n * TaskManager.defineTask(BACKGROUND_TASK_IDENTIFIER, () => {\n * try {\n * await AsyncStorage.setItem(LAST_TASK_DATE_KEY, Date.now().toString());\n * } catch (error) {\n * console.error('Failed to save the last fetch date', error);\n * return BackgroundTaskResult.Failed;\n * }\n * return BackgroundTaskResult.Success;\n * });\n * ```\n *\n * You can now use the `registerTaskAsync` function to register the task:\n *\n * ```ts\n * BackgroundTask.registerTaskAsync(BACKGROUND_TASK_IDENTIFIER, {});\n * ```\n */\nexport async function registerTaskAsync(\n taskName: string,\n options: BackgroundTaskOptions = {}\n): Promise<void> {\n if (!ExpoBackgroundTaskModule.registerTaskAsync) {\n throw new UnavailabilityError('BackgroundTask', 'registerTaskAsync');\n }\n if (!TaskManager.isTaskDefined(taskName)) {\n throw new Error(\n `Task '${taskName}' is not defined. You must define a task using TaskManager.defineTask before registering.`\n );\n }\n\n if ((await ExpoBackgroundTaskModule.getStatusAsync()) === BackgroundTaskStatus.Restricted) {\n if (!warnAboutRunningOniOSSimulator) {\n const message =\n Platform.OS === 'ios'\n ? `Background tasks are not supported on iOS simulators. Skipped registering task: ${taskName}.`\n : `Background tasks are not available in the current environment. Skipped registering task: ${taskName}.`;\n console.warn(message);\n warnAboutRunningOniOSSimulator = true;\n }\n return;\n }\n _validate(taskName);\n if (await TaskManager.isTaskRegisteredAsync(taskName)) {\n return;\n }\n await ExpoBackgroundTaskModule.registerTaskAsync(taskName, options);\n}\n\n// @needsAudit\n/**\n * Unregisters a background task, so the application will no longer be executing this task.\n * @param taskName Name of the task to unregister.\n * @return A promise which fulfils when the task is fully unregistered.\n */\nexport async function unregisterTaskAsync(taskName: string): Promise<void> {\n if (!ExpoBackgroundTaskModule.unregisterTaskAsync) {\n throw new UnavailabilityError('BackgroundTask', 'unregisterTaskAsync');\n }\n _validate(taskName);\n if (!(await TaskManager.isTaskRegisteredAsync(taskName))) {\n return;\n }\n await ExpoBackgroundTaskModule.unregisterTaskAsync(taskName);\n}\n\n// @needsAudit\n/**\n * When in debug mode this function will trigger running the background tasks.\n * This function will only work for apps built in debug mode.\n * @todo(chrfalch): When we have a usable devtools plugin we can enable this function.\n * @returns A promise which fulfils when the task is triggered.\n */\n// export async function triggerTaskWorkerForTestingAsync(): Promise<boolean> {\n// if (__DEV__) {\n// if (!ExpoBackgroundTaskModule.triggerTaskWorkerForTestingAsync) {\n// throw new UnavailabilityError('BackgroundTask', 'triggerTaskWorkerForTestingAsync');\n// }\n// console.log('Calling triggerTaskWorkerForTestingAsync');\n// return await ExpoBackgroundTaskModule.triggerTaskWorkerForTestingAsync();\n// } else {\n// return Promise.resolve(false);\n// }\n// }\n\n// Export types\nexport {\n BackgroundTaskStatus,\n BackgroundTaskResult,\n BackgroundTaskOptions,\n} from './BackgroundTask.types';\n"]}
1
+ {"version":3,"file":"BackgroundTask.js","sourceRoot":"","sources":["../src/BackgroundTask.ts"],"names":[],"mappings":"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","sourcesContent":["import { isRunningInExpoGo } from 'expo';\nimport { Platform, UnavailabilityError } from 'expo-modules-core';\nimport * as TaskManager from 'expo-task-manager';\n\nimport { BackgroundTaskOptions, BackgroundTaskStatus } from './BackgroundTask.types';\nimport ExpoBackgroundTaskModule from './ExpoBackgroundTaskModule';\n\n// Flag to warn about running on Apple simulator\nlet warnAboutRunningOniOSSimulator = false;\n\nlet warnedAboutExpoGo = false;\n\nfunction _validate(taskName: unknown) {\n if (isRunningInExpoGo()) {\n if (!warnedAboutExpoGo) {\n const message =\n '`Background Task` functionality is not available in Expo Go:\\n' +\n 'Please use a development build to avoid limitations. Learn more: https://expo.fyi/dev-client.';\n console.warn(message);\n warnedAboutExpoGo = true;\n }\n }\n if (!taskName || typeof taskName !== 'string') {\n throw new TypeError('`taskName` must be a non-empty string.');\n }\n}\n\n// @needsAudit\n/**\n * Returns the status for the Background Task API. On web, it always returns `BackgroundTaskStatus.Restricted`,\n * while on native platforms it returns `BackgroundTaskStatus.Available`.\n *\n * @returns A BackgroundTaskStatus enum value or `null` if not available.\n */\nexport const getStatusAsync = async (): Promise<BackgroundTaskStatus> => {\n if (!ExpoBackgroundTaskModule.getStatusAsync) {\n throw new UnavailabilityError('BackgroundTask', 'getStatusAsync');\n }\n\n return isRunningInExpoGo()\n ? BackgroundTaskStatus.Restricted\n : ExpoBackgroundTaskModule.getStatusAsync();\n};\n\n// @needsAudit\n/**\n * Registers a background task with the given name. Registered tasks are saved in persistent storage and restored once the app is initialized.\n * @param taskName Name of the task to register. The task needs to be defined first - see [`TaskManager.defineTask`](task-manager/#taskmanagerdefinetasktaskname-taskexecutor)\n * for more details.\n * @param options An object containing the background task options.\n *\n * @example\n * ```ts\n * import * as TaskManager from 'expo-task-manager';\n *\n * // Register the task outside of the component\n * TaskManager.defineTask(BACKGROUND_TASK_IDENTIFIER, () => {\n * try {\n * await AsyncStorage.setItem(LAST_TASK_DATE_KEY, Date.now().toString());\n * } catch (error) {\n * console.error('Failed to save the last fetch date', error);\n * return BackgroundTaskResult.Failed;\n * }\n * return BackgroundTaskResult.Success;\n * });\n * ```\n *\n * You can now use the `registerTaskAsync` function to register the task:\n *\n * ```ts\n * BackgroundTask.registerTaskAsync(BACKGROUND_TASK_IDENTIFIER, {});\n * ```\n */\nexport async function registerTaskAsync(\n taskName: string,\n options: BackgroundTaskOptions = {}\n): Promise<void> {\n if (!ExpoBackgroundTaskModule.registerTaskAsync) {\n throw new UnavailabilityError('BackgroundTask', 'registerTaskAsync');\n }\n if (!TaskManager.isTaskDefined(taskName)) {\n throw new Error(\n `Task '${taskName}' is not defined. You must define a task using TaskManager.defineTask before registering.`\n );\n }\n\n if ((await ExpoBackgroundTaskModule.getStatusAsync()) === BackgroundTaskStatus.Restricted) {\n if (!warnAboutRunningOniOSSimulator) {\n const message =\n Platform.OS === 'ios'\n ? `Background tasks are not supported on iOS simulators. Skipped registering task: ${taskName}.`\n : `Background tasks are not available in the current environment. Skipped registering task: ${taskName}.`;\n console.warn(message);\n warnAboutRunningOniOSSimulator = true;\n }\n return;\n }\n _validate(taskName);\n if (await TaskManager.isTaskRegisteredAsync(taskName)) {\n return;\n }\n await ExpoBackgroundTaskModule.registerTaskAsync(taskName, options);\n}\n\n// @needsAudit\n/**\n * Unregisters a background task, so the application will no longer be executing this task.\n * @param taskName Name of the task to unregister.\n * @return A promise which fulfils when the task is fully unregistered.\n */\nexport async function unregisterTaskAsync(taskName: string): Promise<void> {\n if (!ExpoBackgroundTaskModule.unregisterTaskAsync) {\n throw new UnavailabilityError('BackgroundTask', 'unregisterTaskAsync');\n }\n _validate(taskName);\n if (!(await TaskManager.isTaskRegisteredAsync(taskName))) {\n return;\n }\n await ExpoBackgroundTaskModule.unregisterTaskAsync(taskName);\n}\n\n// @needsAudit\n/**\n * When in debug mode this function will trigger running the background tasks.\n * This function will only work for apps built in debug mode.\n * This method is only available in development mode. It will not work in production builds.\n * @returns A promise which fulfils when the task is triggered.\n */\nexport async function triggerTaskWorkerForTestingAsync(): Promise<boolean> {\n if (__DEV__) {\n if (!ExpoBackgroundTaskModule.triggerTaskWorkerForTestingAsync) {\n throw new UnavailabilityError('BackgroundTask', 'triggerTaskWorkerForTestingAsync');\n }\n console.log('Calling triggerTaskWorkerForTestingAsync');\n return await ExpoBackgroundTaskModule.triggerTaskWorkerForTestingAsync();\n } else {\n return Promise.resolve(false);\n }\n}\n\n// Export types\nexport {\n BackgroundTaskStatus,\n BackgroundTaskResult,\n BackgroundTaskOptions,\n} from './BackgroundTask.types';\n"]}
@@ -32,9 +32,11 @@ export type BackgroundTaskOptions = {
32
32
  * Inexact interval in minutes between subsequent repeats of the background tasks. The final
33
33
  * interval may differ from the specified one to minimize wakeups and battery usage.
34
34
  * - Defaults to once every 12 hours (The minimum interval is 15 minutes)
35
- * - On iOS, the system determines the interval for background task execution,
36
- * but will wait until the specified minimum interval has elapsed before starting a task.
37
- * @platform android
35
+ * - The system controls the background task execution interval and treats the
36
+ * specified value as a minimum delay. Tasks won't run exactly on schedule. On iOS, short
37
+ * intervals are often ignored—the system typically runs background tasks during
38
+ * specific windows, such as overnight.
39
+ *
38
40
  */
39
41
  minimumInterval?: number;
40
42
  };
@@ -1 +1 @@
1
- {"version":3,"file":"BackgroundTask.types.d.ts","sourceRoot":"","sources":["../src/BackgroundTask.types.ts"],"names":[],"mappings":"AACA;;GAEG;AACH,oBAAY,oBAAoB;IAC9B;;OAEG;IACH,UAAU,IAAI;IACd;;OAEG;IACH,SAAS,IAAI;CACd;AAGD;;GAEG;AACH,oBAAY,oBAAoB;IAC9B;;OAEG;IACH,OAAO,IAAI;IACX;;OAEG;IACH,MAAM,IAAI;CACX;AAGD;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC"}
1
+ {"version":3,"file":"BackgroundTask.types.d.ts","sourceRoot":"","sources":["../src/BackgroundTask.types.ts"],"names":[],"mappings":"AACA;;GAEG;AACH,oBAAY,oBAAoB;IAC9B;;OAEG;IACH,UAAU,IAAI;IACd;;OAEG;IACH,SAAS,IAAI;CACd;AAGD;;GAEG;AACH,oBAAY,oBAAoB;IAC9B;;OAEG;IACH,OAAO,IAAI;IACX;;OAEG;IACH,MAAM,IAAI;CACX;AAGD;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"BackgroundTask.types.js","sourceRoot":"","sources":["../src/BackgroundTask.types.ts"],"names":[],"mappings":"AAAA,cAAc;AACd;;GAEG;AACH,MAAM,CAAN,IAAY,oBASX;AATD,WAAY,oBAAoB;IAC9B;;OAEG;IACH,2EAAc,CAAA;IACd;;OAEG;IACH,yEAAa,CAAA;AACf,CAAC,EATW,oBAAoB,KAApB,oBAAoB,QAS/B;AAED,cAAc;AACd;;GAEG;AACH,MAAM,CAAN,IAAY,oBASX;AATD,WAAY,oBAAoB;IAC9B;;OAEG;IACH,qEAAW,CAAA;IACX;;OAEG;IACH,mEAAU,CAAA;AACZ,CAAC,EATW,oBAAoB,KAApB,oBAAoB,QAS/B","sourcesContent":["// @needsAudit\n/**\n * Availability status for background tasks\n */\nexport enum BackgroundTaskStatus {\n /**\n * Background tasks are unavailable.\n */\n Restricted = 1,\n /**\n * Background tasks are available for the app.\n */\n Available = 2,\n}\n\n// @needsAudit\n/**\n * Return value for background tasks.\n */\nexport enum BackgroundTaskResult {\n /**\n * The task finished successfully.\n */\n Success = 1,\n /**\n * The task failed.\n */\n Failed = 2,\n}\n\n// @needsAudit\n/**\n * Options for registering a background task\n */\nexport type BackgroundTaskOptions = {\n /**\n * Inexact interval in minutes between subsequent repeats of the background tasks. The final\n * interval may differ from the specified one to minimize wakeups and battery usage.\n * - Defaults to once every 12 hours (The minimum interval is 15 minutes)\n * - On iOS, the system determines the interval for background task execution,\n * but will wait until the specified minimum interval has elapsed before starting a task.\n * @platform android\n */\n minimumInterval?: number;\n};\n"]}
1
+ {"version":3,"file":"BackgroundTask.types.js","sourceRoot":"","sources":["../src/BackgroundTask.types.ts"],"names":[],"mappings":"AAAA,cAAc;AACd;;GAEG;AACH,MAAM,CAAN,IAAY,oBASX;AATD,WAAY,oBAAoB;IAC9B;;OAEG;IACH,2EAAc,CAAA;IACd;;OAEG;IACH,yEAAa,CAAA;AACf,CAAC,EATW,oBAAoB,KAApB,oBAAoB,QAS/B;AAED,cAAc;AACd;;GAEG;AACH,MAAM,CAAN,IAAY,oBASX;AATD,WAAY,oBAAoB;IAC9B;;OAEG;IACH,qEAAW,CAAA;IACX;;OAEG;IACH,mEAAU,CAAA;AACZ,CAAC,EATW,oBAAoB,KAApB,oBAAoB,QAS/B","sourcesContent":["// @needsAudit\n/**\n * Availability status for background tasks\n */\nexport enum BackgroundTaskStatus {\n /**\n * Background tasks are unavailable.\n */\n Restricted = 1,\n /**\n * Background tasks are available for the app.\n */\n Available = 2,\n}\n\n// @needsAudit\n/**\n * Return value for background tasks.\n */\nexport enum BackgroundTaskResult {\n /**\n * The task finished successfully.\n */\n Success = 1,\n /**\n * The task failed.\n */\n Failed = 2,\n}\n\n// @needsAudit\n/**\n * Options for registering a background task\n */\nexport type BackgroundTaskOptions = {\n /**\n * Inexact interval in minutes between subsequent repeats of the background tasks. The final\n * interval may differ from the specified one to minimize wakeups and battery usage.\n * - Defaults to once every 12 hours (The minimum interval is 15 minutes)\n * - The system controls the background task execution interval and treats the\n * specified value as a minimum delay. Tasks won't run exactly on schedule. On iOS, short\n * intervals are often ignored—the system typically runs background tasks during\n * specific windows, such as overnight.\n *\n */\n minimumInterval?: number;\n};\n"]}
@@ -5,12 +5,6 @@
5
5
  "modules": ["BackgroundTaskModule"]
6
6
  },
7
7
  "android": {
8
- "modules": ["expo.modules.backgroundtask.BackgroundTaskModule"],
9
- "publication": {
10
- "groupId": "host.exp.exponent",
11
- "artifactId": "expo.modules.backgroundtask",
12
- "version": "0.2.6",
13
- "repository": "local-maven-repo"
14
- }
8
+ "modules": ["expo.modules.backgroundtask.BackgroundTaskModule"]
15
9
  }
16
10
  }
@@ -12,11 +12,7 @@ public class BackgroundTaskModule: Module {
12
12
  }
13
13
 
14
14
  AsyncFunction("triggerTaskWorkerForTestingAsync") {
15
- if await BackgroundTaskScheduler.isWorkerRunning() {
16
- BackgroundTaskDebugHelper.triggerBackgroundTaskTest()
17
- return true
18
- }
19
- return false
15
+ BackgroundTaskDebugHelper.triggerBackgroundTaskTest()
20
16
  }
21
17
 
22
18
  AsyncFunction("registerTaskAsync") { (name: String, options: [String: Any]) in
@@ -56,23 +52,5 @@ public class BackgroundTaskModule: Module {
56
52
  return BackgroundTaskScheduler.supportsBackgroundTasks() ?
57
53
  BackgroundTaskStatus.available : .restricted
58
54
  }
59
-
60
- OnAppEntersBackground {
61
- Task {
62
- // Try start worker when app enters background
63
- do {
64
- try await BackgroundTaskScheduler.tryScheduleWorker()
65
- } catch {
66
- log.error("Could not schedule the worker: \(error.localizedDescription)")
67
- }
68
- }
69
- }
70
-
71
- OnAppEntersForeground {
72
- Task {
73
- // When entering foreground we'll stop the worker
74
- await BackgroundTaskScheduler.stopWorker()
75
- }
76
- }
77
55
  }
78
56
  }
@@ -21,6 +21,12 @@ public class BackgroundTaskScheduler {
21
21
  intervalSeconds = Double(minutes) * 60
22
22
  }
23
23
  numberOfRegisteredTasksOfThisType += 1
24
+
25
+ if numberOfRegisteredTasksOfThisType == 1 {
26
+ Task {
27
+ try await tryScheduleWorker()
28
+ }
29
+ }
24
30
  }
25
31
 
26
32
  /**
@@ -28,6 +34,11 @@ public class BackgroundTaskScheduler {
28
34
  */
29
35
  public static func didUnregisterTask() {
30
36
  numberOfRegisteredTasksOfThisType -= 1
37
+ if numberOfRegisteredTasksOfThisType == 0 {
38
+ Task {
39
+ await stopWorker()
40
+ }
41
+ }
31
42
  }
32
43
 
33
44
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-background-task",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "Expo Android and iOS module for Background Task APIs",
5
5
  "main": "build/BackgroundTask.js",
6
6
  "types": "build/BackgroundTask.d.ts",
@@ -35,10 +35,10 @@
35
35
  "expo-task-manager": "~13.1.5"
36
36
  },
37
37
  "devDependencies": {
38
- "expo-module-scripts": "^4.1.6"
38
+ "expo-module-scripts": "^4.1.7"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "expo": "*"
42
42
  },
43
- "gitHead": "84355076bc31a356aa3d23257f387f221885f53d"
43
+ "gitHead": "49c9d53cf0a9fc8179d1c8f5268beadd141f70ca"
44
44
  }
@@ -123,20 +123,20 @@ export async function unregisterTaskAsync(taskName: string): Promise<void> {
123
123
  /**
124
124
  * When in debug mode this function will trigger running the background tasks.
125
125
  * This function will only work for apps built in debug mode.
126
- * @todo(chrfalch): When we have a usable devtools plugin we can enable this function.
126
+ * This method is only available in development mode. It will not work in production builds.
127
127
  * @returns A promise which fulfils when the task is triggered.
128
128
  */
129
- // export async function triggerTaskWorkerForTestingAsync(): Promise<boolean> {
130
- // if (__DEV__) {
131
- // if (!ExpoBackgroundTaskModule.triggerTaskWorkerForTestingAsync) {
132
- // throw new UnavailabilityError('BackgroundTask', 'triggerTaskWorkerForTestingAsync');
133
- // }
134
- // console.log('Calling triggerTaskWorkerForTestingAsync');
135
- // return await ExpoBackgroundTaskModule.triggerTaskWorkerForTestingAsync();
136
- // } else {
137
- // return Promise.resolve(false);
138
- // }
139
- // }
129
+ export async function triggerTaskWorkerForTestingAsync(): Promise<boolean> {
130
+ if (__DEV__) {
131
+ if (!ExpoBackgroundTaskModule.triggerTaskWorkerForTestingAsync) {
132
+ throw new UnavailabilityError('BackgroundTask', 'triggerTaskWorkerForTestingAsync');
133
+ }
134
+ console.log('Calling triggerTaskWorkerForTestingAsync');
135
+ return await ExpoBackgroundTaskModule.triggerTaskWorkerForTestingAsync();
136
+ } else {
137
+ return Promise.resolve(false);
138
+ }
139
+ }
140
140
 
141
141
  // Export types
142
142
  export {
@@ -37,9 +37,11 @@ export type BackgroundTaskOptions = {
37
37
  * Inexact interval in minutes between subsequent repeats of the background tasks. The final
38
38
  * interval may differ from the specified one to minimize wakeups and battery usage.
39
39
  * - Defaults to once every 12 hours (The minimum interval is 15 minutes)
40
- * - On iOS, the system determines the interval for background task execution,
41
- * but will wait until the specified minimum interval has elapsed before starting a task.
42
- * @platform android
40
+ * - The system controls the background task execution interval and treats the
41
+ * specified value as a minimum delay. Tasks won't run exactly on schedule. On iOS, short
42
+ * intervals are often ignored—the system typically runs background tasks during
43
+ * specific windows, such as overnight.
44
+ *
43
45
  */
44
46
  minimumInterval?: number;
45
47
  };
@@ -1 +0,0 @@
1
- 4019bc874cc09d9187352e03c4f54941c7abd91e4a3d8b41c2aaf351dd7ba28e
@@ -1 +0,0 @@
1
- 558f8112433c958b3ce00edac1b1e08835137759aca7f9344968661df70dccbaffb9a193a2a8f186b193edb6e59d0e94021a69455a5f04f6b5495a155ba7560f
@@ -1 +0,0 @@
1
- cbc6bb1d4a80dac949caf56fea16e50d38c9a5a4a690a2f6a5bf04cd929fbd73
@@ -1 +0,0 @@
1
- 176311633c2d7c17756447ddc521a4d6dd6ee13adb6862150517290b87b7ed89048e5d0d73b64309ea4240bb1edb2d79b4d35b61069b2eb6853689a4c185d6fd
@@ -1,98 +0,0 @@
1
- {
2
- "formatVersion": "1.1",
3
- "component": {
4
- "group": "host.exp.exponent",
5
- "module": "expo.modules.backgroundtask",
6
- "version": "0.2.6",
7
- "attributes": {
8
- "org.gradle.status": "release"
9
- }
10
- },
11
- "createdBy": {
12
- "gradle": {
13
- "version": "8.13"
14
- }
15
- },
16
- "variants": [
17
- {
18
- "name": "releaseVariantReleaseApiPublication",
19
- "attributes": {
20
- "org.gradle.category": "library",
21
- "org.gradle.dependency.bundling": "external",
22
- "org.gradle.libraryelements": "aar",
23
- "org.gradle.usage": "java-api"
24
- },
25
- "files": [
26
- {
27
- "name": "expo.modules.backgroundtask-0.2.6.aar",
28
- "url": "expo.modules.backgroundtask-0.2.6.aar",
29
- "size": 47827,
30
- "sha512": "176311633c2d7c17756447ddc521a4d6dd6ee13adb6862150517290b87b7ed89048e5d0d73b64309ea4240bb1edb2d79b4d35b61069b2eb6853689a4c185d6fd",
31
- "sha256": "cbc6bb1d4a80dac949caf56fea16e50d38c9a5a4a690a2f6a5bf04cd929fbd73",
32
- "sha1": "d4e79935b62afcaf84d57b95f256df6a41586bfa",
33
- "md5": "e0acabbb1e698252139204a38916e1de"
34
- }
35
- ]
36
- },
37
- {
38
- "name": "releaseVariantReleaseRuntimePublication",
39
- "attributes": {
40
- "org.gradle.category": "library",
41
- "org.gradle.dependency.bundling": "external",
42
- "org.gradle.libraryelements": "aar",
43
- "org.gradle.usage": "java-runtime"
44
- },
45
- "dependencies": [
46
- {
47
- "group": "org.jetbrains.kotlin",
48
- "module": "kotlin-stdlib-jdk7",
49
- "version": {
50
- "requires": "2.0.21"
51
- }
52
- },
53
- {
54
- "group": "androidx.work",
55
- "module": "work-runtime-ktx",
56
- "version": {
57
- "requires": "2.9.1"
58
- }
59
- },
60
- {
61
- "group": "com.facebook.react",
62
- "module": "react-android"
63
- }
64
- ],
65
- "files": [
66
- {
67
- "name": "expo.modules.backgroundtask-0.2.6.aar",
68
- "url": "expo.modules.backgroundtask-0.2.6.aar",
69
- "size": 47827,
70
- "sha512": "176311633c2d7c17756447ddc521a4d6dd6ee13adb6862150517290b87b7ed89048e5d0d73b64309ea4240bb1edb2d79b4d35b61069b2eb6853689a4c185d6fd",
71
- "sha256": "cbc6bb1d4a80dac949caf56fea16e50d38c9a5a4a690a2f6a5bf04cd929fbd73",
72
- "sha1": "d4e79935b62afcaf84d57b95f256df6a41586bfa",
73
- "md5": "e0acabbb1e698252139204a38916e1de"
74
- }
75
- ]
76
- },
77
- {
78
- "name": "releaseVariantReleaseSourcePublication",
79
- "attributes": {
80
- "org.gradle.category": "documentation",
81
- "org.gradle.dependency.bundling": "external",
82
- "org.gradle.docstype": "sources",
83
- "org.gradle.usage": "java-runtime"
84
- },
85
- "files": [
86
- {
87
- "name": "expo.modules.backgroundtask-0.2.6-sources.jar",
88
- "url": "expo.modules.backgroundtask-0.2.6-sources.jar",
89
- "size": 6743,
90
- "sha512": "558f8112433c958b3ce00edac1b1e08835137759aca7f9344968661df70dccbaffb9a193a2a8f186b193edb6e59d0e94021a69455a5f04f6b5495a155ba7560f",
91
- "sha256": "4019bc874cc09d9187352e03c4f54941c7abd91e4a3d8b41c2aaf351dd7ba28e",
92
- "sha1": "6915c923122c872b1efb67841662515629f6df68",
93
- "md5": "5f6622176ce030ca75524a6962204d5f"
94
- }
95
- ]
96
- }
97
- ]
98
- }
@@ -1 +0,0 @@
1
- 1070ab1cece5ccfa65521802fb44a46353002ffa8335c2ce1ddb5e288d37cc73
@@ -1 +0,0 @@
1
- 88f4a2939e19813f4703963fddbe4e2428cd446c343b9c83f50f5564117d0b244b30a713885757a3fc057e7256da927e96de75c5ec957483fa26a3e384a7060a
@@ -1,46 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
3
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
4
- <!-- This module was also published with a richer model, Gradle metadata, -->
5
- <!-- which should be used instead. Do not delete the following line which -->
6
- <!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
7
- <!-- that they should prefer consuming it instead. -->
8
- <!-- do_not_remove: published-with-gradle-metadata -->
9
- <modelVersion>4.0.0</modelVersion>
10
- <groupId>host.exp.exponent</groupId>
11
- <artifactId>expo.modules.backgroundtask</artifactId>
12
- <version>0.2.6</version>
13
- <packaging>aar</packaging>
14
- <name>expo.modules.backgroundtask</name>
15
- <url>https://github.com/expo/expo</url>
16
- <licenses>
17
- <license>
18
- <name>MIT License</name>
19
- <url>https://github.com/expo/expo/blob/main/LICENSE</url>
20
- </license>
21
- </licenses>
22
- <scm>
23
- <connection>https://github.com/expo/expo.git</connection>
24
- <developerConnection>https://github.com/expo/expo.git</developerConnection>
25
- <url>https://github.com/expo/expo</url>
26
- </scm>
27
- <dependencies>
28
- <dependency>
29
- <groupId>org.jetbrains.kotlin</groupId>
30
- <artifactId>kotlin-stdlib-jdk7</artifactId>
31
- <version>2.0.21</version>
32
- <scope>runtime</scope>
33
- </dependency>
34
- <dependency>
35
- <groupId>androidx.work</groupId>
36
- <artifactId>work-runtime-ktx</artifactId>
37
- <version>2.9.1</version>
38
- <scope>runtime</scope>
39
- </dependency>
40
- <dependency>
41
- <groupId>com.facebook.react</groupId>
42
- <artifactId>react-android</artifactId>
43
- <scope>runtime</scope>
44
- </dependency>
45
- </dependencies>
46
- </project>
@@ -1 +0,0 @@
1
- e6c998b29f76c61123792526727f3a28e870476ca1ed14cc2837a380d38dcf19
@@ -1 +0,0 @@
1
- 34d80cb85240d24e0773d0e96155065849f218b39740647103c10295033aeec90ceb0c9f86cc0d180d34e24dfbe59b975741d1b15bcdb40cc22c9c8f7283cd8e
@@ -1,13 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <metadata>
3
- <groupId>host.exp.exponent</groupId>
4
- <artifactId>expo.modules.backgroundtask</artifactId>
5
- <versioning>
6
- <latest>0.2.6</latest>
7
- <release>0.2.6</release>
8
- <versions>
9
- <version>0.2.6</version>
10
- </versions>
11
- <lastUpdated>20250430211459</lastUpdated>
12
- </versioning>
13
- </metadata>
@@ -1 +0,0 @@
1
- d124045fdb9bab038e1583b22f18de1f
@@ -1 +0,0 @@
1
- 4c460dd9b460b2f0772988a706830108a6aa56a1
@@ -1 +0,0 @@
1
- 1e386862747f3520f4ba51a9bab938dfbdb638d041f1a48c15cf05f4f81ce540
@@ -1 +0,0 @@
1
- 80e5727a10efbe6c2789d0e67de8b1584bc8ce9211638f76082d9b36f80079e176e44784ca79eb0fe525d19fc50f1d67a4d9ab2ea24841844f687094476475e5