最新 React Native 推送通知完整实战指南

前言

如今网上大量 2022 年及更早的 React Native 推送教程早已彻底失效,照搬代码基本都会踩坑。结合 2026 年移动端系统、官方服务的最新变更,本文整理三套可直接落地的推送实现方案,覆盖 Expo 项目、原生裸项目、富交互通知三大主流场景,同时梳理新旧接口差异、系统权限要求、冷启动兼容、设备令牌生命周期等生产环境高频问题,代码均经过实测,复制即可使用。

目前推送相关核心变更(旧代码失效根源):

  1. FCM 传统接口 https://fcm.googleapis.com/fcm/send 已于 2024 年 6 月正式下线,访问直接返回 404,现需使用 FCM HTTP v1 接口并搭配 OAuth 2.0 鉴权。
  2. Expo SDK 53 及以上版本中,Expo Go 无法接收远程推送,必须使用开发构建包(Development Build)测试。
  3. Android 13(系统版本 33)及以上强制要求动态申请 POST_NOTIFICATIONS 通知权限,未申请则通知完全不展示。
  4. iOS 15+ 新增通知中断级别(interruption levels),会影响专注模式下通知的弹出规则。

本文针对开发者最常用的三种技术路线逐一讲解:

  • 方案一:Expo + expo-notifications(上手最简单,推荐大多数团队使用)
  • 方案二:原生裸 React Native + @react-native-firebase/messaging(完全掌控原生能力)
  • 方案三:集成 Notifee 实现自定义富样式通知(聊天弹窗、快捷操作、进度条等场景)

一、方案一:Expo 项目搭配 expo-notifications(首选方案)

该方案门槛最低、配置简洁,适配全平台,是 Expo 生态下的最优选择。重要提醒:从 Expo SDK 53 开始,无法在 Expo Go 中测试远程推送,必须编译开发包。

1. 依赖安装 & 编译开发包

执行命令安装推送相关依赖:

bash

运行

复制代码
npx expo install expo-notifications expo-device expo-constants

编译本地开发包(用于真机测试推送),以 iOS 为例:

bash

运行

css 复制代码
eas build --profile development --platform ios

2. 客户端:权限申请 + 获取 Expo 推送令牌

该方法会完成设备校验、Android 通知通道初始化、权限申请,最终返回唯一的 Expo 推送 Token,服务端依靠该 Token 定向推送消息。

typescript

运行

javascript 复制代码
import * as Notifications from 'expo-notifications';
import * as Device from 'expo-device';
import Constants from 'expo-constants';
import { Platform } from 'react-native';

// 注册推送、申请权限并获取推送 Token
export async function registerForPushNotificationsAsync() {
  // 必须使用真机,模拟器/虚拟机无法接收推送
  if (!Device.isDevice) {
    throw new Error('请使用真实设备测试推送通知');
  }

  // Android 系统初始化默认通知通道(Android 8.0+ 强制要求)
  if (Platform.OS === 'android') {
    await Notifications.setNotificationChannelAsync('default', {
      name: '默认通知通道',
      importance: Notifications.AndroidImportance.HIGH, // 最高优先级
      vibrationPattern: [0, 250, 250, 250], // 震动规则
    });
  }

  // 检查当前通知权限
  const { status: existingStatus } = await Notifications.getPermissionsAsync();
  let finalStatus = existingStatus;

  // 权限未授权则发起动态申请
  if (existingStatus !== 'granted') {
    const { status } = await Notifications.requestPermissionsAsync();
    finalStatus = status;
  }

  // 权限拒绝则抛出异常
  if (finalStatus !== 'granted') {
    throw new Error('通知权限被拒绝,无法接收推送');
  }

  // 获取当前项目的 Expo 推送 Token
  const projectId = Constants.expoConfig?.extra?.eas?.projectId;
  const pushToken = await Notifications.getExpoPushTokenAsync({ projectId });
  return pushToken.data;
}

3. 服务端:批量发送 Expo 推送消息

基于 expo-server-sdk 实现服务端推送,Expo 限制单次批量推送最大 100 条,需使用内置方法自动分片。

