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

Flutter Firebase推送getInitialMessage为null、点击回调不触发

问题根因
  • 推送payload与代码逻辑不匹配:后端当前推送仅携带notification字段,未携带自定义data字段,但你的代码中所有读取通知标题、内容的逻辑都从message.data取值,实际运行时message.data为空对象,不仅会导致手动弹出的通知标题内容为空,还会触发空指针报错打断消息处理流程。
  • 通知点击事件归属逻辑混淆:Firebase Messaging提供的getInitialMessage、onMessageOpenedApp两个回调,仅能响应FCM系统自动弹出的通知的点击事件。你在前台消息监听、后台消息处理回调中手动调用flutter_local_notifications弹出的通知属于本地通知,FCM不会接管这部分通知的点击事件,必须通过本地通知插件自身的回调监听点击。
  • 本地通知配置缺失:你在多个位置重复初始化FlutterLocalNotificationsPlugin,但全程没有配置本地通知的点击回调,也没有处理应用冷启动时点击本地通知的场景,手动弹出的通知点击后自然不会触发跳转。
  • 代码逻辑存在硬伤:getInitialMessage回调中直接使用message!做强制非空断言,当message为null时直接触发红屏报错;没有使用全局导航Key,跳转时依赖的State上下文在路由树未挂载完成时无效,导致跳转失败;后台消息处理中重复初始化本地通知、重复弹出通知,既会造成通知栏显示多条重复消息,也会打乱FCM的事件分发逻辑。
  • 权限与清单配置缺失:安卓12及以上版本未给启动Activity配置exported="true"属性、安卓13+未申请通知权限、iOS端关闭了通知权限申请,都会导致通知点击事件无法正常分发给应用。
修复方案

按步骤调整即可:

  1. 统一全局导航能力
    在全局位置定义导航Key,避免路由跳转时拿不到有效上下文:
    final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
    
    给MaterialApp绑定该Key:
    MaterialApp(
      navigatorKey: navigatorKey, // 绑定全局key
      debugShowCheckedModeBanner: false,
      home: SplashScreen(),
      // 其他配置保持不变
    )
    
  2. 统一本地通知初始化逻辑
    删除_firebaseMessagingBackgroundHandler、initState中所有本地通知初始化的重复代码,在main函数中统一初始化本地通知,同时配置点击回调、冷启动点击处理逻辑:
    Future<void> initLocalNotifications() async {
      const AndroidInitializationSettings androidInit = AndroidInitializationSettings('@mipmap/ic_launcher');
      const IOSInitializationSettings iosInit = IOSInitializationSettings(
        requestSoundPermission: true,
        requestBadgePermission: true,
        requestAlertPermission: true,
      );
      const InitializationSettings initSettings = InitializationSettings(android: androidInit, iOS: iosInit);
      
      // 注册前台运行时本地通知点击回调
      await flutterLocalNotificationsPlugin.initialize(
        initSettings,
        onSelectNotification: (String? payload) async {
          if (payload == null) return;
          // 可根据payload携带的参数跳转不同页面,示例为跳转指定页面
          navigatorKey.currentState?.push(MaterialPageRoute(builder: (_) => DoneAndPaiedPagess(0)));
        },
      );
    
      // 处理应用完全终止时,点击本地通知启动的场景
      final NotificationAppLaunchDetails? launchDetail = await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();
      if (launchDetail != null && launchDetail.didNotificationLaunchApp) {
        WidgetsBinding.instance.addPostFrameCallback((_) {
          navigatorKey.currentState?.push(MaterialPageRoute(builder: (_) => DoneAndPaiedPagess(0)));
        });
      }
    }
    
    在main函数runApp之前调用await initLocalNotifications();完成初始化。
  3. 调整FCM消息处理逻辑,避免重复弹通知
    • 清理_firebaseMessagingBackgroundHandler逻辑:该回调中仅处理角标存储等数据逻辑,不要调用flutterLocalNotificationsPlugin.show弹通知——应用在后台、终止状态时,只要payload携带notification字段,FCM会自动弹出系统通知,手动重复弹会导致通知重复、点击事件无法被FCM捕获。
    • 调整前台onMessage逻辑:应用在前台时FCM不会自动弹通知,此时再调用本地通知插件弹出通知即可,弹通知时传入payload供点击回调使用:
      FirebaseMessaging.onMessage.listen((RemoteMessage message) {
        final RemoteNotification? notification = message.notification;
        final AndroidNotification? androidNoti = message.notification?.android;
      
        // 原有角标处理逻辑
        if (message.data['title']?.toString().toLowerCase() == "new request") {
          SessionManager sessionManager = SessionManager(navigatorKey.currentContext!);
          sessionManager.getBadge().then((badge) {
            final int newBadge = (badge ?? 0) + 1;
            strikeNotifier.value = newBadge;
            sessionManager.saveBadge(newBadge);
          });
        }
      
        // 仅前台时手动弹本地通知
        if (notification != null && androidNoti != null) {
          flutterLocalNotificationsPlugin.show(
            notification.hashCode,
            notification.title,
            notification.body,
            NotificationDetails(
              android: AndroidNotificationDetails(
                channel.id,
                channel.name,
                importance: Importance.high,
                priority: Priority.high,
                playSound: true,
                icon: '@mipmap/ic_launcher',
              ),
              iOS: const IOSNotificationDetails(),
            ),
            payload: 'jump_page', // 可序列化自定义参数传入
          );
        }
      });
      
    • 修复FCM点击回调逻辑,去掉强制非空断言,使用全局Key做跳转:
      // 处理应用完全终止时点击FCM自动通知启动的场景
      FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) {
        if (message == null) return;
        WidgetsBinding.instance.addPostFrameCallback((_) {
          // 根据消息参数判断跳转目标,示例为跳转注册页
          navigatorKey.currentState?.push(MaterialPageRoute(builder: (_) => Register()));
        });
      });
      
      // 处理应用在后台时点击FCM自动通知的场景
      FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
        navigatorKey.currentState?.push(MaterialPageRoute(builder: (_) => DoneAndPaiedPagess(0)));
      });
      
  4. 调整后端推送payload
    推送时同时携带notification和data字段,将跳转需要的自定义参数放入data字段,示例结构:
    {
      "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
      "notification":{
        "title":"Portugal vs. Denmark",
        "body":"great match!"
      },
      "data":{
        "jump_type":"match_detail",
        "match_id":"12345"
      }
    }
    
  5. 补全权限与清单配置
    • 安卓端:找到AndroidManifest.xml中的MainActivity配置,添加android:exported="true"属性(安卓12+必须配置);在应用启动时申请安卓13+的POST_NOTIFICATIONS运行时权限。
    • iOS端:应用启动时调用FirebaseMessaging.instance.requestPermission()申请通知权限,不要在初始化本地通知时关闭权限申请开关。

内容的提问来源于stack exchange,提问作者Ahmed Elsayed

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 12:27:44