PAYATHON 2026

Flutter 中如何从 EGHL 支付响应获取 TxnMessage

支付阿杰

结论

makePayment() 返回 JSON 字符串。先用 Dart 的 jsonDecode() 将其转换为 Map,再通过键名 TxnMessage 读取结果:

final Map<String, dynamic> response =
    jsonDecode(result) as Map<String, dynamic>;

final String txnMessage =
    response['TxnMessage']?.toString() ?? 'Unknown transaction result';

对于示例响应,txnMessage 的值为:

Transaction Failed

在现有代码中处理

将获取结果后的代码改为:

String result = await Eghlpluginunofficial.makePayment(
  merchantReturnUrl: 'SDK',
  serviceId: 'SIT',
  password: 'sit12345',
  merchantName: 'GHL ePayment Testing',
  amount: 1.00,
  paymentDescription: 'eGHL Payment testing',
  customerName: 'Somebody',
  customerEmail: 'somebody@somesite.com',
  customerPhone: '60123456789',
  paymentId: paymentId,
  orderNumber: paymentId,
  currencyCode: 'MYR',
  languageCode: 'EN',
  pageTimeout: const Duration(
    minutes: 12,
    seconds: 30,
  ),
  transactionType: 'SALE',
  paymentMethod: 'ANY',
  useDebugPaymentUrl: true,
);

final Map<String, dynamic> response =
    jsonDecode(result) as Map<String, dynamic>;

final String txnMessage =
    response['TxnMessage']?.toString() ?? 'Unknown transaction result';

if (!mounted) return;

setState(() {
  _result = txnMessage;
});

print(txnMessage);

之后,页面中的 Text(_result) 会显示 Transaction Failed。

为什么需要 jsonDecode

返回内容虽然看起来像 Dart 对象,但 result 的声明类型是 String,因此不能直接这样访问:

result['TxnMessage']

必须先把 JSON 字符串解析成键值结构:

final decoded = jsonDecode(result);

解析完成后,才能通过键名访问字段:

decoded['TxnMessage']

代码中已经导入所需的库:

import 'dart:convert';

更稳妥的完整写法

支付插件返回的内容可能为空、格式异常,或者不是预期的 JSON 对象。可以增加类型和字段检查:

Future<void> pay() async {
  try {
    final String paymentId =
        await Eghlpluginunofficial.generateId('Test');

    final String result = await Eghlpluginunofficial.makePayment(
      merchantReturnUrl: 'SDK',
      serviceId: 'SIT',
      password: 'sit12345',
      merchantName: 'GHL ePayment Testing',
      amount: 1.00,
      paymentDescription: 'eGHL Payment testing',
      customerName: 'Somebody',
      customerEmail: 'somebody@somesite.com',
      customerPhone: '60123456789',
      paymentId: paymentId,
      orderNumber: paymentId,
      currencyCode: 'MYR',
      languageCode: 'EN',
      pageTimeout: const Duration(
        minutes: 12,
        seconds: 30,
      ),
      transactionType: 'SALE',
      paymentMethod: 'ANY',
      useDebugPaymentUrl: true,
    );

    final dynamic decoded = jsonDecode(result);

    if (decoded is! Map<String, dynamic>) {
      throw const FormatException(
        'Payment response is not a JSON object',
      );
    }

    final String txnMessage =
        decoded['TxnMessage']?.toString().trim() ?? '';

    if (!mounted) return;

    setState(() {
      _result = txnMessage.isNotEmpty
          ? txnMessage
          : 'No transaction message returned';
    });
  } on FormatException catch (err) {
    if (!mounted) return;

    setState(() {
      _result = 'Invalid payment response: $err';
    });
  } on PlatformException catch (err) {
    if (!mounted) return;

    setState(() {
      _result = 'PlatformException: ${err.message ?? err.toString()}';
    });
  } catch (err) {
    if (!mounted) return;

    setState(() {
      _result = 'Error: $err';
    });
  }
}

判断支付是否成功

TxnMessage 可以用于页面展示,但不适合单独作为交易状态的判断依据,因为提示文字可能发生变化。判断结果时,应优先读取 EGHL 返回的状态字段,例如 TxnStatus,并按照当前插件或支付接口文档定义的状态值处理。

如果已经确认该接口中 "0" 代表成功,其他值代表失败,可以这样写:

final String status = decoded['TxnStatus']?.toString() ?? '';
final String message =
    decoded['TxnMessage']?.toString() ?? 'Unknown transaction result';

if (status == '0') {
  // 支付成功
} else {
  // 支付失败或状态异常
}

setState(() {
  _result = message;
});

TxnStatus 各个取值的具体含义,应以当前使用的 EGHL 接口或插件版本文档为准,不能根据一条示例响应推断所有状态码。

注意返回字符串的格式

传给 jsonDecode() 的内容必须是合法 JSON。实际返回值应类似:

{
  "TxnMessage": "Transaction Failed",
  "TxnStatus": "1"
}

问题中代码块外层的反引号只是 Markdown 格式标记。如果插件返回的原始字符串也包含反引号或其他额外字符,应先检查插件的原始输出。不要在正常情况下随意删除字符,否则可能掩盖真正的返回格式问题。

备注:内容仅供参考。