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

Flutter中FCM通知接收问题:后台/终止态处理及通知通道疑问

Flutter FCM通知问题排查与解决方案

问题场景

我正在梳理Flutter应用接收FCM通知的机制,按照官方文档实现了前台和后台监听逻辑,但遇到以下问题:

  1. 应用前台状态时,Firebase Composer发送的通知能正常触发日志记录;但后台状态时,通知仅显示在状态栏,_firebaseMessagingBackgroundHandler函数未被调用,无对应日志输出。
  2. 注释掉FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);后,日志提示需要注册后台处理器;但注册后,日志仅显示收到消息,处理器仍未执行。
  3. 日志中提示“Missing Default Notification Channel metadata in AndroidManifest”,不确定是否需要手动配置。
  4. 不清楚设备锁定(应用终止状态)时,如何处理通知。

我的实现代码如下:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  await initApp();
  runApp(const MyApp());
}

Future initApp() async {
  ...
  _initNotifications();
  ...
}

void _initNotifications() async {
  Logger.root.info("FCM token is: ${await FirebaseMessaging.instance.getToken()}");
  await FirebaseMessaging.instance.requestPermission(
    alert: true,
    announcement: false,
    badge: true,
    carPlay: false,
    criticalAlert: false,
    provisional: false,
    sound: true,
  );
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
  FirebaseMessaging.onMessage.listen((RemoteMessage message) {
    Logger.root.info('Got a message whilst in the foreground!');
    Logger.root.info('Message data: ${message.data}');

    if (message.notification != null) {
      Logger.root.info(
          'Message also contained a notification: ${message.notification!.toMap()}');
    }
  });
}

@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  Logger.root.info("Handling a background message: ${message.messageId}");
}

解决方案

一、确保后台消息处理器被触发

1. 修正处理器定义

_firebaseMessagingBackgroundHandler必须是顶级函数(不能嵌套在类或其他函数内部),且保留@pragma('vm:entry-point')注解,确保Dart虚拟机能在后台环境找到它。

2. 完善Firebase初始化

后台处理器中初始化Firebase时必须加await,否则初始化未完成就执行后续逻辑会导致异常:

@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  // 后台环境下Logger可能无法正常输出,改用print或专用日志工具
  print("Handling a background message: ${message.messageId}");
  print("Message data: ${message.data}");
}

3. 调整通知发送格式

通过Firebase Composer发送的纯通知消息(仅含notification payload),在后台状态下会被系统直接展示,不会触发Dart后台处理器。需要发送数据消息(仅含data payload)或混合消息(同时包含notification和data)才能触发处理器:

  • 测试用API请求示例(数据消息):
    {
      "to": "你的FCM设备令牌",
      "data": {
        "title": "后台测试",
        "body": "这是一条后台数据消息",
        "page": "detail"
      }
    }
    

4. 检查Android配置

  • 确保AndroidManifest.xml中存在FCM服务配置(FlutterFire通常自动生成,可验证):
    <service
        android:name="com.google.firebase.messaging.FirebaseMessagingService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>
    
  • 关闭应用的电池优化限制,确保后台进程能正常运行。

二、配置默认通知通道

Android 8.0(API 26)及以上强制要求设置通知通道,否则通知无法正常显示,需手动配置:

  1. 在android/app/src/main/res/values/strings.xml添加通道配置:
    <string name="default_notification_channel_id">default_channel</string>
    <string name="default_notification_channel_name">默认通知通道</string>
    <string name="default_notification_channel_description">应用默认通知通道</string>
    
  2. 在AndroidManifest.xml的<application>标签下添加meta-data:
    <meta-data
        android:name="com.google.firebase.messaging.default_notification_channel_id"
        android:value="@string/default_notification_channel_id" />
    
  3. 在Flutter代码中创建通道(初始化通知时调用):
    import 'package:flutter_local_notifications/flutter_local_notifications.dart';
    
    final FlutterLocalNotificationsPlugin _notificationsPlugin = FlutterLocalNotificationsPlugin();
    
    void _createDefaultNotificationChannel() async {
      const AndroidNotificationChannel channel = AndroidNotificationChannel(
        'default_channel', // 与strings.xml中的ID一致
        '默认通知通道',
        description: '应用默认通知通道',
        importance: Importance.max,
      );
      await _notificationsPlugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()?.createNotificationChannel(channel);
    }
    
    然后在_initNotifications函数中调用_createDefaultNotificationChannel();

三、终止状态(设备锁定/应用未运行)的通知处理

  1. 数据消息:系统会自动启动应用后台进程,触发_firebaseMessagingBackgroundHandler,处理逻辑与后台状态一致。
  2. 通知消息:系统会展示通知,用户点击后启动应用,此时可通过getInitialMessage()获取启动消息并处理:
    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await Firebase.initializeApp(
        options: DefaultFirebaseOptions.currentPlatform,
      );
      // 处理终止状态下点击通知启动应用的场景
      RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage();
      if (initialMessage != null) {
        print("从终止状态启动,收到消息:${initialMessage.messageId}");
        // 这里可添加页面跳转等逻辑
      }
      await initApp();
      runApp(const MyApp());
    }
    
  3. 注意:终止状态下的后台日志无法通过常规方式查看,建议用print输出到Android Studio的Logcat,或写入本地文件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 01:57:39