Flutter集成FCM在Android真机前台运行时重复接收通知问题咨询
问题原因
- 监听器重复注册:你没有在组件销毁/页面退出时取消
FirebaseMessaging.onMessage的订阅,页面多次打开、应用从后台恢复时会重复创建监听器,每个存活的监听器收到消息后都会独立触发一次Snackbar弹出。Android真机的进程生命周期管理逻辑和模拟器不同,更容易出现监听器残留的情况,因此问题仅在真机复现。 - FCM重试推送未折叠:你发送的FCM通知没有配置
collapse_key、tag这类唯一标识参数,网络不稳定时FCM会自动重试推送同一条消息,应用在后台时系统通知栏会自动合并重复内容的通知,前台运行时不会自动拦截重复回调,就会触发多次提示。 - 设备令牌重复存储:
widget.currMatch.deviceTokens列表中可能存在同一个用户的重复设备令牌,for循环会给同一个设备推送多次通知,前台直接触发回调就会显示多次。
解决方案
1. 正确管理监听器生命周期
在组件销毁时取消消息订阅,避免重复注册:
@override void dispose() { _listener?.cancel(); // 销毁前取消监听 super.dispose(); }
如果监听器注册在initState方法中,每次注册前要先取消已存在的订阅,避免重复创建多个监听器。
2. 配置FCM消息去重参数
发送FCM时添加唯一标识参数,让FCM和系统自动折叠重复消息:
- 同一个聊天会话的消息配置相同的
collapse_key,FCM会自动折叠同一个key的未推送消息,避免重复推送 - 单条消息配置唯一的
tag参数,相同tag的通知会被系统自动覆盖,不会多次触发回调
修改后的发送代码参考:
// 先对令牌列表去重 var uniqueTokens = widget.currMatch.deviceTokens.toSet().toList(); for (var d in uniqueTokens) { if (d != thisDeviceToken) Api().sendFcm( 'New Message', 'you have a new message in your chat', d, // 新增去重参数,currMatch.id为当前会话的唯一ID collapseKey: 'chat_${widget.currMatch.id}', tag: 'msg_${DateTime.now().millisecondsSinceEpoch}' ); }
3. 前端去重兜底
如果仍有偶发重复推送,可以在前端增加消息去重判断,同一条消息只处理一次:
// 存储最近处理的消息标识 String? lastProcessedMsgKey; _listener = FirebaseMessaging.onMessage.listen((RemoteMessage event) { // 用消息发送时间+内容生成唯一标识 var currentMsgKey = "${event.sentTime?.millisecondsSinceEpoch ?? ''}_${event.notification.body}"; if (currentMsgKey == lastProcessedMsgKey) return; lastProcessedMsgKey = currentMsgKey; print("message received"); print(event.notification.body); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(event.notification.body), duration: const Duration(seconds: 2), action: SnackBarAction( label: 'OK', onPressed: () {}, ), ), ); });
内容的提问来源于stack exchange,提问作者Val
相关产品推荐
相关产品推荐

