Flutter Android应用启动图标通知角标实现问题求助
Android应用启动图标角标未显示问题排查
我希望在Android应用的启动图标旁显示用户未读消息数量的通知角标,但尝试相关代码后未能成功实现。以下是我编写的main.dart代码,请求帮忙排查错误:
import 'package:flutter_app_badger/flutter_app_badger.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:get/get.dart'; import 'package:liquitech/services/notificationService.dart'; Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await GetStorage.init(); await MpesaFlutterPlugin.setConsumerKey(MyConfig.mpesaConsumerKey); await MpesaFlutterPlugin.setConsumerSecret(MyConfig.mpesaConsumerSecret); await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ).then((value) => Get.put(AuthRepository())); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]) .then((_) { FirebaseMessaging.onBackgroundMessage(backgroundHandler); runApp(const MyApp()); }); } class _MyAppState extends State<MyApp> { final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance; _firebaseMessaging.requestPermission(); _firebaseMessaging.setForegroundNotificationPresentationOptions( alert: true, badge: true, sound: true); _firebaseMessaging.getToken().then((token) { print("token:$token"); }); @override initState() { NotificationApi.init(); listenNotifications(); _firebaseMessaging.getInitialMessage().then((message) async { final routeName = message?.data["route"]; if (routeName != null) { Get.toNamed(routeName); } }); //foreground FirebaseMessaging.onMessage.listen((message) { int badgeCount = int.tryParse(message.data['badge'] ?? '0') ?? 0; if (badgeCount > 0) { SystemChrome.setApplicationSwitcherDescription( ApplicationSwitcherDescription( label: myAppName, primaryColor: Colors.blue.value), ); SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle(statusBarColor: Colors.blue), ); _setNotificationBadge(badgeCount); } NotificationApi.showNotification( title: message.notification!.title, body: message.notification!.body, payload: "sarah.abs"); }); //background and not terminated and user taps on the notification FirebaseMessaging.onMessageOpenedApp.listen((message) { final routeName = message.data["route"]; if (routeName != null) { Get.toNamed(routeName); } }); } void listenNotifications() { NotificationApi.onNotifications.stream.listen((onClickedNotification)); } void onClickedNotification(String? payload) { Navigator.of(context).push(MaterialPageRoute( builder: (BuildContext context) => const OpenedNotificationPage())); } } @override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (context) => GoogleSignInProvider(), child: GetMaterialApp( title: myAppName, debugShowCheckedModeBanner: false, theme: isDarkMode ? ThemeData.dark() : ThemeData.light(), defaultTransition: Transition.leftToRightWithFade, transitionDuration: const Duration(milliseconds: 800), darkTheme: MyThemes.darkTheme, home: SplashScreen(myAppName: myAppName), getPages: [ GetPage( name: "/openedNotification", page: () => const OpenedNotificationPage()) ], ), ); } _setNotificationBadge(int badgeCount) async { if (badgeCount > 0) { await FlutterAppBadger.updateBadgeCount(badgeCount); } else { await FlutterAppBadger.removeBadge(); } } }
代码错误及修复方案
1. 语法结构错误
- 问题:
_firebaseMessaging.requestPermission()等初始化代码直接写在类的成员变量区域,属于语法错误;_setNotificationBadge方法前有多余的闭合花括号,导致类结构混乱。 - 修复:将权限请求代码移至
initState内部,调整类的代码结构,确保所有方法都在类的正确范围内:
@override void initState() { super.initState(); // 移到此处执行初始化 _firebaseMessaging.requestPermission(); _firebaseMessaging.setForegroundNotificationPresentationOptions( alert: true, badge: true, sound: true); _firebaseMessaging.getToken().then((token) { print("token:$token"); }); NotificationApi.init(); listenNotifications(); // ...其他原有代码 }
2. Android角标兼容性问题
- 问题:
flutter_app_badger在Android上依赖厂商ROM支持,国产机型(小米、华为、OPPO等)需要额外配置:- 小米:需在
AndroidManifest.xml添加<meta-data android:name="com.xiaomi.mipush.WIFI" android:value="1"/>,并配置小米推送服务 - 华为:需集成华为推送服务,在后台开启角标权限
- OPPO/VIVO:需申请厂商推送权限,部分机型要求应用处于后台才显示角标
- 小米:需在
- 修复:调用角标更新前先检查设备支持性:
void _setNotificationBadge(int badgeCount) async { bool isSupported = await FlutterAppBadger.isAppBadgeSupported(); if (!isSupported) return; if (badgeCount > 0) { await FlutterAppBadger.updateBadgeCount(badgeCount); } else { await FlutterAppBadger.removeBadge(); } }
3. 消息监听逻辑漏洞
- 问题:仅在前台收到消息时更新角标,未处理应用后台/终止状态的角标更新:
- 后台消息无法直接在
backgroundHandler中更新角标,需通过本地存储记录未读数量,在应用启动时读取更新 - 应用启动时未主动初始化角标状态
- 后台消息无法直接在
- 修复:在
initState中主动读取本地存储的未读数量,初始化角标;点击通知时减少未读数量并更新角标:
@override void initState() { super.initState(); // ...其他代码 // 启动时初始化角标 _initBadgeCount(); } void _initBadgeCount() async { // 从本地存储读取未读数量,示例用GetStorage int unreadCount = GetStorage().read('unread_count') ?? 0; await _setNotificationBadge(unreadCount); } // 点击通知时更新未读数量 void onClickedNotification(String? payload) { int currentCount = GetStorage().read('unread_count') ?? 0; if (currentCount > 0) { currentCount--; GetStorage().write('unread_count', currentCount); _setNotificationBadge(currentCount); } Navigator.of(context).push(MaterialPageRoute( builder: (BuildContext context) => const OpenedNotificationPage())); }
内容的提问来源于stack exchange,提问作者Kevy Kibbz
相关产品推荐
相关产品推荐

