Flutter安卓应用FCM通知数量统计与徽章实现问题求助
我来帮你搞定这个FCM通知数量统计和首页徽章的问题!之前踩过类似的坑,给你一套亲测可行的方案,一步步来:
Flutter FCM通知数量统计与首页徽章实现方案
一、核心思路:本地持久化存计数
FCM本身不会帮你统计通知数量,所以得自己在本地维护这个数字——每次收到通知就+1,用户点击通知/进入首页就清零。推荐用shared_preferences做本地存储,简单稳定。
第一步:添加依赖
先在pubspec.yaml里加好需要的包:
dependencies: flutter: sdk: flutter shared_preferences: ^2.2.2 firebase_messaging: ^14.6.5 flutter_app_badger: ^1.5.0 # 用于设置安卓应用图标徽章 badges: ^3.1.2 # 用于首页AppBar的徽章显示
第二步:封装计数管理类
创建一个NotificationCounter.dart,把计数的增、清、查逻辑封装起来:
import 'package:shared_preferences/shared_preferences.dart'; class NotificationCounter { static const String _countKey = 'notification_count'; static final ValueNotifier<int> countNotifier = ValueNotifier(0); // 用于实时更新UI // 获取当前通知数,同时更新监听者 static Future<int> getCount() async { final prefs = await SharedPreferences.getInstance(); int count = prefs.getInt(_countKey) ?? 0; countNotifier.value = count; return count; } // 通知数+1 static Future<void> increment() async { final prefs = await SharedPreferences.getInstance(); int currentCount = await getCount(); int newCount = currentCount + 1; await prefs.setInt(_countKey, newCount); countNotifier.value = newCount; } // 重置计数为0 static Future<void> reset() async { final prefs = await SharedPreferences.getInstance(); await prefs.setInt(_countKey, 0); countNotifier.value = 0; } }
二、绑定FCM消息回调,更新计数
FCM的消息分三种场景:前台、后台、应用被杀死,要分别处理:
1. 前台消息处理
应用在前台时,onMessage会触发,直接在这里加计数:
FirebaseMessaging.onMessage.listen((RemoteMessage message) { // 前台收到通知,计数+1 NotificationCounter.increment(); // 同步更新应用图标徽章 _updateAppBadge(); });
2. 后台/杀死状态消息处理
- 先写一个顶级的后台消息处理器(必须是顶级函数,不能放在类里):
import 'package:firebase_core/firebase_core.dart'; import 'package:your_app_name/NotificationCounter.dart'; Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async { await Firebase.initializeApp(); // 后台收到通知,计数+1 await NotificationCounter.increment(); }
- 在
main函数里初始化FCM并绑定回调:
void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); // 注册后台消息处理器 FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler); // 处理应用被杀死后,用户点击通知启动的场景 RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage(); if (initialMessage != null) { // 点击通知进入应用,重置计数 await NotificationCounter.reset(); await _updateAppBadge(); } runApp(const MyApp()); }
- 处理应用在后台时,用户点击通知进入的场景:
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { // 点击通知进入应用,重置计数 NotificationCounter.reset(); _updateAppBadge(); });
三、实现首页徽章与应用图标徽章
1. 封装应用图标徽章更新函数
import 'package:flutter_app_badger/flutter_app_badger.dart'; Future<void> _updateAppBadge() async { int count = await NotificationCounter.getCount(); if (count > 0) { await FlutterAppBadger.updateBadgeCount(count); } else { await FlutterAppBadger.removeBadge(); } }
2. 首页AppBar显示徽章
用ValueListenableBuilder实现实时更新,不用手动setState:
import 'package:flutter/material.dart'; import 'package:badges/badges.dart'; import 'package:your_app_name/NotificationCounter.dart'; class HomePage extends StatefulWidget { const HomePage({super.key}); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { @override void initState() { super.initState(); // 页面初始化时加载计数 NotificationCounter.getCount().then((_) => _updateAppBadge()); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('首页'), actions: [ ValueListenableBuilder<int>( valueListenable: NotificationCounter.countNotifier, builder: (context, count, child) { return Badge( badgeContent: Text(count.toString()), showBadge: count > 0, child: child!, ); }, child: IconButton( icon: const Icon(Icons.notifications), onPressed: () { // 用户点击通知图标,重置计数 NotificationCounter.reset().then((_) => _updateAppBadge()); }, ), ), ], ), body: const Center(child: Text('首页内容')), ); } }
四、常见报错排查
如果之前改代码报错,大概率是这几个原因:
- 后台消息处理器不是顶级函数:
firebaseMessagingBackgroundHandler必须放在文件最外层,不能在类或函数内部。 - 安卓权限缺失:安卓13+需要POST_NOTIFICATIONS权限,在
AndroidManifest.xml里加:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
- shared_preferences初始化问题:一定要在调用
SharedPreferences.getInstance()前执行WidgetsFlutterBinding.ensureInitialized()。 - 厂商兼容问题:小米、华为等品牌的徽章显示需要用户在系统设置里开启“应用图标标记”权限。
内容的提问来源于stack exchange,提问作者user13125672
相关产品推荐
相关产品推荐

