iOS前台Firebase通知重复,关闭alert则无法接收通知求助
问题分析
iOS前台通知重复的核心原因:
- 当
setForegroundNotificationPresentationOptions(alert: true)时,FCM会自动在前台弹出系统通知 - 同时代码里
onMessage监听又通过flutter_local_notifications手动弹出一次通知,两者叠加导致重复
而设alert: false后收不到通知,是因为当通知包含图片但下载失败时,代码没有兜底展示无图通知,系统又不自动展示,所以完全看不到。
解决方案
1. 关闭FCM前台自动展示alert,避免重复
修改前台展示选项,让系统不再自动弹出alert,完全由手动展示控制:
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions( alert: false, badge: true, sound: true, );
2. 修复iOS端通知展示的兜底逻辑
当图片下载失败时,也要展示无图通知,避免收不到的情况:
修改onMessage中iOS带图通知的逻辑:
else if (Platform.isIOS) { final attachmentPath = await _downloadAndSaveImage(imageUrl, 'notification_image.jpg'); log("Displaying iOS notification (with image: ${attachmentPath != null})"); // 不管图片是否下载成功,都展示通知 NotificationDetails platformDetails; if (attachmentPath != null) { platformDetails = NotificationDetails( iOS: DarwinNotificationDetails( presentAlert: true, presentBadge: true, presentSound: true, attachments: [ DarwinNotificationAttachment( attachmentPath, identifier: 'notification_image', ) ], ), ); } else { // 图片下载失败,展示无图通知 platformDetails = const NotificationDetails( iOS: DarwinNotificationDetails( presentAlert: true, presentBadge: true, presentSound: true, ), ); } await flutterLocalNotificationsPlugin.show( int.parse(message.messageId ?? DateTime.now().millisecondsSinceEpoch.toString()), message.notification?.title ?? '', message.notification?.body ?? '', platformDetails, ); }
3. 优化通知ID,确保唯一性
原代码用message.notification.hashCode作为通知ID,可能出现重复覆盖的情况,建议使用FCM提供的唯一ID或时间戳:
// 替换原通知ID生成逻辑 int.parse(message.messageId ?? DateTime.now().millisecondsSinceEpoch.toString())
关键代码修改后的完整片段
// Set foreground notification presentation options await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions( alert: false, badge: true, sound: true, ); // Listen for foreground messages FirebaseMessaging.onMessage.listen((RemoteMessage message) async { log("onMessage called: ${message.notification?.title ?? ''}"); if (message.notification != null) { String? imageUrl = message.data['image'] ?? message.notification?.android?.imageUrl ?? message.notification?.apple?.imageUrl; if (imageUrl != null) { log("Image URL: $imageUrl"); if (Platform.isAndroid) { // 保留原Android逻辑不变 final bigPicture = await _downloadAndSaveImage(imageUrl, 'bigPicture'); final largeIcon = await _downloadAndSaveImage(imageUrl, 'largeIcon'); if (bigPicture != null) { log("Displaying Android notification with image."); await flutterLocalNotificationsPlugin.show( int.parse(message.messageId ?? DateTime.now().millisecondsSinceEpoch.toString()), message.notification?.title ?? '', message.notification?.body ?? '', NotificationDetails( android: AndroidNotificationDetails( 'channelid', 'channelname', channelDescription: 'channel description', importance: Importance.high, priority: Priority.high, largeIcon: largeIcon != null ? FilePathAndroidBitmap(largeIcon) : null, styleInformation: BigPictureStyleInformation( FilePathAndroidBitmap(bigPicture), largeIcon: largeIcon != null ? FilePathAndroidBitmap(largeIcon) : null, contentTitle: message.notification?.title, summaryText: message.notification?.body, ), ), ), ); } } else if (Platform.isIOS) { final attachmentPath = await _downloadAndSaveImage(imageUrl, 'notification_image.jpg'); log("Displaying iOS notification (with image: ${attachmentPath != null})"); NotificationDetails platformDetails; if (attachmentPath != null) { platformDetails = NotificationDetails( iOS: DarwinNotificationDetails( presentAlert: true, presentBadge: true, presentSound: true, attachments: [ DarwinNotificationAttachment( attachmentPath, identifier: 'notification_image', ) ], ), ); } else { platformDetails = const NotificationDetails( iOS: DarwinNotificationDetails( presentAlert: true, presentBadge: true, presentSound: true, ), ); } await flutterLocalNotificationsPlugin.show( int.parse(message.messageId ?? DateTime.now().millisecondsSinceEpoch.toString()), message.notification?.title ?? '', message.notification?.body ?? '', platformDetails, ); } } else { // 处理无图通知,同时优化通知ID NotificationDetails platformDetails; if (Platform.isAndroid) { platformDetails = const NotificationDetails( android: AndroidNotificationDetails( 'daiwa_food_notification', 'daiwa_food_notification', channelDescription: 'Daiwa Food Channel', icon: '@mipmap/ic_launcher', importance: Importance.high, priority: Priority.high, ), ); } else { platformDetails = const NotificationDetails( iOS: DarwinNotificationDetails( presentAlert: true, presentBadge: true, presentSound: true, ), ); } await flutterLocalNotificationsPlugin.show( int.parse(message.messageId ?? DateTime.now().millisecondsSinceEpoch.toString()), message.notification?.title ?? '', message.notification?.body ?? '', platformDetails, ); } } });
内容的提问来源于stack exchange,提问作者adeli
相关产品推荐
相关产品推荐

