@zykeco/expo-background-task 1.0.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 (49) hide show
  1. package/.eslintrc.js +2 -0
  2. package/CHANGELOG.md +185 -0
  3. package/README.md +115 -0
  4. package/android/build.gradle +21 -0
  5. package/android/proguard-rules.pro +1 -0
  6. package/android/src/main/AndroidManifest.xml +3 -0
  7. package/android/src/main/java/expo/modules/backgroundtask/BackgroundTaskConsumer.kt +60 -0
  8. package/android/src/main/java/expo/modules/backgroundtask/BackgroundTaskExceptions.kt +13 -0
  9. package/android/src/main/java/expo/modules/backgroundtask/BackgroundTaskModule.kt +56 -0
  10. package/android/src/main/java/expo/modules/backgroundtask/BackgroundTaskScheduler.kt +294 -0
  11. package/android/src/main/java/expo/modules/backgroundtask/BackgroundTaskWork.kt +38 -0
  12. package/app.plugin.js +1 -0
  13. package/build/BackgroundTask.d.ts +63 -0
  14. package/build/BackgroundTask.d.ts.map +1 -0
  15. package/build/BackgroundTask.js +141 -0
  16. package/build/BackgroundTask.js.map +1 -0
  17. package/build/BackgroundTask.types.d.ts +71 -0
  18. package/build/BackgroundTask.types.d.ts.map +1 -0
  19. package/build/BackgroundTask.types.js +31 -0
  20. package/build/BackgroundTask.types.js.map +1 -0
  21. package/build/ExpoBackgroundTaskModule.d.ts +14 -0
  22. package/build/ExpoBackgroundTaskModule.d.ts.map +1 -0
  23. package/build/ExpoBackgroundTaskModule.js +3 -0
  24. package/build/ExpoBackgroundTaskModule.js.map +1 -0
  25. package/build/ExpoBackgroundTaskModule.web.d.ts +6 -0
  26. package/build/ExpoBackgroundTaskModule.web.d.ts.map +1 -0
  27. package/build/ExpoBackgroundTaskModule.web.js +7 -0
  28. package/build/ExpoBackgroundTaskModule.web.js.map +1 -0
  29. package/expo-module.config.json +10 -0
  30. package/ios/BackgorundTaskExceptions.swift +48 -0
  31. package/ios/BackgroundTaskAppDelegate.swift +74 -0
  32. package/ios/BackgroundTaskConstants.swift +13 -0
  33. package/ios/BackgroundTaskConsumer.swift +62 -0
  34. package/ios/BackgroundTaskDebugHelper.swift +21 -0
  35. package/ios/BackgroundTaskModule.swift +80 -0
  36. package/ios/BackgroundTaskRecords.swift +12 -0
  37. package/ios/BackgroundTaskScheduler.swift +206 -0
  38. package/ios/ExpoBackgroundTask.podspec +33 -0
  39. package/package.json +42 -0
  40. package/plugin/build/withBackgroundTask.d.ts +3 -0
  41. package/plugin/build/withBackgroundTask.js +32 -0
  42. package/plugin/src/withBackgroundTask.ts +39 -0
  43. package/plugin/tsconfig.json +9 -0
  44. package/plugin/tsconfig.tsbuildinfo +1 -0
  45. package/src/BackgroundTask.ts +162 -0
  46. package/src/BackgroundTask.types.ts +75 -0
  47. package/src/ExpoBackgroundTaskModule.ts +16 -0
  48. package/src/ExpoBackgroundTaskModule.web.ts +7 -0
  49. package/tsconfig.json +9 -0
