Expo BackgroundTask

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

Android
iOS
tvOS
Included in Expo Go
Bundled version:
~1.0.10

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

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

后台任务

🌐 Background tasks

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

🌐 A background task is a deferrable unit of work that is performed in the background, outside your app's lifecycle. This is useful for tasks that need to be executed when the app is inactive, such as syncing data with a server, fetching new content, or even checking if there are any expo-updates.

后台任务何时运行?

🌐 When are background tasks run?

当应用处于后台时,Expo 后台任务 API 利用每个平台在对用户和设备而言最合适的时间执行任务。

🌐 The Expo Background Task API leverages each platform to execute tasks at the most optimal time for both the user and the device when the app is in the background.

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

🌐 This means that the task may not run immediately after it is scheduled, but it will run at some point in the future if the system decides so. You can specify a minimum interval in minutes for the task to run. The task will execute sometime after the interval has passed, provided the specified conditions are met.

后台任务只有在电池有足够电量(或设备已连接电源)且网络可用时才会运行。如果不满足这些条件,任务将不会执行。具体行为取决于操作系统的不同而有所差异。

🌐 A background task will only run if the battery has enough charge (or the device is plugged into power) and the network is available. Without these conditions, the task won't execute. The exact behavior will vary depending on the operating system.

何时停止?

🌐 When will they be stopped?

后台任务由平台 API 和系统约束管理。了解任务停止的时间有助于有效规划其使用。

🌐 Background tasks are managed by platform APIs and system constraints. Knowing when tasks stop helps plan their use effectively.

  • 如果用户关闭应用,后台任务会被停止。应用重新启动后,任务会继续进行。
  • 如果系统停止应用或设备重新启动,后台任务将恢复,并且应用将重新启动。

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

🌐 On Android, removing an app from the recent apps list doesn't completely stop it, whereas on iOS, swiping it away in the app switcher fully terminates it.

信息 在 Android 上,不同设备厂商的表现各不相同。例如,一些实现会将从最近使用的应用列表中移除应用视为强制关闭它。有关这些差异的更多信息,请阅读这里:https://dontkillmyapp.com

平台差异

🌐 Platform differences

安卓 
Android

🌐 Android 

Android

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

🌐 On Android, the WorkManager API allows specifying a minimum interval for a task to run (minimum 15 minutes). The task will execute sometime after the interval has passed, provided the specified conditions are met.

iOS 
iOS

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

🌐 On iOS, the BGTaskScheduler API decides the best time to launch your background task. The system will consider the battery level, the network availability, and the user's usage patterns to determine when to run the task. You can still specify a minimum interval for the task to run, but the system may choose to run the task at a later time.

已知的限制

🌐 Known limitations

iOS 
iOS

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

🌐 The Background Tasks API is unavailable on iOS simulators. It is only available when running on a physical device.

安装

🌐 Installation

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

🌐 Configuration 

iOS

要在 iOS 上运行后台任务,你需要将 processing 值添加到应用的 Info.plist 文件中的 UIBackgroundModes 数组中。这是后台获取能够正常工作的必要条件。

🌐 To be able to run background tasks on iOS, you need to add the processing value to the UIBackgroundModes array in your app's Info.plist file. This is required for background fetch to work properly.

如果你正在使用 CNG,所需的 UIBackgroundModes 配置将会由预构建自动应用。

在 iOS 上手动配置 UIBackgroundModes

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

🌐 If you're not using Continuous Native Generation (CNG), then you'll need to add the following to your Info.plist file:

ios/project-name/Supporting/Info.plist
<key>UIBackgroundModes</key> <array> <string>processing</string> </array> </key>

用法

🌐 Usage

下面是一个演示如何使用 expo-background-task 的示例。

🌐 Below is an example that demonstrates how to use 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'; // Register and create the task so that it is available also when the background task screen // (a React component defined later in this example) is not visible. // Note: This needs to be called in the global scope, not in a React component. 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('Failed to execute the background task:', error); return BackgroundTask.BackgroundTaskResult.Failed; } return BackgroundTask.BackgroundTaskResult.Success; }); // 2. Register the task at some point in your app by providing the same name // Note: This does NOT need to be in the global scope and CAN be used in your React components! async function registerBackgroundTaskAsync() { return BackgroundTask.registerTaskAsync(BACKGROUND_TASK_IDENTIFIER); } // 3. (Optional) Unregister tasks by specifying the task name // This will cancel any future background task calls that match the given name // Note: This does NOT need to be in the global scope and CAN be used in your React components! 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> Background Task Service Availability:{' '} <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="检查后台任务状态" onPress={updateAsync} /> </View> ); } const styles = StyleSheet.create({ screen: { flex: 1, justifyContent: 'center', alignItems: 'center', }, textContainer: { margin: 10, }, boldText: { fontWeight: 'bold', }, });

