Expo BackgroundTask

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

Android
iOS

此库目前处于测试阶段,可能会发生重大变化。

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

¥expo-background-task provides an API to run deferrable background tasks in a way that optimizes battery and power consumption on the end user's device. This module uses the WorkManager API on Android and the BGTaskScheduler API on iOS to schedule tasks. It also uses the expo-task-manager Native API to run JavaScript tasks.

后台任务

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

  • 如果用户终止应用,后台任务将停止。应用重新启动时任务恢复。

    ¥Background tasks are stopped if the user kills the app. Tasks resume when the app is restarted.

  • 如果系统停止应用或设备重新启动,后台任务将恢复,并且应用将重新启动。

    ¥If the system stops the app or the device reboots, background tasks will resume, and the app will be restarted.

在 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

¥On Android, behavior varies by device vendor. For example, some implementations treat removing an app from the recent apps list as killing it. Read more about these differences here: https://dontkillmyapp.com.

平台差异

¥Platform differences

安卓

¥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

在 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

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, start by installing expo in your project. Then, follow the additional instructions as mentioned by the library's README under "Installation in bare React Native projects" section.

配置

¥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 配置将由预构建自动应用。

¥If you're using CNG, the required UIBackgroundModes configuration will be applied automatically by prebuild.

Configure UIBackgroundModes manually on iOS

如果你不使用持续原生生成 (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(() => {
    checkStatusAsync();
  }, []);

  const checkStatusAsync = async () => {
    const status = await BackgroundTask.getStatusAsync();
    setStatus(status);
  };

  const toggle = async () => {
    if (isRegistered) {
      await registerBackgroundTaskAsync();
    } else {
      await unregisterBackgroundTaskAsync();
    }
    setIsRegistered(!isRegistered);
  };

  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="Check Background Task Status" onPress={checkStatusAsync} />
    </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.

API

import * as BackgroundTask from 'expo-background-task';

Methods

BackgroundTask.getStatusAsync()

Android
iOS

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
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.unregisterTaskAsync(taskName)

Android
iOS
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

Options for registering a background task

PropertyTypeDescription
minimumInterval(optional)number
Only for:
Android

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)
  • On iOS, the system determines the interval for background task execution, but will wait until the specified minimum interval has elapsed before starting a task.

Enums

BackgroundTaskResult

Android
iOS

Return value for background tasks.

Success

BackgroundTaskResult.Success = 1

The task finished successfully.

Failed

BackgroundTaskResult.Failed = 2

The task failed.

BackgroundTaskStatus

Android
iOS

Availability status for background tasks

Restricted

BackgroundTaskStatus.Restricted = 1

Background tasks are unavailable.

Available

BackgroundTaskStatus.Available = 2

Background tasks are available for the app.