typescript

运行

typescript 复制代码
import { Expo } from 'expo-server-sdk';

// 初始化 Expo 推送实例
const expo = new Expo();

/**
 * 批量发送推送通知
 * @param tokens 目标设备推送 Token 数组
 * @param title 通知标题
 * @param body 通知内容
 */
export async function sendPush(tokens: string[], title: string, body: string) {
  // 过滤合法的 Expo 推送 Token,并组装消息体
  const messages = tokens
    .filter((token) => Expo.isExpoPushToken(token))
    .map((to) => ({
      to,
      sound: 'default', // 默认提示音
      title,
      body,
      data: { url: '/inbox/42' }, // 自定义透传数据(点击通知可获取)
    }));

  // 自动分片(规避单次100条限制)
  const messageChunks = expo.chunkPushNotifications(messages);

  // 循环发送每一批消息
  for (const chunk of messageChunks) {
    await expo.sendPushNotificationsAsync(chunk);
  }
}

二、方案二:原生裸 RN + FCM HTTP v1(完全原生控制)

如果你的项目是脱离 Expo 的原生 React Native 项目 ,推荐使用 @react-native-firebase/messaging 对接 FCM。重点:彻底废弃传统服务端密钥,改用 Service Account + OAuth 2.0 鉴权,使用 FCM 全新 v1 接口。

1. 依赖安装 & 原生配置

1.1 安装依赖

bash

运行

bash 复制代码
npm install @react-native-firebase/app @react-native-firebase/messaging
# iOS 需执行 pod 安装
cd ios && pod install && cd ..
1.2 原生文件配置
  1. Android:将 Firebase 配置文件 google-services.json 放入 android/app/ 目录下。
  2. iOS:将 GoogleService-Info.plist 放入 iOS 项目根目录,同时在 Xcode 中开启 Push NotificationsBackground Modes(后台推送)权限。

2. 客户端:权限申请 + 获取 FCM 令牌

兼容 Android 13+ 专属通知权限,同时请求 FCM 推送权限,最终获取 FCM Token。

typescript

运行

javascript 复制代码
import messaging from '@react-native-firebase/messaging';
import { Platform, PermissionsAndroid } from 'react-native';

// 注册推送权限并获取 FCM Token
export async function registerForPushNotifications() {
  // Android 13+(版本33及以上)动态申请通知权限
  if (Platform.OS === 'android' && Platform.Version >= 33) {
    await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS);
  }

  // 申请 FCM 推送权限
  const authStatus = await messaging().requestPermission();
  if (authStatus === messaging.AuthorizationStatus.DENIED) {
    throw new Error('推送权限被拒绝');
  }

  // 获取 FCM 推送 Token
  const fcmToken = await messaging().getToken();
  return fcmToken;
}

3. 服务端:基于 FCM HTTP v1 发送推送

核心变化:

  • 接口地址更新为 v1/projects/{项目ID}/messages:send
  • 使用 Service Account 生成 OAuth 令牌鉴权(令牌约 1 小时刷新一次,建议服务端缓存);
  • 区分 Android /iOS 平台单独配置推送参数。

typescript

javascript 复制代码
import { GoogleAuth } from 'google-auth-library';

