跳转到主要内容

iOS 收据验证 (StoreKit 2)

验证 Unity IAP 5.0 (StoreKit 2) 的签名交易 (Signed Transaction, JWS)。

StoreKit 2 (JWS) 方式

此方法验证 Unity IAP 5.0 (iOS 15.0 及以上) 的 StoreKit 2 签名交易 (JWS)。如果使用 Unity IAP 4.x (StoreKit 1) 的 Base64 收据,请参考 iOS 收据验证。

调用信息​

IAP.IOS_JWS(string jwsTransaction, string productID, PlayNANOODelegate callback) {}
IAP.IOS_JWS(string jwsTransaction, string productID, bool isDuplicateAllow, PlayNANOODelegate callback) {}

调用详细信息​

参数说明类型
jwsTransaction签名交易信息 (JWS)。Unity IAP 5.0 的 pendingOrder.Info.Apple?.jwsRepresentationstring
productID支付商品 IDstring
isDuplicateAllow是否允许重复收据验证boolean
callback通信结果PlayNANOODelegate
无需货币/金额参数

与旧版 IOS() 不同,无需传递 currency、price。货币和金额由服务器直接从 JWS payload 中提取,以防止篡改。

示例​

使用 Unity IAP 服务的情况 (Unity IAP 5.0)

using PlayNANOO;
using UnityEngine.Purchasing;

public class PlayNANOOExample : MonoBehaviour
{
Plugin plugin;

void Awake()
{
plugin = Plugin.GetInstance();
}

// Unity IAP 5.0 - PendingOrder 처리
public void OnPurchasePending(PendingOrder pendingOrder)
{
string jws = pendingOrder.Info.Apple?.jwsRepresentation;
string productID = pendingOrder.CartOrdered.Items()[0].Product.definition.id;

plugin.IAP.IOS_JWS(jws, productID, (status, errorMessage, jsonString, values) => {
if (status.Equals(Configure.PN_API_STATE_SUCCESS))
{
Debug.Log(values["UserID"]);
Debug.Log(values["PackageName"]);
Debug.Log(values["OrderID"]);
Debug.Log(values["ProductID"]);
Debug.Log(values["Currency"]);
Debug.Log(values["Quantity"]);
Debug.Log(values["Price"]);
Debug.Log(values["PurchaseState"]);

// 검증 성공 시 거래 확정
storeController.ConfirmPurchase(pendingOrder);
}
else
{
Debug.Log("Fail");
}
});
}
}

通信结果​

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
{
"UserID" : "String",
"PackageName" : "String",
"OrderID" : "String",
"ProductID" : "String",
"Quantity" : "Integer",
"Currency" : "String",
"Price" : "Integer",
"PurchaseState" : "String"
}

通信结果详细信息​

数据键说明类型
UserID用户识别 IDstring
PackageName应用包名string
OrderID订单 ID (transactionId)string
ProductID支付商品 IDstring
Quantity购买数量integer
Currency支付货币代码string
Price支付商品金额integer
PurchaseState验证结果 (purchase 正常支付 / wait 处理中 / cancel 验证失败)string
退款检测

转向 StoreKit 2 的游戏可以通过 App Store Server Notifications(Webhook) 自动检测退款。注册步骤请参考本页底部的 退款 Webhook 注册 部分。

错误信息​

收据验证失败的情况 ErrorCode : 20000
ErrorMessage : ValidationFailException

应用程序包名不匹配的情况 ErrorCode : 20002
ErrorMessage : NotMatchPackageNameException

收据已被使用的情况 ErrorCode : 20005
ErrorMessage : ExistsReceiptException

退款 Webhook 注册 (App Store Server Notifications)​

若要实时接收退款(REFUND) 等事件,请在 App Store Server Notifications(Version 2) 中注册下方的 Webhook URL。Webhook 以游戏(应用) 为单位运行,因此无论 SDK 版本如何,只要注册 URL 即可生效,退款会自动反映到支付日志中。

Webhook URL​

https://service-api.playnanoo.com/webhook/apple/{gameId}

{gameId} 是游戏频道 ID。请在 控制台 > 设置 > API及平台设置 > iOS 下方,使用复制按钮复制按游戏自动生成的实际 URL 后使用。

App Store Connect 注册步骤​

步骤说明
1进入 App Store Connect > 选择应用 > 应用信息 > App Store Server Notifications
2在 Production Server URL 中输入上述 Webhook URL
3在 Sandbox Server URL 中也输入相同的 URL
4Notification Version 选择 "Version 2" 后保存
无需单独的认证密钥 (.p8)

Webhook 接收验证同样仅通过 JWS 签名(Apple 证书链) 完成,因此无需单独的认证密钥。Production / Sandbox 的区分由 Apple 发送的 payload 中的 environment 字段自动判别。