You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 07:52:35