PAYATHON 2026

React Native 中 Tap Payment 调用后返回 FAILED

支付老李

结论

{"sdk_result":"FAILED","trx_mode":"CHARGE"} 是 GoSell SDK 返回的通用失败结果,仅凭这两个字段无法判断具体原因。常见原因包括:

  • 密钥类型错误,或测试环境与生产环境不匹配;
  • sdkConfigurations 中有字段缺失、为空或格式错误;
  • 商户账户、应用包名或支付方式尚未在 Tap 后台启用;
  • Android 或 iOS 原生配置不完整;
  • SDK 没有返回详细错误,需要结合原生日志或 Tap 后台交易记录排查。

建议先使用最小配置和 Tap 提供的测试凭据验证支付流程,确认可用后再逐项恢复业务参数。

首先检查密钥和环境

不要直接把普通服务端支付 API 的 Secret Key 当作移动 SDK 凭据。GoSell React Native SDK 需要哪种 Key,应以当前版本的官方文档和 Tap 商户后台显示的字段为准。

需要确认:

  1. 使用的 Key 类型符合 SDK 要求;
  2. Test Key 和 Live Key 没有混用;
  3. 测试交易使用测试卡和测试环境;
  4. 当前商户账户已启用目标国家、币种和支付方式;
  5. Android 的 package name 或 iOS 的 bundle identifier 与后台登记信息一致;
  6. Key 中没有多余的空格、换行,也没有在复制时被截断。

不要将拥有服务端权限的 Secret Key 固化在 React Native JavaScript 包中。移动端代码可以被提取和反编译。如果 SDK 要求客户端凭据,应使用官方指定的移动端 Key,服务端 Secret Key 则保留在后端。

检查 sdkConfigurations

配置对象中的字段无效,经常会导致 SDK 直接返回 FAILED。调用前应检查:

  • 金额是有效正数,不是 undefined、NaN 或格式错误的字符串;
  • currency 是商户账户支持的币种;
  • transactionMode、paymentType 等枚举值符合当前 SDK 文档;
  • customer、order、postURL、paymentReference 等对象结构正确;
  • 必填字符串不为空;
  • 回调地址是有效的 HTTPS URL;
  • 测试环境没有传入仅限生产环境使用的支付方式。

不要为了套用示例而照搬其中的占位值,例如电话号码、国家代码、订单编号或 URL。

调用前可以输出脱敏后的配置:

const safeConfigurations = {
  ...sdkConfigurations,
  // 根据实际字段名处理,避免把完整密钥写入日志
  secretKey: sdkConfigurations.secretKey
    ? `${sdkConfigurations.secretKey.slice(0, 6)}***`
    : undefined,
};

console.log(
  'GoSell configuration:',
  JSON.stringify(safeConfigurations, null, 2),
);

RNGoSell.goSellSDK.startPayment(sdkConfigurations, handleResult);

生产环境中不要记录完整密钥、卡号、Token 或客户敏感信息。

完整记录回调结果

先检查 handleResult 是否丢弃了 SDK 返回的其他字段:

const handleResult = result => {
  console.log('GoSell raw result:', JSON.stringify(result, null, 2));

  switch (result?.sdk_result) {
    case 'SUCCESS':
      // 最终支付状态仍应由后端向 Tap 查询或通过 webhook 确认
      break;

    case 'CANCELLED':
      // 用户主动取消
      break;

    case 'FAILED':
      console.error('GoSell payment failed:', result);
      break;

    default:
      console.warn('Unknown GoSell result:', result);
  }
};

try {
  RNGoSell.goSellSDK.startPayment(sdkConfigurations, handleResult);
} catch (error) {
  console.error('Unable to start GoSell SDK:', error);
}

如果回调中仍然只有 sdk_result 和 trx_mode,说明 React Native 封装层没有暴露底层错误。继续修改 JavaScript 回调通常无法获得更多信息,此时需要查看原生日志。

查看 Android 和 iOS 原生日志

在 Android Studio 的 Logcat 中搜索:

GoSell
Tap
Payment
Exception
FAILED

也可以运行:

adb logcat

在 iOS 上,应通过 Xcode 启动应用,检查控制台中的 SDK 初始化错误、网络错误和异常堆栈。

主要关注以下信息:

  • authentication 或 invalid key;
  • merchant/account not enabled;
  • unsupported currency;
  • invalid amount;
  • package name 或 bundle identifier 不匹配;
  • 网络请求失败或 TLS 错误;
  • Activity、URL Scheme、framework、Pod 或 Gradle 依赖缺失。

不要只检查 Metro 控制台。支付页面通常由原生 SDK 运行,具体的失败原因可能只会出现在 Logcat 或 Xcode Console 中。

用最小配置隔离问题

可以按以下顺序排查:

  1. 使用官方示例项目或官方最小配置;
  2. 使用 Test Key、受支持的测试币种和测试支付方式;
  3. 删除非必填字段、自定义回调 URL 和额外业务参数;
  4. 确认最小交易能够启动并完成;
  5. 每次只恢复一个业务字段;
  6. 确认加入哪个字段后开始返回 FAILED。

如果官方示例项目在同一设备上使用同一套商户凭据也会失败,问题更可能出在账户权限、Key、SDK 兼容性或 Tap 后台配置,而不是业务代码。

检查原生集成和兼容性

React Native 包通常只是 Android 和 iOS GoSell SDK 的桥接层。即使 JavaScript 调用方式没有问题,遗漏原生配置也可能导致 SDK 只返回通用失败结果。

请根据当前安装版本的文档重新核对:

  • Android AndroidManifest.xml、Gradle 仓库和依赖;
  • iOS Pods、framework、URL Scheme 和应用能力;
  • React Native 版本是否在该包的支持范围内;
  • Android minSdkVersion、targetSdkVersion 和 iOS Deployment Target;
  • 真机与模拟器上的表现是否一致;
  • 清理并重新构建原生工程后,问题是否仍然存在。

不要默认 npm 页面上的旧示例仍适用于当前的 React Native、Android Gradle Plugin、Xcode 或 iOS 版本。

后端确认支付状态

无论客户端返回 SUCCESS 还是 FAILED,都不应将其作为订单最终状态的唯一依据。后端应使用 Tap 的交易查询接口或 webhook 校验:

  • 交易 ID;
  • 支付状态;
  • 金额和币种;
  • 商户订单号;
  • webhook 签名或其他官方校验机制。

客户端负责展示即时结果,后端负责确认是否实际收款。

仍无法定位时

向 Tap 支持团队提供以下信息,比只提供 FAILED 更有助于定位问题:

  • 商户 ID;
  • 测试或生产环境;
  • 失败时间和所在时区;
  • Android 或 iOS、系统版本及设备型号;
  • React Native 包版本和原生 SDK 版本;
  • package name 或 bundle identifier;
  • 脱敏后的配置;
  • 原生日志;
  • 交易 ID、订单号或后台请求记录。

不要发送完整的 Secret Key、卡号、CVV 或客户敏感数据。如果 Tap 后台没有生成任何交易记录,应优先检查 SDK 初始化、凭据和原生配置。如果已经生成交易记录,应以后台记录中的拒绝原因或状态码为主要线索。

备注:内容仅供参考。