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

Flutter:使用json_serializable反序列化firebase_messaging通知遇错求助

解决FCM消息反序列化类型不匹配问题

我之前也踩过FCM消息反序列化的坑,结合你遇到的Type 'String' is not a subtype of type 'Map < dynamic, dynamic>'和_InternalLinkedHashMap< dynamic, dynamic>' is not a subtype of type 'Map< String, dynamic>'错误,咱们一步步来排查解决:


1. 先搞清楚FCM消息的实际结构

FCM的onMessage回调返回的msg是嵌套结构,通常包含notification(推送通知的标题、内容等)和data(自定义业务字段)两个核心部分。你直接把整个msg传给FCMNotification.fromJson()大概率是不对的——因为你的模型对应的应该是其中某一个子结构,而非整个消息体。

先打印消息结构确认:

onMessage: (Map<String, dynamic> msg) {
  print('完整FCM消息结构: $msg'); // 看控制台输出的字段,定位需要反序列化的部分
  // 比如如果你的模型对应notification字段,就取这个子Map
  final notificationMap = msg['notification'] as Map<String, dynamic>;
  FCMNotification fcmNotification = FCMNotification.fromJson(notificationMap);
}

2. 处理FCM data字段的字符串值陷阱

FCM的data字段有个坑:所有值默认都是String类型,哪怕你后台传的是数字或布尔值。如果你的FCMNotification模型里有非String字段(比如int badge、bool isRead),直接反序列化就会报类型不匹配。

解决办法是用json_serializable的自定义转换逻辑:

@JsonSerializable()
class FCMNotification {
  // 给需要转换的字段加JsonKey,指定转换函数
  @JsonKey(fromJson: _stringToInt, defaultValue: 0)
  final int badge;

  @JsonKey(fromJson: _stringToBool, defaultValue: false)
  final bool isRead;

  final String title;

  FCMNotification({required this.badge, required this.isRead, required this.title});

  factory FCMNotification.fromJson(Map<String, dynamic> json) =>
      _$FCMNotificationFromJson(json);

  Map<String, dynamic> toJson() => _$FCMNotificationToJson(this);
}

// 自定义字符串转int的函数
int _stringToInt(String? value) {
  if (value == null) return 0;
  return int.tryParse(value) ?? 0;
}

// 自定义字符串转bool的函数
bool _stringToBool(String? value) {
  if (value == null) return false;
  return value.toLowerCase() == 'true';
}

3. 显式转换嵌套Map的类型

有时候FCM返回的嵌套Map是_InternalLinkedHashMap类型,直接强转Map<String, dynamic>会失败。这时候可以用Map<String, dynamic>.from()来做类型转换:

onMessage: (Map<String, dynamic> msg) {
  // 处理notification字段
  final rawNotification = msg['notification'];
  if (rawNotification != null) {
    final notificationMap = Map<String, dynamic>.from(rawNotification as Map);
    FCMNotification fcmNotification = FCMNotification.fromJson(notificationMap);
  }

  // 处理data字段同理
  final rawData = msg['data'];
  if (rawData != null) {
    final dataMap = Map<String, dynamic>.from(rawData as Map);
    // 用dataMap反序列化对应的模型
  }
}

4. 检查模型字段与FCM字段的匹配度

json_serializable默认是蛇形命名与驼峰命名自动转换(比如模型里的notificationTitle对应JSON里的notification_title),但如果FCM返回的字段名和你模型的字段名不匹配(比如大小写不一致、命名规则不同),也会导致反序列化失败。

这时候需要用@JsonKey(name: "xxx")指定对应关系:

@JsonSerializable()
class FCMNotification {
  // FCM返回的字段是"notification_title",模型里用驼峰
  @JsonKey(name: "notification_title")
  final String notificationTitle;

  FCMNotification({required this.notificationTitle});

  // ... 其他代码
}

按照上面的步骤排查,应该能解决你遇到的类型转换问题。

内容的提问来源于stack exchange,提问作者Thomas Nicole

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:30:44