|
1 | | -# react-native-continued-task |
| 1 | +# react-native-continued-task: Continued Background Tasks for React Native (iOS 26 & Android) |
2 | 2 |
|
3 | 3 | [](https://www.npmjs.com/package/react-native-continued-task) |
4 | 4 | [](https://www.npmjs.com/package/react-native-continued-task) |
|
8 | 8 |
|
9 | 9 | Run user-initiated work that keeps going after the user leaves your app — a large export, an upload, a batch encode — behind one cross-platform API. |
10 | 10 |
|
| 11 | +## Overview |
| 12 | + |
| 13 | +**react-native-continued-task** is a React Native and Expo library for **long-running background tasks that survive the app being backgrounded**. It wraps iOS 26's [`BGContinuedProcessingTask`](https://developer.apple.com/documentation/backgroundtasks/bgcontinuedprocessingtask) and Android's [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager) foreground services behind a single typed API, so an upload, export, or batch encode the user started keeps running — with the progress UI each platform draws for it. |
| 14 | + |
| 15 | +It is built on [Nitro Modules](https://nitro.margelo.com) with Swift on iOS and Kotlin on Android, ships an Expo config plugin, and is written for the constraints these APIs actually impose rather than hiding them. |
| 16 | + |
11 | 17 | <table> |
12 | 18 | <tr> |
13 | 19 | <td align="center"><b>iOS 26</b> — Live Activity on the Lock Screen</td> |
@@ -441,6 +447,43 @@ device, an Android 15 or 16 handset that can actually reach the six-hour `dataSy |
441 | 447 | `STOP_REASON_QUOTA` seen in the wild. See [CONTRIBUTING.md](CONTRIBUTING.md) for the dev loop, and |
442 | 448 | [docs/DEVICE-QA.md](docs/DEVICE-QA.md) if you want to re-run the iOS checklist and add a run log. |
443 | 449 |
|
| 450 | +## FAQ |
| 451 | + |
| 452 | +**Does it work in Expo Go?** |
| 453 | +No. Nitro modules need native code, so Expo Go can never load them. Use a development build (`npx expo prebuild` then `expo run:ios` / `run:android`). |
| 454 | + |
| 455 | +**Can I test this on the iOS Simulator?** |
| 456 | +No. `BGTaskScheduler` returns `.unavailable` on the Simulator — Apple documents this in the SDK header. `isSupported` reports `false` there and every submission rejects. iOS behaviour has to be verified on a physical device running iOS 26+; see [docs/DEVICE-QA.md](docs/DEVICE-QA.md). |
| 457 | + |
| 458 | +**How long can a continued processing task run on iOS?** |
| 459 | +Apple does not publish a maximum duration or a concurrent-task ceiling, so this library does not quote figures. The "1 refresh + 10 processing tasks" limit in `BGTaskScheduler`'s documentation is about a different task type and does not apply here. |
| 460 | + |
| 461 | +**What happens when the user swipes my app out of the app switcher?** |
| 462 | +iOS cancels the task and — verbatim from Apple — "the app doesn't receive an indication of cancellation in that case." No stop listener, no expiration handler. Call [`getKnownTasks()`](#getknowntasks-promiseknowntask) on your next launch; work interrupted that way comes back with the `app-terminated` stop reason. |
| 463 | + |
| 464 | +**Why does cancelling from the Live Activity report `expired` instead of `user-cancelled`?** |
| 465 | +Because iOS routes user cancellation and system expiry through the same zero-argument `expirationHandler`, with nothing to distinguish them. This library reports what it can justify rather than guessing. Android _can_ tell them apart, and reports `user-cancelled`. |
| 466 | + |
| 467 | +**My Android notification never appears. Is the task running?** |
| 468 | +Almost certainly yes. On Android 13+ you must request `POST_NOTIFICATIONS` at runtime — without the grant the foreground service still starts and the work still runs, but the notification is suppressed. See [Android 13+ needs the notification permission at runtime](#android-13-needs-the-notification-permission-at-runtime). |
| 469 | + |
| 470 | +**How is this different from `expo-background-task` or `BGProcessingTask`?** |
| 471 | +Those schedule deferrable work the system runs _later_, when conditions are favourable — you do not control when, and the user sees nothing. A continued processing task starts **immediately**, because the user just asked for it, and the system shows them progress they can cancel. Different tool for a different job. |
| 472 | + |
| 473 | +**Do I need the background GPU entitlement?** |
| 474 | +Only for tasks submitted with `ios.requiresGPU`. Non-GPU work needs no entitlement. Note that `com.apple.developer.background-tasks.continued-processing.gpu` is valid only for paid Apple Developer Program teams — a free personal team cannot sign it. |
| 475 | + |
| 476 | +**Does it work without Expo?** |
| 477 | +Yes. The Expo config plugin is a convenience; the [Bare workflow](#bare-workflow) section lists the `Info.plist` and `AndroidManifest.xml` entries to add by hand. |
| 478 | + |
| 479 | +## Related resources |
| 480 | + |
| 481 | +- [motionary.dev](https://motionary.dev?utm_source=github&utm_medium=readme&utm_campaign=react-native-continued-task) — React Native components, animations and guides |
| 482 | +- [Apple: Finish tasks in the background (WWDC25 session 227)](https://developer.apple.com/videos/play/wwdc2025/227/) — the iOS behaviour this library wraps |
| 483 | +- [`BGContinuedProcessingTask` documentation](https://developer.apple.com/documentation/backgroundtasks/bgcontinuedprocessingtask) |
| 484 | +- [Android: long-running workers](https://developer.android.com/develop/background-work/background-tasks/persistent/how-to/long-running) |
| 485 | +- [Nitro Modules](https://nitro.margelo.com) — the native module framework this is built on |
| 486 | + |
444 | 487 | ## Sponsor |
445 | 488 |
|
446 | 489 | Built and maintained by [**motionary.dev**](https://motionary.dev?utm_source=github&utm_medium=readme&utm_campaign=react-native-continued-task) — free, and free to use. |
|
0 commit comments