You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Expo版React Native中实现Background Fetch解决离线推送问题

嘿,我刚好有过用Expo实现这个需求的经验,给你梳理下具体的步骤和注意事项,帮你搞定应用完全关闭时的推送通知问题:

核心思路:用Expo Background Fetch + 本地通知补全离线推送

因为应用完全关闭时,没法直接接收远程推送(FCM/APNs找不到活跃的应用进程),所以我们需要靠后台定时任务主动拉取新通知,然后触发本地通知来提醒用户。

第一步:配置项目权限与基础依赖

首先得确保项目有后台任务和通知的权限,同时安装必要的Expo包:

  1. 安装依赖:
    npx expo install expo-background-fetch expo-notifications
    
  2. 修改app.json配置权限:
    • iOS端:需要开启后台fetch权限,在expo.ios.infoPlist里添加:
      "UIBackgroundModes": ["fetch", "remote-notification"]
      
    • Android端:添加必要的权限和后台配置,在expo.android里补充:
      "permissions": [
        "android.permission.FOREGROUND_SERVICE",
        "android.permission.RECEIVE_BOOT_COMPLETED",
        "android.permission.WAKE_LOCK"
      ],
      "backgroundPermissions": ["android.permission.ACCESS_BACKGROUND_LOCATION"],
      "useNextNotificationsApi": true
      

第二步:注册后台Fetch任务

在App启动时注册后台任务,比如在App.jsuseEffect里:

import { BackgroundFetch } from 'expo-background-fetch';
import { registerTaskAsync } from 'expo-task-manager';

// 先定义任务名称
const BACKGROUND_FETCH_TASK = 'fetch-new-notifications';

useEffect(() => {
  const setupBackgroundFetch = async () => {
    // 注册任务处理函数
    await registerTaskAsync(BACKGROUND_FETCH_TASK, {
      minimumInterval: 60, // 注意:iOS系统强制最小15分钟(900秒),填更小的值会被系统自动调整
      stopOnTerminate: false, // Android:应用关闭后是否继续运行任务
      startOnBoot: true, // Android:开机后自动启动任务
    });

    // 申请后台fetch权限
    const status = await BackgroundFetch.getStatusAsync();
    if (status !== BackgroundFetch.Status.Available) {
      await BackgroundFetch.requestPermissionsAsync();
    }
  };

  setupBackgroundFetch();
}, []);

划重点:iOS的minimumInterval最小是15分钟,系统会忽略更小的设置,没法做到精确1分钟的间隔;Android可以设置更短,但要注意系统的电池优化可能会限制任务触发频率。

第三步:编写后台任务处理逻辑

在项目根目录创建一个backgroundTasks.js文件,编写拉取通知和触发本地通知的逻辑:

import { BackgroundFetch } from 'expo-background-fetch';
import * as Notifications from 'expo-notifications';

export async function fetchNewNotificationsTask() {
  try {
    // 1. 调用你的API检查特定用户的新通知
    const response = await fetch('https://your-api-url/check-notifications', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        // 带上用户身份凭证,比如token
        'Authorization': 'Bearer ' + userToken,
      },
      body: JSON.stringify({ userId: 'specific-user-id' }),
    });

    const newNotifications = await response.json();

    // 2. 如果有新通知,触发本地通知
    if (newNotifications.length > 0) {
      for (const notification of newNotifications) {
        await Notifications.scheduleNotificationAsync({
          content: {
            title: notification.title,
            body: notification.content,
            data: notification.data, // 携带自定义数据,方便点击通知跳转
          },
          trigger: null, // 立即触发通知
        });
      }
    }

    // 告诉系统任务成功,有新数据
    return BackgroundFetch.Result.NewData;
  } catch (error) {
    console.error('Background fetch failed:', error);
    // 任务失败,告知系统
    return BackgroundFetch.Result.Failed;
  }
}

然后在App.js里关联这个任务,确保Expo能找到它:

import { fetchNewNotificationsTask } from './backgroundTasks';

// 注册任务时绑定处理函数
registerTaskAsync(BACKGROUND_FETCH_TASK, { task: fetchNewNotificationsTask });

第四步:关键注意事项

  1. iOS的限制
    • 应用被用户从多任务划掉后,后台任务会停止,直到用户再次打开应用才会恢复。
    • 后台fetch的触发时间由系统调度,只有当设备充电、联网且空闲时才会频繁触发,没法保证精确间隔。
    • 如果需要更实时的通知,可结合APNs的静默通知,但静默通知也有严格限制(不能显示内容,只能触发少量逻辑)。
  2. Android的优化规避
    • 部分国产手机(小米、华为等)的电池优化会强制停止后台任务,需要引导用户手动关闭应用的电池优化。
    • 可以申请REQUEST_IGNORE_BATTERY_OPTIMIZATIONS权限,让用户授权忽略电池优化。
  3. 后台任务限制
    • 后台任务的执行时间有限(iOS约30秒,Android约1分钟),所以逻辑要尽量简洁,避免耗时操作。
    • 不能在后台任务中更新UI或调用Alert等交互组件,只能做网络请求和触发本地通知。

第五步:测试方法

  • iOS:用Xcode打开项目的workspace,选择Debug -> Simulate Background Fetch,就能触发后台任务测试。
  • Android:用adb命令触发任务:
    adb shell cmd jobscheduler run -f your-expo-package-name job-id
    
    (job-id可以通过BackgroundFetch.getTaskAsync()获取,或者查看Expo运行日志)

内容的提问来源于stack exchange,提问作者Ilya K

火山引擎 最新活动