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

Dart开发:跨类传递Firebase Cloud Messaging消息Map始终为空的问题

问题根源

你现在遇到的核心问题是:在onMessage回调里创建了一个新的PushList(push: message)实例,但这个实例和当前页面上正在显示的PushList完全是两个独立的对象。Flutter的StatefulWidget状态是和它的Widget实例绑定的,你新创建的实例并没有被挂载到Widget树中,所以页面上的widget.push始终是初始的空值,不会更新。

解决方案:使用状态管理工具共享通知状态

最可靠的跨组件/跨类传递状态的方式是使用状态管理,这里推荐使用Flutter官方的provider包(简单易上手),步骤如下:

1. 添加provider依赖

在pubspec.yaml中添加:

dependencies:
  flutter:
    sdk: flutter
  provider: ^6.0.5 # 可替换为最新版本

2. 创建通知状态管理类

这个类负责存储当前收到的通知,并在通知更新时通知UI刷新:

import 'package:flutter/foundation.dart';

class NotificationProvider extends ChangeNotifier {
  Map<dynamic, dynamic>? _currentNotification;

  // 提供外部访问通知的方法
  Map<dynamic, dynamic>? get currentNotification => _currentNotification;

  // 更新通知并通知UI
  void updateNotification(Map<dynamic, dynamic> message) {
    _currentNotification = message;
    notifyListeners(); // 触发所有监听该状态的UI组件刷新
  }
}

3. 在应用顶层注入状态管理器

在main.dart中用ChangeNotifierProvider包裹你的应用,让所有子组件都能访问到状态:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => NotificationProvider(),
      child: const MyApp(),
    ),
  );
}

// 你的MyApp类保持原有逻辑即可
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Notification Demo',
      home: PushList(), // 假设PushList是首页
    );
  }
}

4. 修改PushConfig类,更新状态

在PushConfig中获取状态管理器实例,收到通知时更新状态:

import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class PushConfig {
  final BuildContext context;

  // 传入上下文,用于获取状态管理器
  PushConfig(this.context);

  Future<void> pushAPIConfigMethod() async {
    FirebaseMessaging fcm = FirebaseMessaging.instance;
    
    // 监听前台收到的通知
    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      print("onMessage: ${message.data}");
      final title = message.notification?.title;
      final body = message.notification?.body;
      print("title: $title | body: $body");

      // 更新通知状态
      Provider.of<NotificationProvider>(context, listen: false)
          .updateNotification(message.data);
    });

    // 处理应用从后台/冷启动打开的场景(可选)
    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
      print("onResume/onLaunch: ${message.data}");
      Provider.of<NotificationProvider>(context, listen: false)
          .updateNotification(message.data);
    });
  }
}

注意:这里替换了旧的fcm.configureAPI,改用Firebase Messaging最新的监听方式,旧API已被弃用,建议升级使用。

5. 修改PushList类,监听状态变化

让PushList监听NotificationProvider的状态变化,自动刷新UI:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class PushList extends StatefulWidget {
  const PushList({Key? key}) : super(key: key);

  @override
  _PushListState createState() => _PushListState();
}

class _PushListState extends State<PushList> {
  @override
  void initState() {
    super.initState();
    // 初始化推送配置
    PushConfig(context).pushAPIConfigMethod();
  }

  @override
  Widget build(BuildContext context) {
    // 监听通知状态变化,状态更新时自动重建UI
    final currentNotification = Provider.of<NotificationProvider>(context).currentNotification;

    return Scaffold(
      extendBody: true,
      backgroundColor: Colors.white, // 替换为你项目中的颜色变量
      appBar: AppBar(
        title: const Text("Minhas Notificações"),
      ),
      body: ListView(
        children: [
          currentNotification == null
              ? Card(
                  elevation: 4,
                  margin: const EdgeInsets.all(10),
                  child: const Padding(
                    padding: EdgeInsets.symmetric(vertical: 20, horizontal: 16),
                    child: Text(
                      "Você não possui novas notificações.",
                      textAlign: TextAlign.center,
                    ),
                  ),
                )
              : Card(
                  elevation: 4,
                  margin: const EdgeInsets.all(10),
                  child: ListTile(
                    title: Text(currentNotification['title'] ?? "Sem título"),
                    subtitle: Text(currentNotification['body'] ?? "Sem conteúdo"),
                  ),
                )
        ],
      ),
    );
  }
}
其他可选方案

如果你的组件层级比较近(比如PushList是PushConfig的父组件),也可以用回调函数的方式传递通知:

  • 在PushList中定义回调void Function(Map<dynamic, dynamic>) onNotificationReceived
  • 将回调传递给PushConfig
  • 在onMessage中调用回调,PushList收到后调用setState更新push变量

但对于跨类/跨层级的场景,状态管理(比如Provider、Riverpod、Bloc)是更优雅、可扩展的方案。

内容的提问来源于stack exchange,提问作者Kaya Ryuuna

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 11:52:34