This is documentation for the next SDK version. For up-to-date documentation, see the latest version (SDK 55).
Expo BackgroundTask
一个提供用于运行后台任务 API 的库。
For the complete documentation index, see llms.txt. Use this Use this file to discover all available pages.
expo-background-task 提供了一个 API,用于以优化终端用户设备电池和电量消耗的方式运行可延迟的后台任务。此模块在 Android 上使用 WorkManager API,在 iOS 上使用 BGTaskScheduler API 来调度任务。它还使用 expo-task-manager 原生 API 来运行 JavaScript 任务。

使用 expo-background-task 在后台同步数据、预取内容并运行延迟工作。
后台任务
后台任务是在应用生命周期之外、于后台执行的可延迟工作单元。这对于需要在应用处于非活动状态时执行的任务很有用,例如与服务器同步数据、获取新内容,甚至检查是否有任何 expo-updates。
后台任务何时运行?
Expo Background Task API 会利用各个平台,在应用处于后台时,于对用户和设备都最优的时间执行任务。
这意味着任务可能不会在调度后立即运行,但如果系统决定如此,它会在未来的某个时间点运行。你可以为任务指定一个最小执行间隔(以分钟为单位)。在满足指定条件的前提下,任务会在该间隔过去之后的某个时间执行。
只有在电池电量充足(或设备已接通电源)且网络可用时,后台任务才会运行。若不满足这些条件,任务不会执行。具体行为会因操作系统而异。
它们何时会停止?
后台任务由平台 API 和系统限制共同管理。了解任务何时停止有助于更有效地规划其使用。
- 如果用户强制结束应用,后台任务会停止。应用重新启动后,任务会恢复。
- 如果系统停止应用或设备重启,后台任务会恢复,且应用会被重新启动。
在 Android 上,将应用从最近任务列表中移除并不会完全停止它;而在 iOS 上,在应用切换器中将其划掉会完全终止它。
信息 在 Android 上,行为因设备厂商而异。例如,有些实现会将从最近任务列表中移除应用视为结束应用。了解更多这些差异: https://dontkillmyapp.com。
平台差异
Android Android
在 Android 上,WorkManager API 允许为任务指定最小执行间隔(至少 15 分钟)。在满足指定条件的前提下,任务会在该间隔过去之后的某个时间执行。
iOS iOS
在 iOS 上,BGTaskScheduler API 会决定启动后台任务的最佳时间。系统会综合考虑电池电量、网络可用性以及用户使用模式来确定任务何时运行。你仍然可以为任务指定最小执行间隔,但系统可能会选择在稍后执行该任务。
已知限制
iOS iOS
iOS 模拟器不提供 Background Tasks API。它仅在物理设备上运行时可用。
安装
- npx expo install expo-background-taskIf you are installing this in an existing React Native app, make sure to install expo in your project.
app 配置中的设置 iOS
为了能够在 iOS 上运行后台任务,你需要在应用的 Info.plist 文件中添加以下内容:
- 将
processing值添加到UIBackgroundModes数组中。这样可以启用后台处理能力。 - 使用
com.expo.modules.backgroundtask.processing标识符添加BGTaskSchedulerPermittedIdentifiers数组。这将注册允许的后台任务标识符。
如果你正在使用 CNG,所需的 UIBackgroundModes 和 BGTaskSchedulerPermittedIdentifiers 配置都会在 prebuild 过程中自动应用。
在 iOS 上手动配置 Info.plist
如果你没有使用 Continuous Native Generation (CNG),那么你需要在 Info.plist 文件中添加以下内容:
<key>UIBackgroundModes</key> <array> <string>processing</string> </array> <key>BGTaskSchedulerPermittedIdentifiers</key> <array> <string>com.expo.modules.backgroundtask.processing</string> </array>
使用
下面是一个演示如何使用 expo-background-task 的示例。
import * as BackgroundTask from 'expo-background-task'; import * as TaskManager from 'expo-task-manager'; import { useEffect, useState } from 'react'; import { StyleSheet, Text, View, Button } from 'react-native'; const BACKGROUND_TASK_IDENTIFIER = 'background-task'; // 注册并创建任务,以便即使后台任务界面 //(本示例后面定义的一个 React 组件)不可见时也能使用。 // 注意:这需要在全局作用域中调用,而不是在 React 组件中。 TaskManager.defineTask(BACKGROUND_TASK_IDENTIFIER, async () => { try { const now = Date.now(); console.log(`在以下日期收到了后台任务调用:${new Date(now).toISOString()}`); } catch (error) { console.error('执行后台任务失败:', error); return BackgroundTask.BackgroundTaskResult.Failed; } return BackgroundTask.BackgroundTaskResult.Success; }); // 2. 在应用的某个时刻通过提供相同的名称来注册任务 // 注意:这不需要在全局作用域中,可以在你的 React 组件中使用! async function registerBackgroundTaskAsync() { return BackgroundTask.registerTaskAsync(BACKGROUND_TASK_IDENTIFIER); } // 3.(可选)通过指定任务名称来注销任务 // 这将取消所有与给定名称匹配的未来后台任务调用 // 注意:这不需要在全局作用域中,可以在你的 React 组件中使用! async function unregisterBackgroundTaskAsync() { return BackgroundTask.unregisterTaskAsync(BACKGROUND_TASK_IDENTIFIER); } export default function BackgroundTaskScreen() { const [isRegistered, setIsRegistered] = useState<boolean>(false); const [status, setStatus] = useState<BackgroundTask.BackgroundTaskStatus | null>(null); useEffect(() => { updateAsync(); }, []); const updateAsync = async () => { const status = await BackgroundTask.getStatusAsync(); setStatus(status); const isRegistered = await TaskManager.isTaskRegisteredAsync(BACKGROUND_TASK_IDENTIFIER); setIsRegistered(isRegistered); }; const toggle = async () => { if (!isRegistered) { await registerBackgroundTaskAsync(); } else { await unregisterBackgroundTaskAsync(); } await updateAsync(); }; return ( <View style={styles.screen}> <View style={styles.textContainer}> <Text> 后台任务服务可用性:{' '} <Text style={styles.boldText}> {status ? BackgroundTask.BackgroundTaskStatus[status] : null} </Text> </Text> </View> <Button disabled={status === BackgroundTask.BackgroundTaskStatus.Restricted} title={isRegistered ? '取消后台任务' : '调度后台任务'} onPress={toggle} /> <Button title="检查后台任务状态" onPress={updateAsync} /> </View> ); } const styles = StyleSheet.create({ screen: { flex: 1, justifyContent: 'center', alignItems: 'center', }, textContainer: { margin: 10, }, boldText: { fontWeight: 'bold', }, });
多个后台任务
由于 iOS 上的 Background Tasks API 和 Android 上的 WorkManager API 都限制了单个应用可调度的任务数量,Expo Background Task 在两个平台上都使用单个 worker。虽然你可以定义多个 JavaScript 后台任务,但它们都会通过这个单一 worker 运行。
最后注册的后台任务决定执行的最小间隔。
测试后台任务
可以使用 triggerTaskWorkerForTestingAsync 方法测试后台任务。此方法会在 Android 上直接运行所有已注册任务,并在 iOS 上调用 BGTaskScheduler。这对于测试后台任务的行为很有用,而无需等待系统触发它们。
此方法仅在开发模式下可用。它不会在生产构建中工作。
import * as BackgroundTask from 'expo-background-task'; import { Button } from 'react-native'; function App() { const triggerTask = async () => { await BackgroundTask.triggerTaskWorkerForTestingAsync(); }; return <Button title="触发后台任务" onPress={triggerTask} />; }
检查后台任务 Android
要排查或调试 Android 上的后台任务问题,请使用 Android SDK 中包含的 adb 工具来检查已调度任务:
- adb shell dumpsys jobscheduler | grep -A 40 -m 1 -E "JOB #.* <package-name>"该命令的输出将显示应用的已调度任务,包括它们的状态、约束以及其他信息。查找 JOB 行以在输出中找到作业 ID 和其他详细信息:
JOB #u0a453/275: 216a359 <package-name>/androidx.work.impl.background.systemjob.SystemJobService u0a453 tag=*job*/<package-name>/androidx.work.impl.background.systemjob.SystemJobService#275 Source: uid=u0a453 user=0 pkg=<package-name> ... Required constraints: TIMING_DELAY CONNECTIVITY UID_NOT_RESTRICTED [0x90100000] Preferred constraints: Dynamic constraints: Satisfied constraints: CONNECTIVITY DEVICE_NOT_DOZING BACKGROUND_NOT_RESTRICTED TARE_WEALTH WITHIN_QUOTA UID_NOT_RESTRICTED [0x1b500000] Unsatisfied constraints: TIMING_DELAY [0x80000000] ... Enqueue time: -8m12s280ms Run time: earliest=+6m47s715ms, latest=none, original latest=none Restricted due to: none. Ready: false (job=false user=true !restricted=true !pending=true !active=true !backingup=true comp=true)
第一行包含 Job ID(275)。Run time: earliest 的值表示任务最早可能开始的时间,而 enqueue time 显示任务是在多久以前被调度的。
要强制运行某个任务,请使用 adb shell am broadcast 命令。在运行此命令之前,请将应用切换到后台,因为如果应用在前台,任务将不会运行。
- adb shell cmd jobscheduler run -f <package-name> <JOB_ID>其中 JOB_ID 是你在上一步中找到、想要运行的作业标识符。
排查后台任务 iOS
iOS 没有类似 adb 的工具可用于检查后台任务。要在 iOS 上测试后台任务,请使用内置的 triggerTaskWorkerForTestingAsync 方法。此方法会模拟系统触发该任务。
你可以在调试模式下从应用中触发此方法(生产构建中不起作用),以便在不等待系统的情况下测试后台任务的行为。如果你的后台任务配置不正确,你会在 Xcode 控制台中看到错误说明:
No task request with identifier com.expo.modules.backgroundtask.processing has been scheduled
上述错误告诉你需要运行 prebuild,以将更改应用到你的应用配置中。
此错误也意味着你必须运行 prebuild,才能将后台任务配置应用到应用中。此外,请确保你已按照此示例定义并注册了后台任务。
API
import * as BackgroundTask from 'expo-background-task';
Methods
Returns the status for the Background Task API. On web, it always returns BackgroundTaskStatus.Restricted,
while on native platforms it returns BackgroundTaskStatus.Available.
Promise<BackgroundTaskStatus>A BackgroundTaskStatus enum value or null if not available.
| Parameter | Type | Description |
|---|---|---|
| taskName | string | Name of the task to register. The task needs to be defined first - see |
| options(optional) | BackgroundTaskOptions | An object containing the background task options. Default: {} |
Registers a background task with the given name. Registered tasks are saved in persistent storage and restored once the app is initialized.
Promise<void>Example
import * as TaskManager from 'expo-task-manager'; // Register the task outside of the component TaskManager.defineTask(BACKGROUND_TASK_IDENTIFIER, () => { try { await AsyncStorage.setItem(LAST_TASK_DATE_KEY, Date.now().toString()); } catch (error) { console.error('Failed to save the last fetch date', error); return BackgroundTaskResult.Failed; } return BackgroundTaskResult.Success; });
You can now use the registerTaskAsync function to register the task:
BackgroundTask.registerTaskAsync(BACKGROUND_TASK_IDENTIFIER, {});
When in debug mode this function will trigger running the background tasks. This function will only work for apps built in debug mode. This method is only available in development mode. It will not work in production builds.
Promise<boolean>A promise which fulfils when the task is triggered.
| Parameter | Type | Description |
|---|---|---|
| taskName | string | Name of the task to unregister. |
Unregisters a background task, so the application will no longer be executing this task.
Promise<void>A promise which fulfils when the task is fully unregistered.
Event Subscriptions
| Parameter | Type |
|---|---|
| listener | () => void |
Adds a listener that is called when the background executor expires. On iOS, tasks can run for minutes, but the system can interrupt the process at any time. This listener is called when the system decides to stop the background tasks and should be used to clean up resources or save state. When the expiry handler is called, the main task runner is rescheduled automatically.
{
remove: () => void
}An object with a remove method to unsubscribe the listener.
Types
Options for registering a background task
| Property | Type | Description |
|---|---|---|
| minimumInterval(optional) | number | Inexact interval in minutes between subsequent repeats of the background tasks. The final interval may differ from the specified one to minimize wakeups and battery usage.
|
Enums
Return value for background tasks.