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

iOS端无法处理FCM推送通知数据,触发空值检查运算符错误

FCM iOS端通知数据空值问题排查与修复

问题场景

已完成FCM全配置,能正常接收推送通知,但处理通知逻辑时出现异常:调用retrieveRideRequestInfo(getRideRequestId(message.data)!, context);尝试获取通知数据并弹窗,iOS端在(message.data)!处触发Null check operator used on a null value错误,Android端运行完全正常。

当前使用的getRideRequestId函数:

String? getRideRequestId(Map<String, dynamic> message) {
    String? rideRequestId = "";

    if (Platform.isAndroid) {
      rideRequestId = message['ride_request_id'];
      print("This is ride request ID :$rideRequestId");
    } else {
      //for ios
      rideRequestId = message['data'];
    }
    return rideRequestId;
  }

同时提供发送通知的代码,确认针对iOS是否正确:

static sendNotificationToDriver(
      String token, context, String rideRequestId) async {
    try {
      await http.post(
        Uri.parse('https://fcm.googleapis.com/fcm/send'),
        headers: <String, String>{
          'Authorization': serverToken,
          'Content-Type': 'application/json',
        },
        body: jsonEncode({
          "to": token,
          "collapse_key": "type_a",
          "notification": {
            "body": "Nepali Rider",
            "title": "You have a new Ride"
          },
          "data": {"ride_request_id": rideRequestId}
        }),
      );
      print('FCM request for device sent!');
    } catch (e) {
      print(e);
    }
    print("ride request id :$rideRequestId");
    print("ride request id :$token");
    print(jsonEncode);
  }

错误原因

  1. 平台数据结构差异:iOS与Android的FCM通知数据解析逻辑不同,当前函数对iOS的处理完全错误——发送的data字段是一个包含ride_request_id的Map,而非直接作为字符串值,所以message['data']拿到的是Map,后续使用时会出现类型不匹配,且如果message本身没有data键就会返回null。
  2. 空值未处理:调用getRideRequestId(message.data)!时,message.data可能为null(比如iOS后台推送场景),直接使用!强制非空会触发错误。
  3. 后台推送配置缺失:iOS后台推送需要额外配置content_available字段,否则App在后台时可能无法正确获取到data字段。

修复方案

1. 修正getRideRequestId函数

统一处理iOS和Android的数据解析,同时增加空值判断:

String? getRideRequestId(Map<String, dynamic>? message) {
  // 先判断message是否为空
  if (message == null) return null;

  String? rideRequestId;
  // 优先从data字段中提取ride_request_id
  final data = message['data'] as Map<String, dynamic>?;
  if (data != null) {
    rideRequestId = data['ride_request_id'];
  } else {
    // 兼容某些iOS场景下数据直接在根节点的情况
    rideRequestId = message['ride_request_id'];
  }

  print("This is ride request ID :$rideRequestId");
  return rideRequestId;
}

2. 安全调用通知处理逻辑

避免直接使用!强制非空,增加空值校验:

// 先校验message.data是否有效
if (message.data != null) {
  final rideRequestId = getRideRequestId(message.data);
  if (rideRequestId != null) {
    retrieveRideRequestInfo(rideRequestId, context);
  } else {
    print("未获取到有效的ride_request_id");
  }
} else {
  print("通知数据为空,无法处理请求");
}

3. 优化发送端代码(适配iOS后台推送)

在FCM请求中添加content_available: true,确保iOS后台能唤醒App处理数据:

body: jsonEncode({
  "to": token,
  "collapse_key": "type_a",
  "content_available": true, // 启用iOS后台推送唤醒
  "notification": {
    "body": "Nepali Rider",
    "title": "You have a new Ride"
  },
  "data": {"ride_request_id": rideRequestId}
}),

额外注意事项

  • 确保iOS端已正确申请推送权限,包括后台刷新权限(在Info.plist中配置UIBackgroundModes包含remote-notification)。
  • 测试时分别验证App前台、后台、被杀掉三种状态下的推送处理逻辑,确保覆盖所有场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 07:15:39