React Native云消息:后台/静默模式双通知及Notifee跳转问题
React Native FCM+Notifee 双通知及点击跳转问题解决
问题核心
- 应用在后台/静默模式下会收到两条通知:一条由Firebase自动展示,一条由Notifee生成
- Notifee通知点击后无法打开应用,也无法跳转指定页面;Firebase通知则正常
一、解决双通知问题
原因
当推送消息包含notification字段时,Firebase在后台/静默状态会自动触发系统通知,同时你的setBackgroundMessageHandler又调用Notifee展示了一条通知,导致重复。
解决方案
1. 修改推送消息格式
去掉notification字段,把标题、内容全部放到data中(纯数据消息):
{ "registration_ids": ["device-tokens......"], "data": { "channel_id": "demo-channel", "channel_name": "demo-channel", "sound_name": "default", "title": "Test notification title!", "body": "Test notificaton body", "redirect_to": "Menu" // 新增跳转目标标识 } }
2. 更新onDisplayNotification函数
从data字段读取标题内容,同时配置通知的点击动作:
export async function onDisplayNotification(data: any) { if (Platform.OS === 'ios') { await notifee.requestPermission(); } const channelId = await notifee.createChannel({ id: data?.data?.channel_id, name: data?.data?.channel_name, sound: data?.data?.sound_name, }); await notifee.displayNotification({ title: data?.data?.title, body: data?.data?.body, android: { smallIcon: 'ic_launcher', channelId, color: BlueColor, // 配置Android点击动作,必须设置才能打开应用 pressAction: { id: 'default', }, }, ios: { foregroundPresentationOptions: { alert: true, badge: true, sound: true, }, // iOS也必须配置pressAction pressAction: { id: 'default', }, }, // 携带消息数据,点击时可读取跳转信息 data: data?.data, }); }
二、实现Notifee通知点击跳转
1. 添加Notifee通知点击监听
修改notificationListner函数,新增Notifee的前后台事件监听:
import AsyncStorage from '@react-native-async-storage/async-storage'; import { EventType } from '@notifee/react-native'; export async function notificationListner() { // 前台FCM消息监听(保留原逻辑) const unsubscribe = messaging().onMessage(async remoteMessage => { console.log('A new FCM message arrived!', remoteMessage); await onDisplayNotification(remoteMessage); }); // 前台状态下的Notifee通知点击 notifee.onForegroundEvent(async ({ type, detail }) => { if (type === EventType.PRESS) { const redirectData = detail.notification.data; console.log('前台点击Notifee通知:', redirectData); // 直接跳转指定页面 if (redirectData?.redirect_to === 'Menu') { NavigationService.navigate('Menu', { data: redirectData }); } } }); // 后台/关闭状态下的Notifee通知点击 notifee.onBackgroundEvent(async ({ type, detail }) => { if (type === EventType.PRESS) { const redirectData = detail.notification.data; console.log('后台点击Notifee通知:', redirectData); // 后台无法直接跳转,存储参数等应用启动后处理 await AsyncStorage.setItem('notificationRedirect', JSON.stringify(redirectData)); } }); // 应用从关闭状态启动时,检查跳转参数 messaging() .getInitialNotification() .then(async () => { const redirectStr = await AsyncStorage.getItem('notificationRedirect'); if (redirectStr) { const redirectData = JSON.parse(redirectStr); if (redirectData?.redirect_to === 'Menu') { // 延迟确保导航初始化完成 setTimeout(() => { NavigationService.navigate('Menu', { data: redirectData }); }, 1000); } // 用完删除参数 await AsyncStorage.removeItem('notificationRedirect'); } }); return unsubscribe; }
2. 关键注意点
- Android:必须配置
pressAction.id = 'default'才能触发打开应用的动作 - iOS:
pressAction是必填项,同时确保Info.plist中已开启通知权限 - 导航跳转:确保
NavigationService已正确配置,支持非组件环境调用导航 - 后台处理:后台事件中不能直接调用导航,需通过
AsyncStorage暂存参数,待应用启动后处理
三、后台处理器保持原逻辑即可
messaging().setBackgroundMessageHandler(async remoteMessage => { await onDisplayNotification(remoteMessage); console.log('Message handled in the background!', remoteMessage); });
内容的提问来源于stack exchange,提问作者Md. Al Amin
相关产品推荐
相关产品推荐

