Flutter Firebase Cloud Messaging自定义通知处理问题求助
问题解决方案
核心问题分析
你遇到两个关键问题:
- 前台/后台收到FCM通知时显示两条重复通知
- 点击后台自定义通知时报错
Attempted to start a duplicate background isolate,且预设逻辑不执行
问题1:重复显示两条通知
原因
- 前台:FCM默认会自动展示通知(你设置了
alert: true),同时你在onMessage回调里又调用自定义通知方法,导致重复弹窗。 - 后台:如果发送的是FCM的
notification类型消息,系统会自动弹出默认通知;同时你的fcmBackgroundMessageHandler里又触发自定义通知,造成双重弹窗。
解决方案
前台禁用FCM默认通知
修改FCMService的initialize方法,关闭前台自动弹窗:await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions( alert: false, // 禁止FCM前台自动弹通知 badge: true, sound: true, );这样前台仅会触发
onMessage回调,由你的自定义通知逻辑弹窗。后台统一自定义通知
发送FCM消息时仅使用data字段(不要包含notification字段),系统不会自动弹窗,完全由你的fcmBackgroundMessageHandler控制自定义通知的展示。
问题2:后台通知点击报错及逻辑失效
原因
showNotification方法里重复初始化flutterLocalNotificationsPlugin,导致后台回调被重复注册,引发隔离重复启动错误。- 后台Isolate没有Flutter UI上下文,直接调用
Fluttertoast无法执行(Toast依赖UI环境)。
解决方案
移除重复初始化代码
修改NotificationService的showNotification方法,删除重复的初始化逻辑(单例已在main中初始化完成):showNotification(RemoteMessage message) { // 删掉以下两行重复初始化代码 // var initializationSettings = InitializationSettings(android: _initializationSettingsAndroid); // flutterLocalNotificationsPlugin.initialize(initializationSettings, ...); flutterLocalNotificationsPlugin.show( DateTime.now().millisecondsSinceEpoch, // 用时间戳做通知ID,避免覆盖旧通知 message.data['title'], message.data['body'], NotificationDetails( android: AndroidNotificationDetails( _androidChannel.id, // 复用已创建的渠道ID,不要硬编码 _androidChannel.name, channelDescription: _androidChannel.description, color: Colors.blue, playSound: true, ), )); }修正后台通知处理逻辑
后台无法直接使用Toast,改用本地存储记录点击事件,待APP启动后再处理:@pragma('vm:entry-point') Future<void> _handleBackgroundNotification(NotificationResponse response) async { // 后台Isolate无UI上下文,用SharedPreferences记录点击状态 final prefs = await SharedPreferences.getInstance(); await prefs.setString('bg_notification_click', '后台通知已点击'); // 如需操作Firebase,确保后台初始化 await Firebase.initializeApp(); }在APP启动时读取并处理:
class MyApp extends StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { @override void initState() { super.initState(); _checkBgNotificationClick(); } void _checkBgNotificationClick() async { final prefs = await SharedPreferences.getInstance(); final clickMsg = prefs.getString('bg_notification_click'); if (clickMsg != null) { Fluttertoast.showToast(msg: clickMsg); await prefs.remove('bg_notification_click'); } } // ... 其余代码 }确保后台初始化正确
在后台消息处理函数中初始化NotificationService(后台Isolate是独立环境,需单独初始化):Future<void> fcmBackgroundMessageHandler(RemoteMessage message) async { await Firebase.initializeApp(); await NotificationService().initialize(); // 后台环境初始化通知服务 NotificationService().showNotification(message); }
额外优化
- 在NotificationService中添加初始化标记,避免重复初始化:
class NotificationService { bool _isInitialized = false; initialize() async { if (_isInitialized) return; // 原初始化代码... _isInitialized = true; } }
内容的提问来源于stack exchange,提问作者Tosif Khan
相关产品推荐
相关产品推荐