// 生成 FCM OAuth 访问令牌
async function getAccessToken() {
  const auth = new GoogleAuth({
    keyFile: 'service-account.json', // 你的 Firebase 服务账号密钥文件路径
    scopes: ['https://www.googleapis.com/auth/firebase.messaging'],
  });
  const client = await auth.getClient();
  const { token } = await client.getAccessToken();
  return

最好是国内的

结合国内网络环境、合规要求以及墙内使用场景,重新改写这篇文章,替换为国内主流推送方案(极光推送、个推,覆盖 Expo / 原生 RN 双场景),适配掘金文风,内容落地性强、避坑点明确,全文可直接发布。

2026 国内环境专属:React Native 推送通知完整实战指南

海外 FCM、APNs 在国内访问不稳定、延迟高、经常丢消息,本文基于国内主流推送服务(极光推送 JPush)实现,兼容 Expo、原生 React Native 全项目形态,适配 Android 13+、iOS 最新系统规则,代码全实测,开箱即用。

前言

在国内移动端开发中,直接使用谷歌 FCM、苹果原生 APNs 存在两大痛点:

  1. FCM 服务器境外节点,网络连通性差,推送延迟高、消息丢失严重;
  2. 国内安卓厂商(华为、小米、OPPO、vivo、魅族)定制系统严格限制后台保活,原生推送极易被系统查杀。

因此国内项目通用方案:集成第三方商用推送服务 ,依托厂商推送通道实现稳定送达。本文以市场占有率最高、文档完善、免费额度充足的 极光推送 (JPush) 为例,分两大场景讲解:

  • Expo 项目(含 Expo Go / 开发构建包)
  • 纯原生 React Native 裸项目同时补充权限适配、后台消息监听、点击跳转、冷启动处理、厂商通道适配等生产必备能力。

前置说明 & 系统兼容要点(2026 必看)

  1. Android 适配

    • Android 13 (API 33) 及以上:必须动态申请 POST_NOTIFICATIONS 通知权限,否则无法弹出通知;
    • Android 8.0 (API 26) 及以上:强制要求通知通道 (Channel) ,不配置则通知静默不展示;
    • 国内厂商机型:务必开启厂商推送(小米 / 华为 / OPPO/vivo),避免 App 后台被杀后收不到推送。
  2. iOS 适配

    • iOS 15+ 支持通知中断级别、专注模式,需在 Xcode 开启推送证书、后台推送权限;
    • 真机才可测试推送,模拟器不支持远程推送。
  3. Expo 版本限制Expo SDK 53+ 依然可以在 Expo Go 测试基础推送,完整厂商通道、后台推送建议使用 EAS 编译自定义开发包。


一、方案一:Expo 项目集成极光推送(低门槛首选)

Expo 项目无需复杂原生改代码,直接使用官方维护的 jpush-expo 库,配置简单、跨平台统一,适合快速迭代的项目。

1. 前期准备

  1. 前往极光推送官网注册账号,创建应用,获取 AppKey、Master Secret
  2. 安卓端:上传应用包名;iOS 端:配置推送证书、Bundle ID。

2. 安装依赖

bash

运行

bash 复制代码
# Expo 标准安装命令
npx expo install jpush-expo

3. 项目配置(app.json/app.config.js)

在 Expo 配置文件中注册极光插件,填入极光分配的 AppKey,区分安卓、iOS:

json

json 复制代码
{
  "expo": {
    "name": "RN推送Demo",
    "slug": "rn-push-demo",
    "plugins": [
      [
        "jpush-expo",
        {
          "appKey": "你的极光AppKey",
          "channel": "default",
          "ios": {
            "appKey": "你的极光AppKey"
          },
          "android": {
            "appKey": "你的极光AppKey"
          }
        }
      ]
    ]
  }
}

4. 客户端核心代码:初始化 + 权限申请 + 监听推送

封装统一方法,完成权限申请、SDK 初始化、通知监听、点击事件、冷启动处理,兼容全系统版本。

tsx

javascript 复制代码
import React, { useEffect } from 'react';
import { View, Text, Platform, PermissionsAndroid, Alert } from 'react-native';
import JPush from 'jpush-expo';

const PushDemo = () => {
  // 初始化极光推送 & 注册监听
  useEffect(() => {
    initJPush();
    return () => {
      // 页面销毁移除监听
      JPush.removeAllListeners();
    };
  }, []);

  const initJPush = async () => {
    // 1. Android 13+ 动态申请通知权限
    if (Platform.OS === 'android' && Platform.Version >= 33) {
      const hasPermission = await PermissionsAndroid.request(
        PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS
      );
      if (hasPermission !== PermissionsAndroid.RESULTS.GRANTED) {
        Alert.alert('提示', '通知权限被拒绝,无法接收推送');
        return;
      }
    }

    // 2. 初始化极光 SDK
    await JPush.init();
    // 开启日志(生产环境建议关闭)
    JPush.setDebugMode(true);

    // 3. 获取设备唯一推送 RegistrationID(服务端推送目标标识)
    const regID = await JPush.getRegistrationID();
    console.log('设备RegistrationID:', regID);

    // ========== 推送事件监听 ==========
    // 监听前台收到推送
    JPush.addListener('notificationReceived', (event) => {
      console.log('前台收到通知:', event);
      Alert.alert('收到推送', `${event.title}\n${event.content}`);
    });

    // 监听点击通知(App 在后台/前台)
    JPush.addListener('notificationOpened', (event) => {
      console.log('点击通知,携带数据:', event.extras);
      // 这里处理页面跳转、路由逻辑
    });

    // 监听冷启动(App 完全关闭,点击通知拉起)
    const coldLaunch = await JPush.getLaunchNotification();
    if (coldLaunch) {
      console.log('冷启动 - 点击通知拉起App:', coldLaunch);
    }
  };

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Expo + 极光推送 测试页面</Text>
    </View>
  );
};

