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
Background Tasks API 在 iOS 模拟器上不可用。它仅在真机上运行时可用。
安装
- npx expo install expo-background-taskIf you are installing this in an existing React Native app, make sure to install expo in your project.
配置 iOS
要在 iOS 上运行后台任务,你需要在应用的 Info.plist 文件中的 UIBackgroundModes 数组里添加 processing 值。这是后台获取正常工作的必要条件。
如果你正在使用 CNG,所需的 UIBackgroundModes 配置会在 prebuild 时自动应用。
在 iOS 上手动配置 UIBackgroundModes
如果你没有使用 Continuous Native Generation (CNG),那么你需要将以下内容添加到你的 Info.plist 文件中:
<key>UIBackgroundModes</key> <array> <string>processing</string> </array> </key>
用法
下面是一个演示如何使用 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(`Got background task call at date: ${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)
第一行包含作业 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.
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.