WWDC Quick Look 💓 By SwiftGGTeam
Manage in-app purchases on your server

Manage in-app purchases on your server

观看原视频

Highlight

App Store Server API 支持主动查询交易历史、订阅状态和退款信息;Server Notifications V2 覆盖 20+ 种事件类型;新增 Family Sharing 支持和沙盒环境改进。

核心内容

你的应用有内购功能。用户购买后,客户端把 receipt 发给服务器验证。但用户可能在离线时购买,或者客户端请求失败。你怎么确保服务器上的购买记录是完整的?

App Store Server API 和 Server Notifications V2 让你可以主动拉取数据,而不是被动等待客户端上报。

详细内容

App Store Server API

01:14

Server API 是一组 RESTful 接口,你的服务器可以用 JWT 认证后调用。

查询交易历史:

GET https://api.storekit.itunes.apple.com/inApps/v1/history/{originalTransactionId}

返回用户的完整交易历史,包括所有续订、升级、降级和退款。

查询订阅状态:

GET https://api.storekit.itunes.apple.com/inApps/v1/subscriptions/{originalTransactionId}

返回当前订阅的详细状态,包括过期时间、自动续订状态、优惠类型等。

02:30

关键点:

  • originalTransactionId 查询,不是 transactionId
  • originalTransactionId 在整个订阅生命周期中不变
  • 返回 JWS(JSON Web Signature)格式的签名数据
  • 需要验证签名确保数据来自 Apple

Server Notifications V2

04:00

V2 的通知类型从 V1 的 10 种扩展到 20+ 种,覆盖订阅生命周期的所有关键事件:

通知类型说明
SUBSCRIBED新订阅
RENEWAL自动续订成功
DID_CHANGE_RENEWAL_STATUS用户开启/关闭自动续订
DID_CHANGE_RENEWAL_PREF用户升级/降级订阅
EXPIRED订阅过期
REFUND退款
REFUND_DECLINED退款被拒绝
CONSUMPTION_REQUEST请求消费数据
REVOKE家庭共享被撤销

05:15

关键点:

  • V2 通知包含更丰富的信息
  • 所有通知都是 JWS 格式
  • 需要验证签名
  • 如果返回非 200,Apple 会在几天内重试

验证 JWS 签名

06:30

Server API 和通知返回的数据都是 JWS 格式,需要验证签名:

import CryptoKit

func verifyJWS(_ jwsString: String) throws -> Transaction {
    // 1. 分离 JWS 的三个部分
    let parts = jwsString.split(separator: ".")
    guard parts.count == 3 else { throw VerificationError.invalidFormat }

    // 2. 解析 header,获取证书
    let headerData = base64Decode(String(parts[0]))
    let header = try JSONDecoder().decode(JWSHeader.self, from: headerData)

    // 3. 从 Apple 获取公钥并验证证书链
    let certificate = try validateCertificateChain(header.x5c)

    // 4. 验证签名
    let signedData = Data((parts[0] + "." + parts[1]).utf8)
    let signature = base64Decode(String(parts[2]))
    let isValid = certificate.publicKey.isValidSignature(signature, for: signedData)

    guard isValid else { throw VerificationError.invalidSignature }

    // 5. 解析 payload
    let payloadData = base64Decode(String(parts[1]))
    return try JSONDecoder().decode(Transaction.self, from: payloadData)
}

07:45

关键点:

  • JWS 包含 header、payload、signature 三部分
  • 从 Apple 获取根证书验证证书链
  • 验证签名确保数据未被篡改
  • 解析 payload 获取交易信息

Family Sharing

09:00

iOS 15 支持内购的 Family Sharing。用户购买后,家庭成员可以自动访问,不需要额外付费。

Server API 中可以通过 inAppOwnershipType 字段区分:

  • PURCHASED:用户自己购买
  • FAMILY_SHARED:通过家庭共享获得

当家庭共享被撤销时,服务器会收到 REVOKE 通知。

10:15

关键点:

  • inAppOwnershipType 区分购买和共享
  • REVOKE 通知表示共享被撤销
  • 需要处理共享用户的访问权限
  • 适合订阅和非消耗型内购

沙盒环境改进

11:30

沙盒环境新增功能:

  • 测试订阅加速:沙盒中的订阅周期被压缩(1年=1小时)
  • 测试退款:可以在沙盒中模拟退款流程
  • 测试家庭共享:可以在沙盒中测试 Family Sharing
  • 测试优惠:可以在沙盒中测试 introductory offer 和 promotional offer

12:45

关键点:

  • 沙盒订阅周期加速,方便测试续订
  • 沙盒支持退款测试
  • 沙盒支持家庭共享测试
  • 测试账号在 App Store Connect 中管理

核心启发

  1. 用 Server API 主动同步购买状态。不要只依赖客户端上报,服务器定期拉取确保数据一致。入口 API:GET /inApps/v1/history/{originalTransactionId}

  2. 用 Server Notifications V2 实时响应状态变化。20+ 种事件类型覆盖订阅全生命周期。入口 API:配置服务器 URL 接收 JWS 通知。

  3. 验证所有 JWS 数据的签名。防止中间人攻击和数据篡改。入口 API:Apple 根证书 + JWS 签名验证。

  4. 支持 Family Sharing。区分 PURCHASEDFAMILY_SHARED,处理 REVOKE 通知。入口 API:inAppOwnershipType + REVOKE 通知。

  5. 在沙盒中测试完整购买流程。利用加速订阅周期快速测试续订、升级、降级和退款。入口 API:App Store Connect 沙盒测试账号。

关联 Session

评论

GitHub Issues · utterances