最新 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 项目最主流的推送实现方案。

相关推荐
GuWenyue1 小时前
前端异步请求踩坑?3种方式搞定Ajax数据交互,从XHR到async/await
前端·javascript·设计模式
李白的天不白1 小时前
pnpm 启动前端项目
前端
lvchaoq1 小时前
从原理层面解释前端大数据量性能优化系列——分片加载
前端
杨先生哦2 小时前
2026 热端攻防:AI 驱动 Web 前端安全全景透析
前端·笔记·安全·web安全
李白的天不白2 小时前
SmartAdmin(基于 Spring Boot 框架)中配置跨域请求 VUE3 设置请求头
java·前端
一个被程序员耽误的厨师2 小时前
01-设计篇-我用前端那一套手艺造了一个AI-Native工具
前端·ai-native
不吃糖葫芦32 小时前
vue3实现拓扑图编辑功能(谨以此纪念我当前的最后一份前端工作)
前端
大家的林语冰2 小时前
超越 TypeScript,Flow 强势回归,语法高仿 TS,功能更丰富,类型更安全!
前端·javascript·typescript