iOS 收据验证 (StoreKit 2)
验证 Unity IAP 5.0 (StoreKit 2) 的签名交易 (Signed Transaction, 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?.jwsRepresentation | string |
| productID | 支付商品 ID | string |
| 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 | 用户识别 ID | string |
| PackageName | 应用包名 | string |
| OrderID | 订单 ID (transactionId) | string |
| ProductID | 支付商品 ID | string |
| 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 |
| 4 | Notification Version 选择 "Version 2" 后保存 |
Webhook 接收验证同样仅通过 JWS 签名(Apple 证书链) 完成,因此无需单独的认证密钥。Production / Sandbox 的区分由 Apple 发送的 payload 中的 environment 字段自动判别。