Reference version

This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.

Expo BackgroundTask

一个提供用于运行后台任务 API 的库。

Android
iOS
tvOS
Included in Expo Go
Recommended version:
~57.0.0

expo-background-task 提供了一个 API,用于以优化终端用户设备电池和电量消耗的方式运行可延迟的后台任务。此模块在 Android 上使用 WorkManager API,在 iOS 上使用 BGTaskScheduler API 来调度任务。它还使用 expo-task-manager 原生 API 来运行 JavaScript 任务。

观看:Expo 后台任务深度解析
观看:Expo 后台任务深度解析

使用 expo-background-task 在后台同步数据、预取内容并运行延迟工作。

后台任务

后台任务是一种可延迟执行的工作单元,它会在应用生命周期之外于后台执行。这适用于需要在应用处于非活动状态时执行的任务,例如与服务器同步数据、获取新内容,甚至检查是否有任何 expo-updates

什么时候运行后台任务?

Expo Background Task API 会利用各个平台,在应用处于后台时,于对用户和设备都最合适的时间执行任务。

这意味着任务可能不会在调度后立即运行,但如果系统决定执行,它会在未来的某个时间点运行。你可以为任务指定一个最小执行间隔(分钟)。在满足指定条件的前提下,任务会在该间隔过后某个时间执行。

只有在电池电量充足(或设备已接通电源)且网络可用时,后台任务才会运行。没有这些条件,任务就不会执行。具体行为会因操作系统而异。

它们什么时候会停止?

后台任务由平台 API 和系统限制管理。了解任务何时停止有助于更有效地规划其使用。

  • 如果用户强制结束应用,后台任务会停止。应用重新启动后,任务会恢复。
  • 如果系统停止应用或设备重新启动,后台任务会恢复,并且应用会重新启动。

在 Android 上,从最近使用的应用列表中移除应用并不会完全停止它;而在 iOS 上,在应用切换器中将其滑走会完全终止它。

平台差异

Android 
Android

在 Android 上,WorkManager API 允许为任务指定最小运行间隔(最少 15 分钟)。只要满足指定条件,任务会在间隔过去后的某个时间执行。

iOS 
iOS

在 iOS 上,BGTaskScheduler API 会决定启动后台任务的最佳时间。系统会考虑电池电量、网络可用性以及用户的使用模式来决定何时运行任务。你仍然可以为任务指定最小运行间隔,但系统也可能选择在更晚的时间运行该任务。

已知限制

iOS 
iOS

Background Tasks API 在 iOS 模拟器上不可用。它仅在物理设备上运行时可用。

安装

Terminal
npx expo install expo-background-task

If you are installing this in an existing React Native app, make sure to install expo in your project.

应用配置中的配置 
iOS

为了能够在 iOS 上运行后台任务,你需要将以下内容添加到应用的 Info.plist 文件中:

  • processing 值添加到 UIBackgroundModes 数组中。这将启用后台处理功能。
  • com.expo.modules.backgroundtask.processing 标识符添加到 BGTaskSchedulerPermittedIdentifiers 数组中。这将注册允许的后台任务标识符。

如果你正在使用 CNG,所需的 UIBackgroundModesBGTaskSchedulerPermittedIdentifiers 配置都会在预构建过程中自动应用。

在 iOS 上手动配置 Info.plist

如果你没有使用持续原生生成(CNG),那么你需要将以下内容添加到 Info.plist 文件中:

ios/project-name/Supporting/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 的示例。

App.tsx
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 ? 'Cancel background task' : 'Schedule background task'} onPress={toggle} /> <Button title="Check background task status" 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 工具来检查已安排的任务:

Terminal
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 命令。在运行此命令之前,请先将应用切换到后台,因为如果应用处于前台,任务将不会运行。

Terminal
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

BackgroundTask.getStatusAsync()

Android
iOS
tvOS

Returns the status for the Background Task API. On web, it always returns BackgroundTaskStatus.Restricted, while on native platforms it returns BackgroundTaskStatus.Available.

A BackgroundTaskStatus enum value or null if not available.

BackgroundTask.registerTaskAsync(taskName, options)

Android
iOS
tvOS
ParameterTypeDescription
taskNamestring

Name of the task to register. The task needs to be defined first - see TaskManager.defineTask for more details.

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.

Returns:
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, {});

BackgroundTask.triggerTaskWorkerForTestingAsync()

Android
iOS
tvOS

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.

Returns:
Promise<boolean>

A promise which fulfils when the task is triggered.

BackgroundTask.unregisterTaskAsync(taskName)

Android
iOS
tvOS
ParameterTypeDescription
taskNamestring

Name of the task to unregister.


Unregisters a background task, so the application will no longer be executing this task.

Returns:
Promise<void>

A promise which fulfils when the task is fully unregistered.

Event subscriptions

BackgroundTask.addExpirationListener(listener)

iOS
ParameterType
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.

Returns:
{ remove: () => void }

An object with a remove method to unsubscribe the listener.

Types

BackgroundTaskOptions

Android
iOS
tvOS

Options for registering a background task

PropertyTypeDescription
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.

  • Defaults to once every 12 hours (The minimum interval is 15 minutes)
  • The system controls the background task execution interval and treats the specified value as a minimum delay. Tasks won't run exactly on schedule. On iOS, short intervals are often ignored—the system typically runs background tasks during specific windows, such as overnight.

Enums

BackgroundTaskResult

Android
iOS
tvOS

Return value for background tasks.

Success

BackgroundTaskResult.Success = 1

The task finished successfully.

Failed

BackgroundTaskResult.Failed = 2

The task failed.

BackgroundTaskStatus

Android
iOS
tvOS

Availability status for background tasks

Restricted

BackgroundTaskStatus.Restricted = 1

Background tasks are unavailable.

Available

BackgroundTaskStatus.Available = 2

Background tasks are available for the app.