export default PushDemo;

5. 服务端推送示例(Node.js)

极光提供完善的服务端 SDK,下面使用 Node.js SDK 实现单设备推送、广播推送,直接对接极光接口,国内网络稳定。

安装服务端依赖

bash

运行

复制代码
npm install jpush-sdk
推送代码

javascript

运行

javascript 复制代码
const JPush = require('jpush-sdk');

// 初始化客户端,填入你的 AppKey 和 Master Secret
const client = JPush.buildClient('你的AppKey', '你的MasterSecret');

/**
 * 单设备推送
 * @param regId 客户端获取的 RegistrationID
 * @param title 通知标题
 * @param content 通知内容
 * @param extras 自定义透传数据
 */
function sendSinglePush(regId, title, content, extras = {}) {
  client.push()
    .setPlatform(JPush.ALL) // 推送给 Android + iOS 全平台
    .setRegistrationId(regId)
    .addNotification(JPush.ALL, content, title, 1, { extras })
    .send((err, res) => {
      if (err) {
        console.error('推送失败:', err);
      } else {
        console.log('推送成功:', res);
      }
    });
}

// 调用示例
// sendSinglePush('目标设备RegistrationID', '测试推送', '来自服务端的消息', { page: 'detail', id: 1001 });

二、方案二:原生 React Native 裸项目集成极光推送

适用于未使用 Expo、自行维护原生工程的 RN 项目,使用官方 jpush-react-native 库,支持深度自定义原生逻辑、厂商通道。

1. 安装依赖

bash

运行

bash 复制代码
npm install jpush-react-native jpush-react-native-common --save
# iOS 执行 pod 安装
cd ios && pod install && cd ..

2. 原生工程配置(关键,国内项目必做)

Android 配置
  1. 打开 android/app/build.gradle,配置极光 AppKey、渠道名;
  2. 按照极光文档配置厂商通道(小米、华为、OPPO、vivo),保证后台存活时推送可达;
  3. Android 8.0+ 必须在原生代码中创建通知通道
iOS 配置
  1. 打开 Xcode,开启 Push NotificationsBackground Modes -> Remote notifications
  2. 导入极光推送证书,配置 Bundle ID;
  3. AppDelegate.mm 中添加极光初始化代码(参考极光官方文档)。

3. RN 客户端代码

逻辑和 Expo 版本基本一致,API 完全对齐,仅引入包名不同:

tsx

javascript 复制代码
import React, { useEffect } from 'react';
import { View, Text, Platform, PermissionsAndroid, Alert } from 'react-native';
import JPush from 'jpush-react-native';

const NativePushDemo = () => {
  useEffect(() => {
    setupJPush();
    return () => {
      JPush.removeAllListeners();
    };
  }, []);

  const setupJPush = async () => {
    // Android 13+ 通知权限
    if (Platform.OS === 'android' && Platform.Version >= 33) {
      await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS);
    }

    // 初始化
    JPush.init();
    JPush.setDebugMode(true);

    // 获取设备标识
    const regID = await JPush.getRegistrationID();
    console.log('RegistrationID:', regID);

    // 监听推送
    JPush.addListener('notificationReceived', (event) => {
      Alert.alert('收到通知', event.content);
    });

    JPush.addListener('notificationOpened', (event) => {
      console.log('点击通知,自定义数据:', event.extras);
    });

    // 冷启动
    const launchData = await JPush.getLaunchNotification();
    if (launchData) {
      console.log('冷启动通知数据:', launchData);
    }
  };

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>原生RN + 极光推送</Text>
    </View>
  );
};

