Flutter FCM自定义通知音效与后台/终止状态跳转问题求助
Flutter FCM 自定义音效+全状态跳转解决方案
核心思路
要同时满足自定义音效、无重复通知、全状态跳转,核心是禁止FCM自动创建通知,完全通过flutter_local_notifications手动处理所有通知逻辑,同时补全冷启动和后台点击的消息处理流程。
一、调整FCM推送Payload
移除顶层的notification对象,只保留data字段+平台专属音效配置,避免FCM自动弹通知导致的重复和默认音效问题。
正确Payload格式:
{ "message": { "token": "DEVICE_FCM_TOKEN", "data": { "title": "Visitor has been admitted!", "body": "Dhaval developer (Visitor) has been admitted.", "id": "1215454", "notification_type": "visitor_visited", "other_data_key": "other_data_value" }, "android": { "notification": { "sound": "visitor_notification_sound" } }, "apns":{ "payload":{ "aps":{ "sound":"visitor_notification_sound.mp3", "badge": 1 } } } } }
说明:
data字段必须包含title、body,用于手动创建通知内容- Android的
sound值对应res/raw目录下的音效文件名(不带后缀)- iOS的
sound值对应项目中添加的音效文件名(带后缀)
二、修改Flutter代码
1. 处理应用冷启动(终止状态)的通知点击
在main.dart中添加冷启动消息获取逻辑,确保应用从终止状态被通知唤醒时能处理跳转:
Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); // 处理冷启动时的通知消息 RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage(); if (initialMessage != null) { await FirebaseCloudMessagingService().handleNotificationTappedFormNotificationTray(initialMessage.data); } await FirebaseCloudMessagingService().initFCM(); runApp(const MyApp()); }
2. 添加全局导航键用于跨状态跳转
在fcm_controller.dart顶部定义全局导航键,解决后台/冷启动时无法获取页面上下文的问题:
// 全局导航键,用于在任意状态下跳转页面 final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
3. 完善后台通知点击逻辑
修改notificationTapBackground函数,添加实际跳转逻辑:
@pragma('vm:entry-point') Future<void> notificationTapBackground(NotificationResponse notificationResponse) async { debugPrint('background notification tap'); Map<String, dynamic> data = jsonDecode(notificationResponse.payload ?? "{}"); // 通过全局导航键跳转至目标页面 navigatorKey.currentState?.pushNamed('/visitor-detail', arguments: data); }
4. 更新MyApp使用全局导航键
class MyApp extends StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { @override Widget build(BuildContext context) { return MaterialApp( navigatorKey: navigatorKey, // 绑定全局导航键 routes: { '/': (context) => const Scaffold(body: Center(child: Text('hello'))), '/visitor-detail': (context) => const VisitorDetailPage(), // 定义目标页面 }, ); } }
5. 优化通知创建逻辑
确保showNotification完全从data字段读取内容,并正确创建通知渠道:
static Future<void> showNotification(RemoteMessage message) async { String title = message.data['title'] ?? '默认通知'; String body = message.data['body'] ?? '无内容'; String soundName = 'notification_sound_android'; String iosSoundName = 'notification_sound_android.mp3'; if (message.data['notification_type'] == 'visitor_visited') { soundName = 'visitor_notification_sound'; iosSoundName = 'visitor_notification_sound.mp3'; } AndroidNotificationChannel channel = AndroidNotificationChannel( soundName, '访客通知', importance: Importance.max, playSound: true, sound: RawResourceAndroidNotificationSound(soundName), ); // Android 8.0+必须先创建通知渠道 await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()?.createNotificationChannel(channel); AndroidNotificationDetails androidDetails = AndroidNotificationDetails( channel.id, channel.name, sound: RawResourceAndroidNotificationSound(soundName), ); NotificationDetails notificationDetails = NotificationDetails( android: androidDetails, iOS: DarwinNotificationDetails(sound: iosSoundName), ); flutterLocalNotificationsPlugin.show( math.Random().nextInt(100000), title, body, notificationDetails, payload: jsonEncode(message.data), ); }
三、平台配置注意事项
Android
- 将自定义音效文件(如
visitor_notification_sound.mp3)放在android/app/src/main/res/raw目录下(无raw目录则新建) - 音效文件名必须全小写,无空格或特殊字符
- 无需在
AndroidManifest.xml额外配置音效,代码中已通过通知渠道处理
iOS
- 将音效文件添加到Xcode项目,勾选"Copy items if needed"和对应target
- 在
Info.plist中添加后台推送权限:
<key>UIBackgroundModes</key> <array> <string>remote-notification</string> </array>
- 确保音效格式为iOS支持的类型(如mp3、wav),时长建议不超过30秒
四、验证步骤
- 发送调整后的Payload到测试设备
- 测试三种状态下的表现:
- 应用前台:收到自定义音效通知,点击跳转正常
- 应用后台:收到自定义音效通知,点击跳转正常
- 应用终止:收到自定义音效通知,点击唤醒应用并跳转正常
- 确认无重复通知,仅播放自定义音效
内容的提问来源于stack exchange,提问作者codnix dev
相关产品推荐
相关产品推荐

