跳转到主要内容

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() 不同,无需传递 currencyprice。货币和金额由服务器直接从 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
2Production Server URL 中输入上述 Webhook URL
3Sandbox Server URL 中也输入相同的 URL
4Notification Version 选择 "Version 2" 后保存
无需单独的认证密钥 (.p8)

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