跳到主要内容

Payment API

Payment API

TudadaSDK.Instance.payment.* 是用于游戏内商品购买的支付 API。游戏无需了解支付方式·渠道, 仅通过 productId 即可发起购买。支付方式选择、价格计算、收据验证、发放处理均由投多多平台负责。

四个方法均基于回调 — 接收 onSuccess(按结果类型)与 onFailAction<PaymentFailResult>)。 失败分支始终以 PaymentFailResult.code 进行。

支付可用性 · 商店展示
  • 不支持支付的环境GetProductsonFailPAYMENT_UNAVAILABLE 被调用。
  • 支持环境,但无匹配商品products空数组(正常响应)。为空数组时请勿展示商店 UI。
  • 通信失败 — 以 NETWORK_ERROR 失败。
发放确认由游戏服务器完成

Purchase 的结果是用于界面显示·UX 的精简信息。最终发放确认请在游戏服务器进行。 交易中不包含金额·收据,权威的发放信息由游戏服务器·投多多服务器持有。

参考: 支付仅在 WebGL 构建中生效。在 Unity 编辑器模拟中,onFailPAYMENT_UNAVAILABLE 被调用(参见编辑器模拟)。

payment.GetProducts(onSuccess, onFail)

查询可购买的商品列表。若无可售商品,products 为空数组。

参数:

参数类型必须说明
onSuccessAction<GetProductsResult>-成功回调
onFailAction<PaymentFailResult>-失败回调

成功响应 (GetProductsResult):

字段类型说明
productsPaymentProduct[]可售商品列表(无则为空数组)
errMsgstring结果消息
TudadaSDK.Instance.payment.GetProducts(
onSuccess: (res) => {
if (res.products.Length == 0) { HideStore(); return; } // 空数组 → 不展示商店
foreach (var p in res.products)
Debug.Log($"{p.productId} / {p.name} / {p.price} {p.currency}");
RenderStore(res.products);
},
onFail: (err) => Debug.LogError("商品查询失败: " + err.code)
);

payment.GetProduct(productId, onSuccess, onFail)

查询单个商品。商品不存在/不可售时,onFailPRODUCT_NOT_FOUND 被调用。

参数:

参数类型必须说明
productIdstring要查询的商品 ID
onSuccessAction<GetProductResult>-成功回调
onFailAction<PaymentFailResult>-失败回调

成功响应 (GetProductResult):

字段类型说明
productPaymentProduct商品信息
errMsgstring结果消息
TudadaSDK.Instance.payment.GetProduct("coin_100",
onSuccess: (res) => Debug.Log($"{res.product.name} / {res.product.price}"),
onFail: (err) => {
if (err.code == PaymentErrorCode.ProductNotFound) ShowToast("该商品当前不可售。");
}
);

payment.Purchase(productId, passthroughPayload, onSuccess, onFail)

购买商品。成功时交易以 GRANTED(已发放)或 PENDING(已受理·等待确认) 状态返回,其他情况则调用 onFail

参数:

参数类型必须说明
productIdstring要购买的商品 ID
passthroughPayloadstring-不透明 echo 字符串(≤1000 UTF-8 字节)。购买验证时原样返回。禁止包含密钥·个人信息
onSuccessAction<PurchaseResult>-成功回调
onFailAction<PaymentFailResult>-失败回调

成功响应 (PurchaseResult):

字段类型说明
transactionPaymentTransaction交易 (GRANTED / PENDING)
errMsgstring结果消息
TudadaSDK.Instance.payment.Purchase("coin_100", "order-1234",
onSuccess: (res) => {
var txn = res.transaction;
if (txn.status == PaymentTxnStatus.Granted) {
// 已发放 — 反映到 UX(最终确认由游戏服务器进行)
} else if (txn.status == PaymentTxnStatus.Pending) {
// 已受理 — 等待确认。可通过 GetTransaction 查询后续状态
}
},
onFail: (err) => {
if (err.code == PaymentErrorCode.UserCancelled) return; // 用户关闭了支付窗口
Debug.LogError("支付失败: " + err.code);
}
);

