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 商户后台显示的字段为准。
需要确认:
- 使用的 Key 类型符合 SDK 要求;
- Test Key 和 Live Key 没有混用;
- 测试交易使用测试卡和测试环境;
- 当前商户账户已启用目标国家、币种和支付方式;
- Android 的 package name 或 iOS 的 bundle identifier 与后台登记信息一致;
- 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 中。
用最小配置隔离问题
可以按以下顺序排查:
- 使用官方示例项目或官方最小配置;
- 使用 Test Key、受支持的测试币种和测试支付方式;
- 删除非必填字段、自定义回调 URL 和额外业务参数;
- 确认最小交易能够启动并完成;
- 每次只恢复一个业务字段;
- 确认加入哪个字段后开始返回
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 初始化、凭据和原生配置。如果已经生成交易记录,应以后台记录中的拒绝原因或状态码为主要线索。
备注:内容仅供参考。
