Flutter中如何根据用户Token状态禁用推送通知
仅向授权Flutter用户发送推送通知的实现方案
你的代码核心问题是Token加载时机不对——main函数里判断Constants.USER_TOKEN的时候,shared_preferences里的Token还没读出来,这时候的判断完全无效。得把推送通知的配置逻辑移到_MyAppState里,等Token加载完成后再处理。
第一步:重构main函数
移除main中与Token校验相关的推送初始化代码,只保留基础初始化逻辑:
void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); await Permission.notification.request(); // 初始化本地通知插件 var initializationSettingsAndroid = const AndroidInitializationSettings('@drawable/ic_notification'); var initializationSettingsIOS = const DarwinInitializationSettings(); var initializationSettings = InitializationSettings( android: initializationSettingsAndroid, iOS: initializationSettingsIOS); await flutterLocalNotificationsPlugin.initialize(initializationSettings); runApp(const MyApp()); }
第二步:完善_MyAppState的Token校验与推送配置
在_MyAppState中完成Token加载、推送权限配置、消息监听等逻辑,确保只有已授权用户能接收推送:
class MyApp extends StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> with WidgetsBindingObserver { final FirebaseMessaging _messaging = FirebaseMessaging.instance; @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); _initApp(); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } Future<void> _initApp() async { // 1. 加载本地存储的用户授权Token await _loadUserToken(); // 2. 根据Token状态配置推送服务 await _configurePushNotifications(); // 3. 处理应用冷启动时的推送消息 await _handleInitialMessage(); } Future<void> _loadUserToken() async { SharedPreferences pref = await SharedPreferences.getInstance(); setState(() { Constants.USER_TOKEN = pref.getString('login') ?? ""; }); } Future<void> _configurePushNotifications() async { // 请求推送权限 await _messaging.requestPermission(); // 根据用户授权状态控制推送开关 if (Constants.USER_TOKEN.isEmpty) { await _messaging.setAutoInitEnabled(false); // 可选:主动删除Firebase Token,避免服务器向未授权用户发推送 await _messaging.deleteToken(); } else { await _messaging.setAutoInitEnabled(true); // 获取并打印Firebase Token(仅已登录用户) String? token = await _messaging.getToken(); if (token != null) { print("FIREBASE TOKEN $token"); } if (Platform.isIOS) { var APNS = await _messaging.getAPNSToken(); print('APNS: $APNS'); } } // 配置前台通知展示选项 await _messaging.setForegroundNotificationPresentationOptions( alert: true, badge: true, sound: true, ); // 前台推送监听:仅已登录用户展示通知 FirebaseMessaging.onMessage.listen((RemoteMessage message) { if (Constants.USER_TOKEN.isNotEmpty) { RemoteNotification? notification = message.notification; AndroidNotification? android = message.notification?.android; if (notification != null && android != null) { flutterLocalNotificationsPlugin.show( notification.hashCode, notification.title, notification.body, NotificationDetails( android: AndroidNotificationDetails( channel.id, channel.name, channelDescription: channel.description, icon: '@mipmap/ic_launcher', ), ), ); } } }); // 推送打开应用监听:仅已登录用户跳转通知页面 FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { print("On message opened app: ${message.data}"); if (navKey.currentState != null && Constants.USER_TOKEN.isNotEmpty) { navKey.currentState!.push(MaterialPageRoute( builder: (context) => const NotificationScreen(), )); } }); } Future<void> _handleInitialMessage() async { RemoteMessage? initialMessage = await _messaging.getInitialMessage(); if (initialMessage != null && navKey.currentState != null) { if (Constants.USER_TOKEN.isNotEmpty) { navKey.currentState!.push(MaterialPageRoute( builder: (context) => NotificationScreen(), )); } print('Message opened from terminated state'); } } }
关键修改说明
- 将Token加载和推送配置移到
initState流程中,确保Token加载完成后再执行推送逻辑 - 未登录用户主动禁用推送自动初始化,并可删除Firebase Token,彻底阻断推送通道
- 所有推送监听逻辑都增加了授权判断,确保只有已登录用户能接收通知、跳转页面
- 修正了原代码中
onMessageOpenedApp的语法错误(多了一个大括号)
内容的提问来源于stack exchange,提问作者st4tic
相关产品推荐
相关产品推荐