payment.GetTransaction(txnKey, onSuccess, onFail)

查询交易状态·结果。用于 PurchasePENDING 结束后的后续确认等。 交易不存在/不属于该用户时,onFailTRANSACTION_NOT_FOUND 被调用。

参数:

参数类型必须说明
txnKeystring要查询的交易键
onSuccessAction<GetTransactionResult>-成功回调
onFailAction<PaymentFailResult>-失败回调

成功响应 (GetTransactionResult):

字段类型说明
transactionPaymentTransaction交易(5 种状态均可能)
errMsgstring结果消息
TudadaSDK.Instance.payment.GetTransaction(prevTxnKey,
onSuccess: (res) => Debug.Log("状态: " + res.transaction.status),
onFail: (err) => Debug.LogError("查询失败: " + err.code)
);

数据类型

PaymentProduct

字段类型说明
productIdstring与市场无关的单一商品 ID(购买时指定)
namestring注册商品名
pricestring(已应用折扣的)当前价格 — 显示就绪的字符串(如 "4,400""4.99")。禁止算术运算,原样显示
currencystring货币标识字符串(如 "KRW")。未识别的值原样按字符串显示
originalPricestring折扣前价格(显示就绪字符串)。无折扣则为空字符串。用于删除线等显示
discountRatestring折扣率显示字符串(如 "20%")。营销标注 — 禁止据此反推价格

价格均为显示就绪的完整字符串。已应用千位分隔符·小数位数,请原样输出,不要用于直接计算。

PaymentTransaction

用于验证·UX 的精简视图(不含金额·收据)。

字段类型说明
txnKeystring唯一键 — 用于重新查询
statusstring交易状态(见下表,PaymentTxnStatus 常量)
productIdstring交易商品
failReasonstring用于诊断·日志的详细原因(禁止向用户展示,值可能变更)。无则为空字符串
passthroughPayloadstring购买时传入的值原样返回。省略·空字符串则为空字符串
requestedAtlong请求时刻 (Unix epoch ms)
grantedAtlong首次发放时刻 (epoch ms)。未发放状态则为 0(可用 hasGrantedAt 确认是否存在)

交易状态(status):

说明
PENDING已受理,发放未确认
GRANTED已发放
FAILED失败
PARTIALLY_REFUNDED已部分退款(存在过往发放记录)
REFUNDED已退款(存在过往发放记录)

Purchase 仅返回 GRANTED / PENDING,而 GetTransaction 可返回全部 5 种状态。

错误处理

失败通过 onFailPaymentFailResult 返回,分支始终以 code 进行。

字段类型说明
codestring错误码(见下表)— 分支依据。PaymentErrorCode 常量
errMsgstring消息(禁止向用户展示)
txnKeystring仅在已记录交易的失败中存在。无则为空字符串
failReasonstring用于诊断·日志的详细原因。无则为空字符串

错误码(codePaymentErrorCode 常量):

说明
PAYMENT_UNAVAILABLE不支持支付的环境
USER_CANCELLED用户关闭了支付窗口
PAYMENT_FAILED支付失败(卡被拒·余额不足等)
PRODUCT_NOT_FOUND未注册的 productId
INVALID_PARAM无效参数(passthroughPayload 超长等)
PURCHASE_REJECTED验证/发放被拒
PAYMENT_IN_PROGRESS存在进行中的购买,拒绝新调用(同时仅 1 笔)
TRANSACTION_NOT_FOUND交易不存在或不属于该用户
SESSION_EXPIRED会话过期 — 需要重新登录
NETWORK_ERROR通信失败
TudadaSDK.Instance.payment.Purchase("coin_100", null,
onSuccess: (res) => { /* ... */ },
onFail: (err) => {
switch (err.code) {
case PaymentErrorCode.UserCancelled: break; // 静默忽略
case PaymentErrorCode.PaymentInProgress: ShowToast("正在处理中。"); break;
case PaymentErrorCode.SessionExpired: RequestRelogin(); break;
default: ShowToast("支付失败。");
}
}
);