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

如何从Reactjs后台向Android和iOS设备发送Expo推送通知?

实现Expo跨平台推送通知(Android+iOS)结合Firebase后台

问题背景

我有一款同时支持Android和iOS的Expo应用,后端基于Firebase;还开发了一个ReactJS后台系统。当在后台执行特定操作(比如将订单状态从pending改为delivered,Firebase集合中对应用户的订单状态同步更新)时,需要向该用户发送推送通知,告知订单已发货。如何实现同时支持双平台的推送功能?


解决方案

一、客户端(Expo应用)配置

1. 安装依赖

npx expo install expo-notifications

2. 全局通知配置(组件外部)

import * as Notifications from 'expo-notifications';

// 全局配置通知处理规则
Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowAlert: true,
    shouldPlaySound: false,
    shouldSetBadge: false,
  }),
});

3. 组件内部代码(获取Token+监听通知)

import { useState, useEffect, useRef } from 'react';
import { Device, Platform } from 'react-native';
import * as Notifications from 'expo-notifications';

const [expoPushToken, setExpoPushToken] = useState('');
const [notification, setNotification] = useState(false);
const notificationListener = useRef();
const responseListener = useRef();

// 客户端测试用:发送通知到当前设备
async function sendPushNotification(expoPushToken) {
  const message = {
    to: expoPushToken,
    sound: 'default',
    title: '测试通知',
    body: '这是一条测试推送',
    data: { testData: '自定义内容' },
  };

  console.log('当前设备Token:', expoPushToken);

  await fetch('https://exp.host/--/api/v2/push/send', {
    method: 'POST',
    headers: {
      Accept: 'application/json',
      'Accept-encoding': 'gzip, deflate',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(message),
  });
}

// 申请通知权限并获取推送Token
async function registerForPushNotificationsAsync() {
  let token;
  if (Device.isDevice) {
    // 检查已有权限
    const { status: existingStatus } = await Notifications.getPermissionsAsync();
    let finalStatus = existingStatus;
    
    // 无权限则申请
    if (existingStatus !== 'granted') {
      const { status } = await Notifications.requestPermissionsAsync();
      finalStatus = status;
    }
    
    if (finalStatus !== 'granted') {
      alert('无法获取推送权限,请在设置中开启');
      return;
    }
    
    // 获取Expo推送Token
    token = (await Notifications.getExpoPushTokenAsync()).data;
    console.log('推送Token:', token);
    
    // TODO: 将Token与用户UID关联,存储到Firebase数据库
  } else {
    alert('推送通知仅支持物理设备,请使用真机测试');
  }

  // Android配置通知渠道
  if (Platform.OS === 'android') {
    Notifications.setNotificationChannelAsync('default', {
      name: 'default',
      importance: Notifications.AndroidImportance.MAX,
      vibrationPattern: [0, 250, 250, 250],
      lightColor: '#FF231F7C',
    });
  }

  return token;
}

// 初始化监听
useEffect(() => {
  // 获取Token并保存
  registerForPushNotificationsAsync().then(token => setExpoPushToken(token));

  // 监听应用前台收到的通知
  notificationListener.current = Notifications.addNotificationReceivedListener(notification => {
    setNotification(notification);
  });

  // 监听用户点击通知的行为(前台/后台/杀死状态均生效)
  responseListener.current = Notifications.addNotificationResponseReceivedListener(response => {
    console.log('用户点击通知:', response);
    // 可在此处处理跳转逻辑,比如打开订单详情页
  });

  // 清理监听
  return () => {
    Notifications.removeNotificationSubscription(notificationListener.current);
    Notifications.removeNotificationSubscription(responseListener.current);
  };
}, []);

关键说明

获取到的推送Token格式示例:ExponentPushToken[KA2CcEFolWMq_9TmIddctr],需将该Token与用户的Firebase UID绑定,存储到Firebase数据库(比如新增一个userPushTokens集合,以UID为文档ID,保存对应的Token列表)。


二、服务端(ReactJS后台)实现

1. 安装依赖

npm i node-fetch

2. 发送通知的核心代码

import fetch from "node-fetch";

/**
 * 向指定用户发送推送通知
 * @param {string} expoPushToken - 用户的Expo推送Token
 */
async function sendPushNotification(expoPushToken) {
  const message = {
    to: expoPushToken,
    sound: 'default',
    title: '订单状态更新',
    body: '您的订单已发货,请注意查收!',
    data: { 
      orderStatus: 'delivered',
      // 可携带订单ID等自定义数据,客户端点击后可跳转对应页面
      orderId: 'ORD123456' 
    },
  };

  try {
    await fetch('https://exp.host/--/api/v2/push/send', {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Accept-encoding': 'gzip, deflate',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(message),
    });
    console.log('通知发送成功');
  } catch (error) {
    console.error('通知发送失败:', error);
  }
}

3. 触发通知的逻辑

在后台修改订单状态的代码中,添加以下步骤:

  1. 当订单状态从pending更新为delivered时,获取该订单关联的用户UID
  2. 根据UID从Firebase数据库中查询对应的推送Token
  3. 调用sendPushNotification函数,传入Token发送通知

示例触发代码:

// 假设订单更新逻辑
async function updateOrderStatus(orderId, newStatus) {
  // 更新Firebase中的订单状态
  await db.collection('orders').doc(orderId).update({ status: newStatus });

  // 如果状态改为delivered,发送通知
  if (newStatus === 'delivered') {
    // 获取订单所属用户UID
    const orderDoc = await db.collection('orders').doc(orderId).get();
    const userId = orderDoc.data().userId;
    
    // 获取用户的推送Token
    const userTokenDoc = await db.collection('userPushTokens').doc(userId).get();
    const pushToken = userTokenDoc.data().token;
    
    // 发送通知
    if (pushToken) {
      await sendPushNotification(pushToken);
    }
  }
}

内容的提问来源于stack exchange,提问作者Najeeb Ullah Khan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 10:31:12