Flutter中FCM通知接收问题:后台/终止态处理及通知通道疑问
Flutter FCM通知问题排查与解决方案
问题场景
我正在梳理Flutter应用接收FCM通知的机制,按照官方文档实现了前台和后台监听逻辑,但遇到以下问题:
- 应用前台状态时,Firebase Composer发送的通知能正常触发日志记录;但后台状态时,通知仅显示在状态栏,
_firebaseMessagingBackgroundHandler函数未被调用,无对应日志输出。 - 注释掉
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);后,日志提示需要注册后台处理器;但注册后,日志仅显示收到消息,处理器仍未执行。 - 日志中提示“Missing Default Notification Channel metadata in AndroidManifest”,不确定是否需要手动配置。
- 不清楚设备锁定(应用终止状态)时,如何处理通知。
我的实现代码如下:
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)及以上强制要求设置通知通道,否则通知无法正常显示,需手动配置:
- 在
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> - 在
AndroidManifest.xml的<application>标签下添加meta-data:<meta-data android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="@string/default_notification_channel_id" /> - 在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();
三、终止状态(设备锁定/应用未运行)的通知处理
- 数据消息:系统会自动启动应用后台进程,触发
_firebaseMessagingBackgroundHandler,处理逻辑与后台状态一致。 - 通知消息:系统会展示通知,用户点击后启动应用,此时可通过
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()); } - 注意:终止状态下的后台日志无法通过常规方式查看,建议用
print输出到Android Studio的Logcat,或写入本地文件。
内容的提问来源于stack exchange,提问作者Ralfeus
相关产品推荐
相关产品推荐

