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

Flutter Firebase Cloud Messaging自定义通知处理问题求助

问题解决方案

核心问题分析

你遇到两个关键问题:

  1. 前台/后台收到FCM通知时显示两条重复通知
  2. 点击后台自定义通知时报错Attempted to start a duplicate background isolate,且预设逻辑不执行

问题1:重复显示两条通知

原因

  • 前台:FCM默认会自动展示通知(你设置了alert: true),同时你在onMessage回调里又调用自定义通知方法,导致重复弹窗。
  • 后台:如果发送的是FCM的notification类型消息,系统会自动弹出默认通知;同时你的fcmBackgroundMessageHandler里又触发自定义通知,造成双重弹窗。

解决方案

  1. 前台禁用FCM默认通知
    修改FCMService的initialize方法,关闭前台自动弹窗:

    await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
      alert: false, // 禁止FCM前台自动弹通知
      badge: true,
      sound: true,
    );
    

    这样前台仅会触发onMessage回调,由你的自定义通知逻辑弹窗。

  2. 后台统一自定义通知
    发送FCM消息时仅使用data字段(不要包含notification字段),系统不会自动弹窗,完全由你的fcmBackgroundMessageHandler控制自定义通知的展示。


问题2:后台通知点击报错及逻辑失效

原因

  1. showNotification方法里重复初始化flutterLocalNotificationsPlugin,导致后台回调被重复注册,引发隔离重复启动错误。
  2. 后台Isolate没有Flutter UI上下文,直接调用Fluttertoast无法执行(Toast依赖UI环境)。

解决方案

  1. 移除重复初始化代码
    修改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,
            ),
          ));
    }
    
  2. 修正后台通知处理逻辑
    后台无法直接使用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');
        }
      }
    
      // ... 其余代码
    }
    
  3. 确保后台初始化正确
    在后台消息处理函数中初始化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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 22:40:43