多个后台任务

🌐 Multiple background tasks

由于 iOS 上的 Background Tasks API 和 Android 上的 WorkManager API 限制了单个应用可以调度的任务数量,Expo Background Task 在两个平台上都使用单个工作线程。虽然你可以定义多个 JavaScript 后台任务,但它们都会通过这个单一的工作线程运行。

🌐 Since the Background Tasks API on iOS and the WorkManager API on Android limit the number of tasks that can be scheduled for a single app, Expo Background Task uses a single worker on both platforms. While you can define multiple JavaScript background tasks, they will all run through this single worker.

最后注册的后台任务决定了执行的最小间隔。

🌐 The last registered background task determines the minimum interval for execution.

测试后台任务

🌐 Testing background tasks

可以使用 triggerTaskWorkerForTestingAsync 方法测试后台任务。此方法将在 Android 上直接运行所有已注册的任务,并在 iOS 上调用 BGTaskScheduler。这对于测试后台任务的行为非常有用,而无需等待系统触发它们。

🌐 Background tasks can be tested using the triggerTaskWorkerForTestingAsync method. This method will run all registered tasks directly on Android and invoke the BGTaskScheduler on iOS. This is useful for testing the behavior of your background tasks without having to wait for the system to trigger them.

此方法仅在开发模式下可用。在生产构建中无法使用。

🌐 This method is only available in development mode. It will not work in production builds.

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

🌐 Inspecting background tasks 

Android

要排查或调试 Android 后台任务的问题,请使用随 Android SDK 提供的 adb 工具来检查已调度的任务:

🌐 To troubleshoot or debug issues with background tasks on Android, use the adb tool included with the Android SDK to inspect scheduled tasks:

Terminal
adb shell dumpsys jobscheduler | grep -A 40 -m 1 -E "JOB #.* <package-name>"

此命令的输出将显示你的应用的计划任务,包括它们的状态、限制和其他信息。查找 JOB 行以在输出中找到作业的 ID 及其他详细信息:

🌐 The output from this command will show you the scheduled tasks for your app, including their status, constraints, and other information. Look for the JOB line to find the ID of the job and other details in the output:

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 显示任务是多久前被调度的。

🌐 The first line contains the Job ID (275). The Run time: earliest value indicates the earliest time the task may start, while enqueue time shows how long ago the task was scheduled.

要强制运行任务,请使用 adb shell am broadcast 命令。在运行此命令之前将你的应用移到后台,因为如果应用在前台,任务将不会运行。

🌐 To force a task to run, use the adb shell am broadcast command. Move your app to the background before running this command, as the task will not run if the app is in the foreground.

Terminal
adb shell cmd jobscheduler run -f <package-name> <JOB_ID>

JOB_ID 将是你在上一步中找到的要运行的作业的标识符。

🌐 Where JOB_ID would be the identifier of the job you want to run that you found in the previous step.

故障排除后台任务 
iOS

🌐 Troubleshooting background tasks 

iOS

iOS 没有类似 adb 的工具来检查后台任务。要在 iOS 上测试后台任务,请使用内置的 triggerTaskWorkerForTestingAsync 方法。此方法会模拟系统触发任务。

🌐 iOS does not have a tool similar to adb for inspecting background tasks. To test background tasks on iOS, use the built-in triggerTaskWorkerForTestingAsync method. This method simulates the system triggering the task.

你可以在应用的调试模式下触发此方法(在生产版本中不起作用),以便在不等待系统的情况下测试后台任务的行为。如果你的后台任务配置不正确,你将在 Xcode 控制台中看到错误描述:

🌐 You can trigger this method from your app in debug mode (it does not work in production builds) to test the behavior of your background tasks without waiting for the system. If your background task configuration is incorrect, you will see the error description in the Xcode console:

No task request with identifier com.expo.modules.backgroundtask.processing has been scheduled

上述错误告诉你需要运行 prebuild 来将更改应用到你的应用配置中。

🌐 The above error tells you that you need to run prebuild to apply the changes to your app's configuration.

此错误还意味着你必须运行 prebuild,以将后台任务配置应用到应用中。此外,请确保你已按照此示例中所示定义并注册了后台任务。

🌐 This error also means you must run prebuild to apply your background task configuration to the app. Additionally, ensure you have defined and registered a background task as shown in this example.

应用接口

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

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.