iOS前台Flutter FirebaseMessaging通知重复问题求助
iOS前台Firebase通知重复显示的问题解决
问题概述
开发Flutter + FirebaseMessaging通知测试应用时,Android端完全正常;iOS后台接收通知正常,但应用前台时通知会重复显示两次:带图片的通知一条显示图片、一条无图。无论通过Firebase控制台还是自研后端调用接口,问题均复现。
核心原因
- 双重通知触发:iOS平台下,同时开启了
setForegroundNotificationPresentationOptions(alert: true)(系统自动展示前台通知)和flutter_local_notifications手动展示通知,导致重复。 - 图片展示差异:系统自动展示的通知会经过
NotificationService扩展处理加载图片,而手动调用的通知未处理图片逻辑,因此出现一条有图一条无图的情况。
修复步骤
1. 关闭iOS系统自动展示前台通知
在main.dart中,针对iOS平台禁用系统自动展示前台通知,保留Android平台的设置:
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions( alert: Platform.isAndroid, // iOS关闭系统自动弹通知 badge: true, sound: true, );
2. 优化本地通知插件初始化逻辑
当前NotificationManager每次调用都重新初始化插件,既低效也可能引发问题,改为全局初始化一次:
- 修改
main.dart,将插件初始化移至main函数:
import 'dart:developer'; import 'dart:io'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:googlenotifpoc/notification_manager.dart'; import 'firebase_options.dart'; // 全局声明本地通知插件实例 final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp( name: "...", options: DefaultFirebaseOptions.currentPlatform, ); await FirebaseMessaging.instance.setAutoInitEnabled(true); // 初始化本地通知插件(全局只做一次) const androidInit = AndroidInitializationSettings("ic_white"); const iosInit = DarwinInitializationSettings(); const initialSettings = InitializationSettings(android: androidInit, iOS: iosInit); await flutterLocalNotificationsPlugin.initialize(initialSettings); const AndroidNotificationChannel channel = AndroidNotificationChannel( 'high_importance_channel', 'High Importance Notifications', description: 'This channel is used for important notifications.', importance: Importance.max, ); await flutterLocalNotificationsPlugin .resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>() ?.createNotificationChannel(channel); const AndroidNotificationDetails androidDetails = AndroidNotificationDetails( 'high_importance_channel', 'High Importance Notifications', channelDescription: 'This channel is used for important notifications.', importance: Importance.max, priority: Priority.high, ticker: 'ticker', icon: "ic_white", playSound: true, ); await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions( alert: Platform.isAndroid, // iOS关闭系统自动弹通知 badge: true, sound: true, ); FirebaseMessaging.onMessage.listen((event) => NotificationManager.showNotification(event, androidDetails, flutterLocalNotificationsPlugin)); runApp(const MyApp()); } // 以下MyApp、MyHomePage代码保持不变...
- 修改
NotificationManager类,接收全局插件实例,添加图片处理逻辑:
import 'dart:convert'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:http/http.dart' as http; class NotificationManager { static Future<void> showNotification( RemoteMessage payload, AndroidNotificationDetails androidDetails, FlutterLocalNotificationsPlugin plugin, ) async { NotificationDetails platformChannelSpecifics; const iOSDetails = DarwinNotificationDetails(); // 处理带图片的通知 if (payload.notification?.android?.imageUrl != null || payload.notification?.apple?.imageUrl != null) { final String? imageUrl = payload.notification?.android?.imageUrl ?? payload.notification?.apple?.imageUrl; if (imageUrl != null) { try { final http.Response response = await http.get(Uri.parse(imageUrl)); final base64Image = base64Encode(response.bodyBytes); final bigPictureStyle = BigPictureStyleInformation( ByteArrayAndroidBitmap.fromBase64String(base64Image), largeIcon: ByteArrayAndroidBitmap.fromBase64String(base64Image), ); final androidWithImage = androidDetails.copyWith(styleInformation: bigPictureStyle); platformChannelSpecifics = NotificationDetails(android: androidWithImage, iOS: iOSDetails); } catch (e) { // 图片加载失败时使用默认配置 platformChannelSpecifics = NotificationDetails(android: androidDetails, iOS: iOSDetails); } } else { platformChannelSpecifics = NotificationDetails(android: androidDetails, iOS: iOSDetails); } } else { platformChannelSpecifics = NotificationDetails(android: androidDetails, iOS: iOSDetails); } // 用messageId的哈希值作为通知ID,避免重复覆盖 await plugin.show( payload.messageId?.hashCode ?? DateTime.now().millisecondsSinceEpoch, payload.notification!.title, payload.notification!.body, platformChannelSpecifics, ); } }
注意:需要在pubspec.yaml中添加http依赖:
dependencies: # 其他依赖... http: ^1.1.0
3. 保留NotificationService扩展配置
当前NotificationService.m的配置是正确的,它负责处理iOS后台通知的图片加载,无需修改。
验证效果
修改后,iOS前台只会收到一次由本地通知插件展示的通知,带图片的通知能正确显示图片;后台通知仍由系统正常处理,无重复问题。
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

