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

Flutter集成Google Pay:paymentResult非有效JSON如何解析

问题解答

1. paymentResult的实际数据类型

  • 它不是JSON字符串,是Flutter平台通道从Android/iOS原生层传递过来的原生结构化Map对象,对应Dart侧的类型是Map<dynamic, dynamic>。
  • 调用toString()打印时看到键名没有双引号,是Dart中Map默认的toString()输出格式,不是标准JSON结构,直接用jsonDecode处理必然失败。
  • 遍历看不到第三个条目的核心原因:Map<String, dynamic>.from()仅做浅转换,外层key被转成了String,但嵌套的paymentMethodData等值仍然是Map<dynamic, dynamic>类型,遍历过程中触发隐式类型校验异常时会中断循环(部分Flutter版本下未捕获的这类异常不会直接打印红色报错,只会终止遍历逻辑),加上Flutter默认日志单条长度有1000字符左右的截断,容易误导判断条目不存在。

2. 正确解析提取字段的方式

不要用遍历键值对判断的方式取值,直接通过key索引访问即可,访问嵌套结构时手动做类型强转,解析逻辑外层包try-catch捕获潜在类型异常,示例代码:

void onGooglePayResult(paymentResult) {
  try {
    // 先强转外层为可安全访问的Map
    final resMap = Map<String, dynamic>.from(paymentResult);
    
    // 提取基础字段
    final int apiVersion = resMap['apiVersion'];
    final int apiVersionMinor = resMap['apiVersionMinor'];
    
    // 提取paymentMethodData嵌套结构
    final paymentMethodData = Map<String, dynamic>.from(resMap['paymentMethodData']);
    final String cardDesc = paymentMethodData['description'];
    final String payType = paymentMethodData['type'];
    
    // 提取卡信息、账单地址
    final cardInfo = Map<String, dynamic>.from(paymentMethodData['info']);
    final billingAddress = Map<String, dynamic>.from(cardInfo['billingAddress']);
    final String userName = billingAddress['name'];
    final String phoneNumber = billingAddress['phoneNumber'];
    final String countryCode = billingAddress['countryCode'];
    final String address1 = billingAddress['address1'];
    final String postalCode = billingAddress['postalCode'];
    final String cardNetwork = cardInfo['cardNetwork'];
    final String cardDetail = cardInfo['cardDetails'];
    
    // 提取支付token(核心需要传给服务端的字段)
    final tokenData = Map<String, dynamic>.from(paymentMethodData['tokenizationData']);
    final String payToken = tokenData['token'];
    final String tokenType = tokenData['type'];

    // 后续把提取到的字段传给服务端即可
  } catch (e) {
    log('Google Pay结果解析异常: $e');
  }
}

注意:所有嵌套Map取值后都要调用Map<String, dynamic>.from()做一次转换,避免后续操作时出现dynamic类型的调用异常。

3. 快速转换为自定义实体类的方法

可以先写一个递归转换方法,把整个Map<dynamic, dynamic>完全转换成全String key的标准JSON结构Map,之后就可以和普通接口返回的JSON一样,配合常用的序列化方案(比如json_serializable、手写fromJson构造方法)转成自定义实体,递归转换工具方法示例:

Map<String, dynamic> convertDynamicMap(Map<dynamic, dynamic> originMap) {
  final result = <String, dynamic>{};
  originMap.forEach((key, value) {
    if (value is Map<dynamic, dynamic>) {
      result[key.toString()] = convertDynamicMap(value);
    } else if (value is List) {
      result[key.toString()] = value.map((item) {
        if (item is Map<dynamic, dynamic>) return convertDynamicMap(item);
        return item;
      }).toList();
    } else {
      result[key.toString()] = value;
    }
  });
  return result;
}

使用时只需要先调用一次转换方法,后续就可以走熟悉的JSON序列化逻辑:

void onGooglePayResult(paymentResult) {
  final standardJsonMap = convertDynamicMap(paymentResult);
  // 直接传入实体类fromJson方法即可
  final gPayResult = MyPaymentResult.fromJson(standardJsonMap);
}

对应的自定义实体类基础结构(可根据需要的字段删减):

class MyPaymentResult {
  int apiVersion;
  int apiVersionMinor;
  PaymentMethodData paymentMethodData;

  MyPaymentResult({this.apiVersion, this.apiVersionMinor, this.paymentMethodData});

  MyPaymentResult.fromJson(Map<String, dynamic> json) {
    apiVersion = json['apiVersion'];
    apiVersionMinor = json['apiVersionMinor'];
    paymentMethodData = json['paymentMethodData'] != null 
      ? PaymentMethodData.fromJson(json['paymentMethodData']) 
      : null;
  }
}
// 其余PaymentMethodData、BillingAddress、TokenizationData等子类同理按照嵌套结构写fromJson即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 01:09:25