基于Firebase Messaging实现Flutter应用角标更新问题求助
将flutter_app_badger集成到Firebase Messaging通知处理的方案
问题背景
我正在使用flutter_app_badger和Firebase Messaging搭建通知系统,期望收到新通知时更新应用角标数字,开发环境为FlutterFlow。目前已完成两项工作:
- 编写了应用前台运行时更新角标的独立函数
- 配置了由应用内动作触发的通知系统
但无法将两者结合,现提供push_notification_handler代码,寻求集成FlutterAppBadger.updateBadgeCount()的方案。
现有代码
import 'dart:async'; import 'dart:convert'; import 'serialization_util.dart'; import '../backend.dart'; import '../../flutter_flow/flutter_flow_theme.dart'; import '../../flutter_flow/flutter_flow_util.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import '../../index.dart'; import '../../main.dart'; final _handledMessageIds = <String?>{}; class PushNotificationsHandler extends StatefulWidget { const PushNotificationsHandler({Key? key, required this.child}) : super(key: key); final Widget child; @override _PushNotificationsHandlerState createState() => _PushNotificationsHandlerState(); } class _PushNotificationsHandlerState extends State<PushNotificationsHandler> { bool _loading = false; Future handleOpenedPushNotification() async { if (isWeb) { return; } final notification = await FirebaseMessaging.instance.getInitialMessage(); if (notification != null) { await _handlePushNotification(notification); } FirebaseMessaging.onMessageOpenedApp.listen(_handlePushNotification); } Future _handlePushNotification(RemoteMessage message) async { if (_handledMessageIds.contains(message.messageId)) { return; } _handledMessageIds.add(message.messageId); if (mounted) { setState(() => _loading = true); } try { final initialPageName = message.data['initialPageName'] as String; final initialParameterData = getInitialParameterData(message.data); final pageBuilder = pageBuilderMap[initialPageName]; if (pageBuilder != null) { final page = await pageBuilder(initialParameterData); await Navigator.push( context, MaterialPageRoute(builder: (context) => page), ); } } catch (e) { print('Error: $e'); } finally { if (mounted) { setState(() => _loading = false); } } } @override void initState() { super.initState(); handleOpenedPushNotification(); } @override Widget build(BuildContext context) => _loading ? Container( color: FlutterFlowTheme.of(context).primaryBtnText, child: Image.asset( 'assets/images/Screen_Shot_2022-11-22_at_12.59.57.png', fit: BoxFit.contain, ), ) : widget.child; } final pageBuilderMap = <String, Future<Widget> Function(Map<String, dynamic>)>{ 'SignInSignUpPage': (data) async => SignInSignUpPageWidget(), 'ForgotPasswordPage': (data) async => ForgotPasswordPageWidget(), 'ContactsListPage': (data) async => ContactsListPageWidget( tabToOpen: getParameter(data, 'tabToOpen'), ), 'SyncProcessPage': (data) async => SyncProcessPageWidget(), 'SyncConfirmationPage': (data) async => SyncConfirmationPageWidget(), 'ContactDetailsPage': (data) async => ContactDetailsPageWidget( idReference: getParameter(data, 'idReference'), comment: getParameter(data, 'comment'), ), 'ContactDeletePage': (data) async => ContactDeletePageWidget( idReference: getParameter(data, 'idReference'), comment: getParameter(data, 'comment'), ), 'ContactInvitationPage': (data) async => ContactInvitationPageWidget( idReference: getParameter(data, 'idReference'), ), 'AddConfirmationAfterInvitePage': (data) async => AddConfirmationAfterInvitePageWidget( uID: getParameter(data, 'uID'), phraseState: getParameter(data, 'phraseState'), ), 'AddContactsOptionPage': (data) async => AddContactsOptionPageWidget(), 'SearchNewContactsPage': (data) async => SearchNewContactsPageWidget(), 'NewContactInvitationConfirmationPage': (data) async => NewContactInvitationConfirmationPageWidget(), 'NewContactScanPage': (data) async => NewContactScanPageWidget(), 'AddConfirmationAfterScanPageNew': (data) async => AddConfirmationAfterScanPageNewWidget( uID: getParameter(data, 'uID'), phraseState: getParameter(data, 'phraseState'), ), 'AddConfirmationAfterScanPageOld': (data) async => AddConfirmationAfterScanPageOldWidget( uID: getParameter(data, 'uID'), phraseState: getParameter(data, 'phraseState'), ), 'ShareProfileOptionsPage': (data) async => ShareProfileOptionsPageWidget(), 'InAppQRcodeSharePage': (data) async => InAppQRcodeSharePageWidget(), 'WebQRcodeSharePage': (data) async => WebQRcodeSharePageWidget(), 'ProfileEditPage': (data) async => ProfileEditPageWidget(), 'GameSettingsPage': (data) async => GameSettingsPageWidget(), 'GamePage': (data) async => GamePageWidget(), 'TutorialPage': (data) async => TutorialPageWidget(), 'AboutPage': (data) async => AboutPageWidget(), 'FAQPage': (data) async => FAQPageWidget(), 'PrivacyPolicyPage': (data) async => PrivacyPolicyPageWidget(), }; bool hasMatchingParameters(Map<String, dynamic> data, Set<String> params) => params.any((param) => getParameter(data, param) != null); Map<String, dynamic> getInitialParameterData(Map<String, dynamic> data) { try { final parameterDataStr = data['parameterData']; if (parameterDataStr == null || parameterDataStr is! String || parameterDataStr.isEmpty) { return {}; } return jsonDecode(parameterDataStr) as Map<String, dynamic>; } catch (e) { print('Error parsing parameter data: $e'); return {}; } }
集成步骤
1. 导入flutter_app_badger包
在代码顶部添加导入语句:
import 'package:flutter_app_badger/flutter_app_badger.dart';
2. 添加角标更新方法
在_PushNotificationsHandlerState类中添加角标更新的核心方法,支持获取当前角标数并累加:
Future<void> _updateBadgeCount() async { int currentCount = 0; // 尝试获取当前角标数,兼容部分不支持获取的设备 try { currentCount = await FlutterAppBadger.getBadgeCount() ?? 0; } catch (e) { print('获取当前角标数失败: $e'); } // 每次收到通知角标数+1 await FlutterAppBadger.updateBadgeCount(currentCount + 1); }
3. 监听前台通知并更新角标
修改initState方法,添加前台通知的监听逻辑,确保应用在前台时收到通知立即更新角标:
@override void initState() { super.initState(); handleOpenedPushNotification(); // 监听前台收到的推送通知 FirebaseMessaging.onMessage.listen((RemoteMessage message) { _updateBadgeCount(); }); }
4. 处理通知打开后的角标更新
当用户点击通知进入应用时,可选择将角标数减1或清空,修改_handlePushNotification的finally块:
finally { if (mounted) { setState(() => _loading = false); } // 用户打开通知后更新角标 int currentCount = await FlutterAppBadger.getBadgeCount() ?? 0; if (currentCount > 0) { await FlutterAppBadger.updateBadgeCount(currentCount - 1); } else { await FlutterAppBadger.removeBadge(); } }
5. 处理应用未启动时的角标更新
在handleOpenedPushNotification中,处理应用未启动时点击通知的场景,同步更新角标:
Future handleOpenedPushNotification() async { if (isWeb) { return; } final notification = await FirebaseMessaging.instance.getInitialMessage(); if (notification != null) { await _handlePushNotification(notification); // 应用未启动时点击通知,更新角标 int currentCount = await FlutterAppBadger.getBadgeCount() ?? 0; if (currentCount > 0) { await FlutterAppBadger.updateBadgeCount(currentCount - 1); } else { await FlutterAppBadger.removeBadge(); } } FirebaseMessaging.onMessageOpenedApp.listen(_handlePushNotification); }
注意事项
- 平台兼容性:flutter_app_badger支持iOS和部分Android机型,iOS需在Xcode中开启
Push Notifications和Background Modes下的Remote notifications权限;Android部分机型可能需要额外配置。 - 如果推送消息中携带了
badge字段,也可以直接使用该字段的值来设置角标,替换累加逻辑即可。
内容的提问来源于stack exchange,提问作者Yury_X
相关产品推荐
相关产品推荐