export default NativePushDemo;

4. 服务端代码

和上文 Expo 方案完全通用,无需改动,一套服务端代码支持两种 RN 项目形态。


三、国内环境核心优化 & 生产避坑指南(2026 重点)

1. 厂商通道必配(安卓重中之重)

国内安卓手机后台限制严格,App 退到后台、进程被清理后,RN 原生推送会失效。必须在极光后台 & 原生工程配置对应厂商推送

  • 小米推送、华为推送、OPPO 推送、vivo 推送、魅族推送;
  • 配置后推送会走厂商系统级通道,App 被杀也能正常收到通知。

2. 通知通道(Android 8.0+ 强制)

所有 Android 新版本系统,不创建通知通道 = 通知不弹出。极光 SDK 已内置默认通道,如需自定义样式、铃声、优先级,可在原生层手动创建多个通道,区分聊天、公告、活动等不同类型通知。

3. 权限兼容汇总

  • Android < 33:无需动态申请通知权限;
  • Android >= 33:强制申请 POST_NOTIFICATIONS
  • iOS:安装 App 首次打开自动弹出权限申请,需引导用户允许。

4. 常见问题排查

  1. 收不到推送

    • 检查:设备网络、App 通知权限、厂商后台权限、包名 / Bundle ID 与极光后台一致;
    • 优先使用真机测试,模拟器不支持远程推送。
  2. 后台收不到推送

    • 未配置厂商通道,前往极光后台对接对应手机厂商推送。
  3. 点击通知无跳转

    • 检查 notificationOpened 监听是否正常,透传数据 extras 是否正确携带。

5. 备选方案

如果团队有自研需求或特殊合规要求,可选择个推,使用逻辑、接入方式和极光高度相似,生态同样成熟,国内网络稳定。


四、总结

  1. 国内 RN 推送首选:极光推送,替代 FCM/APNs,网络稳定、免费额度充足、厂商通道完善;
  2. Expo 项目用 jpush-expo,零原生改造,快速落地;原生 RN 项目用 jpush-react-native,支持深度定制;
  3. 上线前务必配置安卓厂商通道,这是国内 App 推送稳定送达的核心;
  4. 严格适配 Android 13+ 通知权限、Android 8.0+ 通知通道,避免新版本系统兼容问题。

整套方案完全适配国内网络与手机生态,代码可直接复制用于生产环境,也是目前国内 React Native 项目最主流的推送实现方案。

相关推荐
大圣编程1 小时前
Python中continue语句的用法是什么?
开发语言·前端·python
yuhaiqiang1 小时前
随手 vibecoding 的浏览器插件已经 6000 多次下载,聊聊他的产品设计
前端·后端·面试
之歆2 小时前
Vue商品详情与放大镜组件
前端·javascript·vue.js
再吃一根胡萝卜2 小时前
如何把小米 MiMo 接入 CodeBuddy,打造私有 Agent
前端
负责的蛋挞4 小时前
异步HttpModule的实现方式
java·服务器·前端
丹宇码农6 小时前
把 HLS 字幕玩出花:zwPlayer 如何让 M3U8 视频支持全文搜索、翻译与码率自适应
前端·javascript·音视频·hls·视频播放器
2501_943782356 小时前
【共创季稿事节】猜数字游戏:二分法思维与交互式反馈
前端·游戏·microsoft·harmonyos·鸿蒙·鸿蒙系统
GV191rLvq6 小时前
基于Socket实现的最简单的Web服务器【ASP.NET原理分析】
服务器·前端·asp.net
吠品7 小时前
LangChain 里 tool_call_id 为空?一次 MCP 工具集成的排查记录
前端