package/.eslintrc.js ADDED
@@ -0,0 +1,2 @@
1
+ // @generated by expo-module-scripts
2
+ module.exports = require('expo-module-scripts/eslintrc.base.js');
package/CHANGELOG.md ADDED
@@ -0,0 +1,185 @@
1
+ # Changelog
2
+
3
+ ## Unpublished
4
+
5
+ ### 🛠 Breaking changes
6
+
7
+ ### 🎉 New features
8
+
9
+ ### 🐛 Bug fixes
10
+
11
+ ### 💡 Others
12
+
13
+ ## 55.0.8 — 2026-02-25
14
+
15
+ _This version does not introduce any user-facing changes._
16
+
17
+ ## 55.0.7 — 2026-02-20
18
+
19
+ _This version does not introduce any user-facing changes._
20
+
21
+ ## 55.0.6 — 2026-02-16
22
+
23
+ _This version does not introduce any user-facing changes._
24
+
25
+ ## 55.0.5 — 2026-02-08
26
+
27
+ _This version does not introduce any user-facing changes._
28
+
29
+ ## 55.0.4 — 2026-02-03
30
+
31
+ _This version does not introduce any user-facing changes._
32
+
33
+ ## 55.0.3 — 2026-01-27
34
+
35
+ _This version does not introduce any user-facing changes._
36
+
37
+ ## 55.0.2 — 2026-01-26
38
+
39
+ _This version does not introduce any user-facing changes._
40
+
41
+ ## 55.0.1 — 2026-01-22
42
+
43
+ _This version does not introduce any user-facing changes._
44
+
45
+ ## 55.0.0 — 2026-01-21
46
+
47
+ _This version does not introduce any user-facing changes._
48
+
49
+ ## 1.0.10 - 2025-12-05
50
+
51
+ _This version does not introduce any user-facing changes._
52
+
53
+ ## 1.0.9 - 2025-11-17
54
+
55
+ _This version does not introduce any user-facing changes._
56
+
57
+ ## 1.0.8 - 2025-09-18
58
+
59
+ ### 🎉 New features
60
+
61
+ - [iOS] Added support for task expiration handler on iOS. ([#39773](https://github.com/expo/expo/pull/39773) by [@chrfalch](https://github.com/chrfalch))
62
+
63
+ ### 🐛 Bug fixes
64
+
65
+ - [iOS] Fixed timing issue where background task iOS handler was not registered when we try to schedule a task. ([#39769](https://github.com/expo/expo/pull/39769) by [@chrfalch](https://github.com/chrfalch))
66
+
67
+ ## 1.0.7 — 2025-09-11
68
+
69
+ _This version does not introduce any user-facing changes._
70
+
71
+ ## 1.0.6 — 2025-09-02
72
+
73
+ _This version does not introduce any user-facing changes._
74
+
75
+ ## 1.0.5 — 2025-08-31
76
+
77
+ _This version does not introduce any user-facing changes._
78
+
79
+ ## 1.0.4 — 2025-08-27
80
+
81
+ _This version does not introduce any user-facing changes._
82
+
83
+ ## 1.0.3 — 2025-08-25
84
+
85
+ _This version does not introduce any user-facing changes._
86
+
87
+ ## 1.0.2 — 2025-08-16
88
+
89
+ _This version does not introduce any user-facing changes._
90
+
91
+ ## 1.0.1 — 2025-08-15
92
+
93
+ _This version does not introduce any user-facing changes._
94
+
95
+ ## 1.0.0 — 2025-08-13
96
+
97
+ ### 🐛 Bug fixes
98
+
99
+ - [iOS] Rethrow obj-c exception as swift error. ([#38714](https://github.com/expo/expo/pull/38714) by [@jakex7](https://github.com/jakex7))
100
+
101
+ ## 0.2.8 - 2025-07-01
102
+
103
+ ### 💡 Others
104
+
105
+ - Remove "Please" from warnings and errors ([#36862](https://github.com/expo/expo/pull/36862) by [@brentvatne](https://github.com/brentvatne))
106
+
107
+ ## 0.2.7 — 2025-05-08
108
+
109
+ ### 💡 Others
110
+
111
+ - 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))
112
+ - 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))
113
+
114
+ ## 0.2.6 — 2025-04-30
115
+
116
+ _This version does not introduce any user-facing changes._
117
+
118
+ ## 0.2.5 — 2025-04-25
119
+
120
+ ### 💡 Others
121
+
122
+ - Removed throwing an exception if registerTaskAsync/unregisterTaskAsync is called on a task that is already registered/unregistered ([#36393](https://github.com/expo/expo/pull/36393) by [@chrfalch](https://github.com/chrfalch))
123
+
124
+ ## 0.2.4 — 2025-04-14
125
+
126
+ _This version does not introduce any user-facing changes._
127
+
128
+ ## 0.2.3 — 2025-04-11
129
+
130
+ ### 💡 Others
131
+
132
+ - Added warning about Background Tasks not being supported in Expo Go ([#36063](https://github.com/expo/expo/pull/36063) by [@chrfalch](https://github.com/chrfalch))
133
+
134
+ ## 0.2.2 — 2025-04-09
135
+
136
+ _This version does not introduce any user-facing changes._
137
+
138
+ ## 0.2.1 — 2025-04-08
139
+
140
+ ### 🐛 Bug fixes
141
+
142
+ - [android] added expo-background-task to Expo Go's configuration ([#36000](https://github.com/expo/expo/pull/36000) by [@chrfalch](https://github.com/chrfalch))
143
+
144
+ ## 0.2.0 — 2025-04-04
145
+
146
+ _This version does not introduce any user-facing changes._
147
+
148
+ ## 0.1.4 - 2025-04-02
149
+
150
+ ### 🐛 Bug fixes
151
+
152
+ - [Android] added proguard rules for background-task consumer ([#35816](https://github.com/expo/expo/pull/35816) by [@chrfalch](https://github.com/chrfalch))
153
+
154
+ ### 💡 Others
155
+
156
+ - added error handling when registering/unregistering invalid tasks with the TaskManager. ([#35734](https://github.com/expo/expo/pull/35734) by [@chrfalch](https://github.com/chrfalch))
157
+
158
+ ## 0.1.3 - 2025-03-14
159
+
160
+ ### 💡 Others
161
+
162
+ - added throwing an exception if registerTask is run on an iOS Simulator or a device without background modes enabled ([#35350](https://github.com/expo/expo/pull/35350) by [@chrfalch](https://github.com/chrfalch))
163
+ - [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))
164
+
165
+ ## 0.1.2 - 2025-02-14
166
+
167
+ _This version does not introduce any user-facing changes._
168
+
169
+ ## 0.1.1 - 2025-01-31
170
+
171
+ ### 💡 Others
172
+
173
+ - [Android] Started using expo modules gradle plugin. ([#34431](https://github.com/expo/expo/pull/34431) by [@chrfalch](https://github.com/chrfalch))
174
+
175
+ ## 0.0.1 — 2025-01-21
176
+
177
+ ### 💡 Others
178
+
179
+ - Update README description
180
+
181
+ ## 0.0.0 — 2025-01-21
182
+
183
+ ### 🎉 New features
184
+
185
+ - Added expo-background-task package ([#33438](https://github.com/expo/expo/pull/33438) by [@chrfalch](https://github.com/chrfalch))
package/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # expo-background-task
2
+
3
+ Expo Android and iOS module for Background Task APIs
4
+
5
+ # API documentation
6
+
7
+ - [Documentation for the latest stable release](https://docs.expo.dev/versions/latest/sdk/background-task/)
8
+ - [Documentation for the main branch](https://docs.expo.dev/versions/unversioned/sdk/background-task/)
9
+
10
+ # Installation in managed Expo projects
11
+
12
+ For [managed](https://docs.expo.dev/archive/managed-vs-bare/) Expo projects, please follow the installation instructions in the [API documentation for the latest stable release](https://docs.expo.dev/versions/latest/sdk/background-task/).
13
+
14
+ # Installation in bare React Native projects
15
+
16
+ For bare React Native projects, you must ensure that you have [installed and configured the `expo` package](https://docs.expo.dev/bare/installing-expo-modules/) before continuing.
17
+
18
+ ### Add the package to your npm dependencies
19
+
20
+ ```
21
+ npx expo install expo-background-task
22
+ ```
23
+
24
+ ### Configure for Android
25
+
26
+ No additional set up necessary.
27
+
28
+ ### Configure for iOS
29
+
30
+ Run `npx pod-install` after installing the npm package.
31
+
32
+ In order to use `BackgroundTask` API in standalone, detached and bare apps on iOS, your app has to include the background task identifier in the `Info.plist` file. You can do this by adding the following XML snippet to your `Info.plist` file:
33
+
34
+ ```xml
35
+ <key>BGTaskSchedulerPermittedIdentifiers</key>
36
+ <array>
37
+ <string>com.expo.modules.backgroundtask.processing</string>
38
+ </array>
39
+ ```
40
+
41
+ # iOS Task Types
42
+
43
+ On iOS, background tasks are powered by Apple's BGTaskScheduler framework, which offers two distinct task types. You can choose between them using the `iosTaskType` option.
44
+
45
+ ## `'refresh'` (default)
46
+
47
+ Uses `BGAppRefreshTaskRequest`. This is the recommended choice for most apps.
48
+
49
+ ```ts
50
+ await BackgroundTask.registerTaskAsync('myTask', {
51
+ minimumInterval: 15, // minutes
52
+ // iosTaskType: 'refresh', — this is the default, no need to specify
53
+ });
54
+ ```
55
+
56
+ **When to use:**
57
+ - Periodic content syncs (e.g. fetching new messages, updating a feed)
58
+ - Lightweight data updates that complete quickly
59
+ - Any task that should run frequently in the background
60
+
61
+ **Characteristics:**
62
+ - Aggressive scheduling — iOS typically runs these every ~15–30 minutes when conditions allow
63
+ - ~30 second execution limit
64
+ - Only supports `earliestBeginDate` (via `minimumInterval`) — no network/power constraints
65
+ - Requires `fetch` in `UIBackgroundModes` (added automatically by the config plugin)
66
+
67
+ ## `'processing'`
68
+
69
+ Uses `BGProcessingTaskRequest`. Use this for heavy, deferrable work.
70
+
71
+ ```ts
72
+ await BackgroundTask.registerTaskAsync('heavyTask', {
73
+ minimumInterval: 60,
74
+ iosTaskType: 'processing',
75
+ requiresNetworkConnectivity: true,
76
+ requiresExternalPower: false,
77
+ });
78
+ ```
79
+
80
+ **When to use:**
81
+ - Large database migrations or cleanup
82
+ - ML model training or inference
83
+ - Bulk data sync or media processing
84
+ - Any work that takes more than 30 seconds and can be deferred
85
+
86
+ **Characteristics:**
87
+ - iOS defers execution at its own discretion (hours to days)
88
+ - Several minutes of execution time allowed
89
+ - Supports `requiresNetworkConnectivity` and `requiresExternalPower` constraints
90
+ - Requires `processing` in `UIBackgroundModes` (added automatically by the config plugin)
91
+
92
+ ## Quick comparison
93
+
94
+ | | `'refresh'` | `'processing'` |
95
+ |---|---|---|
96
+ | **Scheduling** | Aggressive (~15–30 min) | Deferred (hours/days) |
97
+ | **Execution limit** | ~30 seconds | Several minutes |
98
+ | **Best for** | Periodic syncs, content updates | Heavy work, migrations, ML |
99
+ | **Network constraint** | Not supported | Supported |
100
+ | **External power constraint** | Not supported | Supported |
101
+
102
+ ## Additional options
103
+
104
+ | Option | Platforms | Default | Description |
105
+ |---|---|---|---|
106
+ | `minimumInterval` | iOS, Android | 720 (12h) | Minimum interval in minutes between task executions |
107
+ | `iosTaskType` | iOS only | `'refresh'` | Which BGTask type to use |
108
+ | `requiresNetworkConnectivity` | iOS, Android | `true` | Whether the task needs network access |
109
+ | `requiresExternalPower` | iOS only | `false` | Whether the task needs external power (only for `'processing'`) |
110
+
111
+ > **Note:** On Android, `iosTaskType` is ignored. Android uses WorkManager for all background work, which handles scheduling uniformly regardless of task complexity. The `requiresNetworkConnectivity` option does work on Android and controls the WorkManager network constraint.
112
+
113
+ # Contributing
114
+
115
+ Contributions are very welcome! Please refer to guidelines described in the [contributing guide](https://github.com/expo/expo#contributing).
@@ -0,0 +1,21 @@
1
+ plugins {
2
+ id 'com.android.library'
3
+ id 'expo-module-gradle-plugin'
4
+ }
5
+
6
+ group = 'host.exp.exponent'
7
+ version = '55.0.8'
8
+
9
+ android {
10
+ namespace "expo.modules.backgroundtask"
11
+ defaultConfig {
12
+ versionCode 23
13
+ versionName "55.0.8"
14
+ consumerProguardFiles("proguard-rules.pro")
15
+ }
16
+ }
17
+
18
+ dependencies {
19
+ implementation 'androidx.work:work-runtime-ktx:2.9.1'
20
+ implementation 'com.facebook.react:react-android'
21
+ }
@@ -0,0 +1 @@
1
+ -keep class expo.modules.backgroundtask.** { *; }
@@ -0,0 +1,3 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
3
+ </manifest>
@@ -0,0 +1,60 @@
1
+ package expo.modules.backgroundtask
2
+
3
+ import android.content.Context
4
+ import android.util.Log
5
+ import expo.modules.interfaces.taskManager.TaskConsumer
6
+ import expo.modules.interfaces.taskManager.TaskConsumerInterface
7
+ import expo.modules.interfaces.taskManager.TaskExecutionCallback
8
+ import expo.modules.interfaces.taskManager.TaskInterface
9
+ import expo.modules.interfaces.taskManager.TaskManagerUtilsInterface
10
+
11
+ class BackgroundTaskConsumer(context: Context?, taskManagerUtils: TaskManagerUtilsInterface?) :
12
+ TaskConsumer(context, taskManagerUtils), TaskConsumerInterface {
13
+
14
+ companion object {
15
+ private const val BACKGROUND_TASK_TYPE = "expo-background-task"
16
+ private val TAG = BackgroundTaskConsumer::class.java.simpleName
17
+ }
18
+
19
+ private var task: TaskInterface? = null
20
+
21
+ override fun taskType(): String {
22
+ return BACKGROUND_TASK_TYPE
23
+ }
24
+
25
+ /**
26
+ * Exposing the execute task function so that the BackgroundTaskWork (WorkManager Work unit)
27
+ * can execute the inner task. A task is only executed if the app is in the background.
28
+ * This only applies when the app is in release mode.
29
+ */
30
+ fun executeTask(callback: TaskExecutionCallback) {
31
+ Log.d(TAG, "Executing task '${task?.name}'")
32
+ taskManagerUtils.executeTask(task, null, callback)
33
+ }
34
+
35
+ override fun didRegister(task: TaskInterface) {
36
+ Log.d(TAG, "didRegister: ${task.name}")
37
+ this.task = task
38
+
39
+ val intervalMinutes = getIntervalMinutes()
40
+ val requiresNetwork = getRequiresNetwork()
41
+ BackgroundTaskScheduler.registerTask(context, intervalMinutes, requiresNetwork)
42
+ }
43
+
44
+ override fun didUnregister() {
45
+ Log.d(TAG, "didUnregister: ${task?.name}")
46
+ this.task = null
47
+ BackgroundTaskScheduler.unregisterTask(context)
48
+ }
49
+
50
+ private fun getIntervalMinutes(): Long {
51
+ val options = task?.options as? Map<String, Any?>
52
+ return (options?.get("minimumInterval") as? Number)?.toLong()
53
+ ?: BackgroundTaskScheduler.DEFAULT_INTERVAL_MINUTES
54
+ }
55
+
56
+ private fun getRequiresNetwork(): Boolean? {
57
+ val options = task?.options as? Map<String, Any?>
58
+ return options?.get("requiresNetworkConnectivity") as? Boolean
59
+ }
60
+ }
@@ -0,0 +1,13 @@
1
+ package expo.modules.backgroundtask
2
+
3
+ import expo.modules.kotlin.exception.CodedException
4
+
5
+ internal class MissingContextException : CodedException(message = "Application context not found")
6
+
7
+ internal class MissingTaskServiceException : CodedException(message = "TaskService not available.")
8
+
9
+ internal class MissingAppScopeKey : CodedException(message = "Could not find required appScopeKey in worker.")
10
+
11
+ internal class TaskMangerInterfaceNotFoundException : CodedException(message = "TaskManagerInterface not found")
12
+
13
+ internal class TestMethodNotAvailableInProductionBuild : CodedException(message = "Background tasks cannot be triggered in production builds")
@@ -0,0 +1,56 @@
1
+ package expo.modules.backgroundtask
2
+
3
+ import android.util.Log
4
+ import com.facebook.react.common.build.ReactBuildConfig
5
+ import expo.modules.interfaces.taskManager.TaskManagerInterface
6
+ import expo.modules.kotlin.functions.Coroutine
7
+ import expo.modules.kotlin.modules.Module
8
+ import expo.modules.kotlin.modules.ModuleDefinition
9
+
10
+ class BackgroundTaskModule : Module() {
11
+ companion object {
12
+ private val TAG = BackgroundTaskModule::class.java.simpleName
13
+ }
14
+
15
+ private val _taskManager by lazy { appContext.legacyModule<TaskManagerInterface>() }
16
+ private val taskManager: TaskManagerInterface
17
+ get() = _taskManager ?: throw TaskMangerInterfaceNotFoundException()
18
+
19
+ override fun definition() = ModuleDefinition {
20
+ Name("ExpoBackgroundTask")
21
+
22
+ AsyncFunction("getStatusAsync") {
23
+ return@AsyncFunction 2 // WorkManager is always available on Android.
24
+ }
25
+
26
+ AsyncFunction("triggerTaskWorkerForTestingAsync") Coroutine { ->
27
+ if (ReactBuildConfig.DEBUG) {
28
+ Log.d(TAG, "Triggering tasks for testing")
29
+ appContext.reactContext?.let {
30
+ val appScopeKey = it.packageName
31
+ return@Coroutine BackgroundTaskScheduler.runTasks(it, appScopeKey)
32
+ } ?: throw MissingContextException()
33
+ } else {
34
+ throw TestMethodNotAvailableInProductionBuild()
35
+ }
36
+ }
37
+
38
+ AsyncFunction("registerTaskAsync") { taskName: String, options: Map<String, Any?> ->
39
+ Log.d(TAG, "registerTaskAsync: $taskName with options $options")
40
+ taskManager.registerTask(taskName, BackgroundTaskConsumer::class.java, options)
41
+ }
42
+
43
+ AsyncFunction("unregisterTaskAsync") { taskName: String ->
44
+ Log.d(TAG, "unregisterTaskAsync: $taskName")
45
+ taskManager.unregisterTask(taskName, BackgroundTaskConsumer::class.java)
46
+ }
47
+
48
+ OnActivityEntersForeground {
49
+ BackgroundTaskScheduler.inForeground = true
50
+ }
51
+
52
+ OnActivityEntersBackground {
53
+ BackgroundTaskScheduler.inForeground = false
54
+ }
55
+ }
56
+ }