跳转到主要内容

iOS 收据验证 (StoreKit 2)

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

URL 确认

此 API 使用 service-api.playnanoo.com 域名。

StoreKit 2 (JWS) 方式

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

API 信息

  • URL: https://service-api.playnanoo.com/iap/v20260401/unity/ios
  • Method: PUT
  • 需要认证: 是

请求参数

参数类型必填说明
jws_transactionstring必填签名交易信息 (JWS)。Unity IAP 5.0 的 jwsRepresentation
product_idstring必填支付商品 ID
duplicate_allowstring选填是否允许重复验证收据 (Y/N)
无 currency / price 参数

与旧版 v20221001 不同,无需传递 currencyprice。货币和金额由服务器直接从 JWS payload 中提取。

响应数据

Res 类

字段类型说明
UserIDstring用户 ID
PackageNamestring包名
OrderIDstring订单 ID (transactionId)
ProductIDstring商品 ID
Quantitystring数量
Currencystring货币代码
Pricestring价格
PurchaseStatestring验证结果
purchase : 正常支付
wait : 处理中
cancel : 验证失败

Unity C# 实现

BaseResponse 类

所有 API 响应的基类。

public class BaseResponse
{
public string ErrorCode;
public string Message;
public string WithdrawalKey;
public string BlockKey;
}

字段说明:

  • ErrorCode:错误代码
  • Message:错误信息
  • WithdrawalKey:账号处于注销等待状态时,用于恢复的密钥(仅注销等待中的账号提供)
  • BlockKey:账号被封禁时提供的密钥(仅被封禁的账号提供)

iOS IAP 验证类 (StoreKit 2)

using System;
using System.Collections;
using UnityEngine.Networking;

public class IAPUnityIOSJWS
{
static string path = "https://service-api.playnanoo.com/iap/v20260401/unity/ios";

[Serializable]
public class Req
{
public string jws_transaction; // 서명된 거래 정보 (JWS)
public string product_id; // 결제 상품 아이디
public string duplicate_allow; // 영수증 중복 검증 허용 여부

public IEnumerator Send(string jws_transaction, string product_id, bool duplicate_allow, Action<Res> onSuccess, Action<BaseResponse> onError)
{
if (!string.IsNullOrEmpty(jws_transaction)) this.jws_transaction = jws_transaction;
if (!string.IsNullOrEmpty(product_id)) this.product_id = product_id;
this.duplicate_allow = duplicate_allow ? "Y" : "N";

yield return HttpClient.Send<Req, Res>(
UnityWebRequest.kHttpVerbPUT,
path,
requireToken: true,
body: this,
onSuccess: onSuccess,
onError: onError
);
}
}

[Serializable]
public class Res : BaseResponse
{
public string UserID;
public string PackageName;
public string OrderID;
public string ProductID;
public string Quantity;
public string Currency;
public string Price;
public string PurchaseState;
}
}

使用示例

public void ValidateIOSIAP(PendingOrder pendingOrder)
{
IAPUnityIOSJWS.Req req = new IAPUnityIOSJWS.Req();

// Unity IAP 5.0 (StoreKit 2) 서명된 거래
string jwsTransaction = pendingOrder.Info.Apple?.jwsRepresentation;
string productId = "com.example.game.gold_100";

StartCoroutine(req.Send(
jws_transaction: jwsTransaction,
product_id: productId,
duplicate_allow: false, // 중복 영수증 허용 안 함
onSuccess: res =>
{
Debug.Log($"IAP 검증 성공");
Debug.Log($"사용자 ID: {res.UserID}");
Debug.Log($"주문 ID: {res.OrderID}");
Debug.Log($"상품 ID: {res.ProductID}");
Debug.Log($"가격: {res.Price} {res.Currency}");
Debug.Log($"상태: {res.PurchaseState}");
},
onError: (error) =>
{
Debug.LogError($"IAP 검증 실패: [{error.ErrorCode}] [{error.Message}]");
}
));
}
获取 JWS

jws_transaction 是从 Unity IAP 5.0 的 pendingOrder.Info.Apple?.jwsRepresentation 获取的签名交易 (Signed Transaction) 字符串。Unity IAP 5.0 需要 iOS 15.0 及以上

本地证书链验证

服务器以 Apple Root CA G3 为基准验证 (ES256) JWS 内置的 x5c 证书链,无需向 Apple 服务器进行额外调用或密钥文件 (.p8)。Sandbox / Xcode 支付会以测试模式保存,不计入销售额。

退款检测 (Webhook)

注册 App Store Server Notifications(Version 2) 后,将自动接收退款 (REFUND) 事件。注册 URL 为 https://service-api.playnanoo.com/webhook/apple/{gameId},详细内容请参考控制台的 API 及平台设置 > iOS。