如何从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. 触发通知的逻辑
在后台修改订单状态的代码中,添加以下步骤:
- 当订单状态从
pending更新为delivered时,获取该订单关联的用户UID - 根据UID从Firebase数据库中查询对应的推送Token
- 调用
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
相关产品推荐
相关产品推荐

