You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native Expo后台通知任务前后台正常,被杀进程后失效(集成CallKeep)

应用被终止时如何用Expo + CallKeep触发来电通知?

问题背景

我正在开发React Native Expo项目,使用expo-notifications、expo-task-manager和react-native-callkeep处理来电通知,目标是应用被终止(被杀/关闭)时仍能显示来电界面。

当前实现代码:

import { Component } from 'react';
import Routes from "./Navigations/Route";
import * as React from 'react';
import { registerRootComponent } from 'expo';
import { Provider } from 'react-redux';
import store from './store/store';
import * as TaskManager from "expo-task-manager";
import * as Notifications from "expo-notifications";
import CallKeep from 'react-native-callkeep';

const BACKGROUND_NOTIFICATION_TASK = "BACKGROUND-NOTIFICATION-TASK";

TaskManager.defineTask(
  BACKGROUND_NOTIFICATION_TASK,
  ({ data, error, executionInfo }) => {
    if (error) {
      console.log("Error occurred:", error);
    }
    if (data) {
      console.log("Data received:", data);
      let res = JSON.parse(data.notification.data.body);
      CallKeep.displayIncomingCall(res.uuid, "9999999999", res.instructorName, 'generic', true);
    }
  }
);

Notifications.registerTaskAsync(BACKGROUND_NOTIFICATION_TASK);

export default class App extends Component {
  componentDidMount() {
    // Any other initialization
  }

  render() {
    return (
      <Provider store={store}>
        <Routes />
      </Provider>
    );
  }
};

registerRootComponent(App);

当前状态:应用前台、后台状态下运行正常,收到纯数据通知时会触发后台任务,CallKeep可成功显示来电界面。通知负载示例:

{
  "to": "device_token",
  "data": {
    "customKey": "customValue"
  }
}

问题:应用被终止(被杀/关闭)时,后台任务无法触发,来电界面不显示(测试环境为Android)。


解决方案(Android平台)

1. 修改推送负载为带可见通知的格式

Expo的TaskManager在应用被完全杀死后,无法处理纯data字段的推送,必须包含notification字段(即带有可见通知栏提示的推送)才能唤醒后台任务。调整后的推送负载:

{
  "to": "device_token",
  "notification": {
    "title": "来电提醒",
    "body": "有新的来电",
    "sound": "default"
  },
  "data": {
    "uuid": "unique-call-id",
    "instructorName": "讲师姓名",
    "phoneNumber": "9999999999"
  }
}

2. 配置应用权限与插件参数

在app.json中添加必要的权限声明和插件配置,确保系统允许应用后台运行并显示来电界面:

{
  "expo": {
    "android": {
      "permissions": [
        "RECEIVE_BOOT_COMPLETED",
        "FOREGROUND_SERVICE",
        "READ_PHONE_STATE",
        "CALL_PHONE"
      ],
      "useNextNotificationsApi": true
    },
    "plugins": [
      [
        "expo-notifications",
        {
          "icon": "./assets/notification-icon.png",
          "color": "#ffffff",
          "sounds": ["./assets/ringtone.mp3"]
        }
      ],
      [
        "react-native-callkeep",
        {
          "ios": {
            "appName": "你的应用名称"
          },
          "android": {
            "alertTitle": "来电权限申请",
            "alertDescription": "应用需要权限才能显示来电界面",
            "cancelButton": "取消",
            "okButton": "允许"
          }
        }
      ]
    ]
  }
}

3. 优化后台任务逻辑

确保应用被唤醒时CallKeep已完成初始化,正确解析推送中的来电数据:

TaskManager.defineTask(
  BACKGROUND_NOTIFICATION_TASK,
  async ({ data, error, executionInfo }) => {
    if (error) {
      console.error("后台任务执行错误:", error);
      return;
    }
    // 解析推送中的来电数据
    const callData = data?.notification?.data;
    if (!callData) return;

    // 初始化CallKeep(应用被杀死后唤醒时需重新初始化)
    CallKeep.setup({
      ios: {
        appName: "你的应用名称"
      },
      android: {
        alertTitle: "来电权限申请",
        alertDescription: "应用需要权限才能显示来电界面",
        cancelButton: "取消",
        okButton: "允许"
      }
    });

    // 显示来电界面
    CallKeep.displayIncomingCall(
      callData.uuid,
      callData.phoneNumber,
      callData.instructorName,
      'generic',
      true
    );
  }
);

4. 处理Android厂商的后台限制

多数Android厂商(小米、华为、OPPO等)会对被杀死的应用做后台运行限制,需要引导用户完成以下设置:

  • 关闭应用的电池优化(设置 -> 电池 -> 电池优化 -> 找到应用 -> 选择不优化)
  • 开启应用的自启动权限(不同厂商路径不同,一般在应用设置的权限或自启动选项中)
  • 在多任务界面将应用锁定到后台(下拉应用卡片即可锁定)

可以在应用首次启动时添加引导弹窗,告知用户开启这些权限以保证来电通知正常工作。

5. 使用EAS Build构建正式包

Expo Go在测试后台任务时存在沙箱限制,无法完全模拟生产环境的行为。使用EAS Build构建正式的APK/AAB包,能更准确地测试应用被终止后的来电通知触发逻辑。


内容的提问来源于stack exchange,提问作者Pradeep Charan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 05:44:55