Flutter后台服务通知常驻通知栏,如何隐藏该通知?
问题:隐藏后台服务通知同时保持Firebase推送接收
我在Flutter应用中使用flutter_local_notifications包实现了应用终止状态下接收Firebase推送通知,但后台服务弹出的通知给用户带来了不佳体验。请问能否在保持后台服务正常运行的前提下,隐藏这个通知?
现有代码
import 'dart:developer'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_background_service/flutter_background_service.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:zooper_ai/app/componets/messenger.dart'; import 'package:zooper_ai/app/core/color.dart'; import 'package:zooper_ai/app/helper/sqflite_db/database_functions.dart'; import 'package:zooper_ai/app/modules/drawer_menu/adhoc_bookings/view/adhoc_booking.dart'; import 'package:zooper_ai/app/modules/bottomsheet/botttom_sheet_screen/view/bottom_sheet.dart'; import 'package:zooper_ai/app/modules/splash/view/splash_screen.dart'; import 'package:zooper_ai/app/providers/providers.dart'; import 'package:zooper_ai/app/routes/routes.dart'; import 'package:zooper_ai/app/services/notification/notification_services.dart'; @pragma('vm:entry-point') Future<void> firebaseMessagingBackgroundHandler(message) async { await Firebase.initializeApp(); await FirebaseMessaging.instance.getToken(); NotificationServices() .sendNotification("TestApp", "${message.data['notificationTitle']}"); } void initialiseNotification() async { InitializationSettings initializationSettings = InitializationSettings( android: NotificationServices().androidInitializationSettings, ); await NotificationServices().flutterLocalNotificationsPlugin.initialize( initializationSettings, onSelectNotification: notificationResponse // onDidReceiveNotificationResponse: notificationResponse, // onDidReceiveBackgroundNotificationResponse: notificationResponse, ); } Future<dynamic> notificationResponse(args) async { if (NotificationServices().notifyredirect != null) { log("if some notifications come"); log(NotificationServices().notifyredirect.toString()); if (NotificationServices().notifyredirect == "notificationCustomerConfigUpdate") { Routes.push( screen: CurvedBottomNavBar( page: 1, )); } else if (NotificationServices().notifyredirect == "notificationOnGeofenceTrigger") { NotificationServices().findNotifiedRide(); } //log("| asss ride id ass $NotificationServices().notifyredirect"); } } Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await ScreenUtil.ensureScreenSize(); FlutterBackgroundService(); //if (await checkInternetConnectivity()) { log("here from here"); await Firebase.initializeApp(); await FirebaseMessaging.instance.getToken(); FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler); FirebaseMessaging.instance.getInitialMessage().then((message) { if (message != null) { // RemoteNotification? notification = message!.notification; AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails(NotificationServices().channel.id, NotificationServices().channel.name, importance: Importance.high, priority: Priority.high, playSound: true); NotificationDetails notificationDetails = NotificationDetails(android: androidNotificationDetails); //AndroidNotification? android = message.notification?.android; var channelId = 0; print( " notification details : ${NotificationServices().flutterLocalNotificationsPlugin}"); // if (message.data['notificationType'] == 'notificationOnGeofenceTrigger') { // channelId = 2; NotificationServices().notifyredirect = message.data['notificationType']; NotificationServices().rideIdNotification = message.data['rideId']; NotificationServices().flutterLocalNotificationsPlugin.show(channelId, "Zooper", "${message.data['notificationTitle']}", notificationDetails, payload: 'mesaf'); FirebaseMessaging.instance.setForegroundNotificationPresentationOptions( alert: true, badge: true, sound: true); } else { log("data is null"); } }); // final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = // FlutterLocalNotificationsPlugin(); // flutterLocalNotificationsPlugin.cancel(notificationId); FirebaseMessaging.onMessage.listen((RemoteMessage message) async { RemoteNotification? notification = message.notification; AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails(NotificationServices().channel.id, NotificationServices().channel.name, importance: Importance.high, priority: Priority.high, playSound: true); NotificationDetails notificationDetails = NotificationDetails(android: androidNotificationDetails); //AndroidNotification? android = message.notification?.android; var channelId = 0; print( " notification details : ${NotificationServices().flutterLocalNotificationsPlugin}"); // if (message.data['notificationType'] == 'notificationOnGeofenceTrigger') { // channelId = 2; NotificationServices().notifyredirect = message.data['notificationType']; NotificationServices().rideIdNotification = message.data['rideId']; NotificationServices().flutterLocalNotificationsPlugin.show(channelId, "Zooper", "${message.data['notificationTitle']}", notificationDetails, payload: 'mesaf'); FirebaseMessaging.instance.setForegroundNotificationPresentationOptions( alert: true, badge: true, sound: true); }); FirebaseMessaging.instance.getToken(); FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { if (message != null) { NotificationServices() .sendNotification("Zooper", "${message.data['notificationTitle']}"); } else { log("backround from"); } // print("A new onMessageOpenedApp event was published"); // print("Messagenotfi ${message.data['notificationTitle']}"); }); initialiseNotification(); SystemChrome.setPreferredOrientations( [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); await initiolizeDatabase(); await getcityList(); await gettimeSloteSqflite(); await getRosterSqflite(); await getCompanyInfoSqflit(); runApp(Provders.provders()); } class MyApp extends StatelessWidget { const MyApp({super.key}); // initState() { // super.initState(); // } void showNotification() { NotificationServices().flutterLocalNotificationsPlugin.show( 0, "Testing", "Hiw you doing", NotificationDetails( android: AndroidNotificationDetails( NotificationServices().channel.id, NotificationServices().channel.name, channelDescription: NotificationServices().channel.description, importance: Importance.high, color: Colors.blue, playSound: true, icon: 'assets/ui/images/Empty.png'))); } @override Widget build(BuildContext context) { return ScreenUtilInit( splitScreenMode: false, minTextAdapt: true, builder: (BuildContext context, Widget? child) { return MaterialApp( initialRoute: '/', builder: (BuildContext context, Widget? child) { return MediaQuery( data: MediaQuery.of(context).copyWith( textScaleFactor: 0.85, ), child: child!, ); }, routes: { 'bottomSheet': (context) => CurvedBottomNavBar(), '/adhoc': (context) => const MyAdhoc(), }, navigatorKey: Routes.navigatorKey, debugShowCheckedModeBanner: false, title: 'Test', scaffoldMessengerKey:Messenger.rootScaffoldMessengerKey, //darkTheme: darkThemeData(context), theme: lightThemeData(context), home: const SplashScreen()); }); } }
解决方案
1. 避免后台消息重复弹出通知
你的firebaseMessagingBackgroundHandler里手动调用了sendNotification,但Firebase在应用终止状态下收到通知消息(带notification字段)时,系统会自动弹出通知,手动调用会导致重复。只需要在后台处理数据消息(无notification字段)的逻辑,不要显示通知:
@pragma('vm:entry-point') Future<void> firebaseMessagingBackgroundHandler(message) async { await Firebase.initializeApp(); await FirebaseMessaging.instance.getToken(); // 仅处理数据消息,通知消息由系统自动处理 if (message.notification == null) { log("后台处理数据消息: ${message.data}"); // 这里执行你的后台逻辑,比如更新本地数据库、触发其他操作 } }
2. 移除启动时的重复通知
getInitialMessage中你又调用了flutterLocalNotificationsPlugin.show,这会导致应用从终止状态启动时重复弹出系统已经显示过的通知,直接处理跳转逻辑即可:
FirebaseMessaging.instance.getInitialMessage().then((message) { if (message != null) { NotificationServices().notifyredirect = message.data['notificationType']; NotificationServices().rideIdNotification = message.data['rideId']; // 直接处理跳转,不要再次显示通知 if (NotificationServices().notifyredirect == "notificationCustomerConfigUpdate") { Routes.push(screen: CurvedBottomNavBar(page: 1)); } else if (NotificationServices().notifyredirect == "notificationOnGeofenceTrigger") { NotificationServices().findNotifiedRide(); } } else { log("data is null"); } });
3. 配置静默后台服务通知
如果你用了flutter_background_service,它默认会显示后台服务通知。可以配置一个完全静默的通知渠道,让通知不在状态栏显示:
Future<void> initBackgroundService() async { final service = FlutterBackgroundService(); await service.configure( androidConfiguration: AndroidConfiguration( onStart: onStart, // 你的后台任务逻辑 autoStart: true, isForegroundMode: true, // 配置静默通知 foregroundServiceNotification: AndroidNotificationDetails( 'silent_service', '后台服务', channelDescription: '应用后台运行中', importance: Importance.low, priority: Priority.low, playSound: false, enableVibration: false, showBadge: false, visibility: NotificationVisibility.secret, // 完全隐藏通知 ), ), iosConfiguration: IosConfiguration( autoStart: true, onForeground: onStart, onBackground: (service) async { service.setAutoStartOnBoot(true); return true; }, ), ); }
然后在main中替换原来的FlutterBackgroundService();,调用这个初始化函数。
4. Android版本特殊处理
Android 12+要求前台服务必须显示通知,无法完全隐藏,但可以通过以下方式优化:
- 创建单独的静默通知渠道,引导用户在系统设置中关闭该渠道的通知
- 使用
NotificationVisibility.secret让通知不在状态栏显示,仅在下拉通知中心可见(如果必须保留前台服务)
内容的提问来源于stack exchange,提问作者MJ13
相关产品推荐
相关产品推荐

