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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 17:01:13