WWDC Quick Look 💓 By SwiftGGTeam
Support customers and handle refunds

Support customers and handle refunds

观看原视频

Highlight

StoreKit 2 新增 showManageSubscriptions()beginRefundRequest() API,让用户在应用内管理订阅和申请退款;Consumption API 让开发者向 Apple 提供消费数据,参与退款决策。

核心内容

用户想取消订阅,但找不到入口。用户想申请退款,但不知道怎么做。这些场景下,用户可能给应用差评,或者联系 Apple 支持。如果能在应用内直接解决这些问题,用户体验会好很多。

StoreKit 2 今年新增了三个 API 来解决这些痛点。

详细内容

应用内管理订阅

11:42

以前用户要管理订阅,必须离开应用去 App Store。现在可以在应用内直接打开管理页面。

import StoreKit

// 显示订阅管理页面
func showSubscriptionManagement() {
    if let windowScene = view.window?.windowScene {
        Task {
            try await AppStore.showManageSubscriptions(in: windowScene)
        }
    }
}

12:20

关键点:

  • AppStore.showManageSubscriptions(in:) 显示系统管理页面
  • 用户可以看到当前订阅、续订选项
  • 可以升级、降级或取消订阅
  • 所有操作同步到 App Store

你还可以在管理页面前展示挽留优惠:

// 在用户点击取消前展示优惠
func showRetentionOffer() {
    // 展示自定义挽留界面
    // 如果用户仍想取消,再调用 showManageSubscriptions
}

应用内申请退款

13:36

用户可以直接在应用内申请退款,不需要联系 Apple 支持。

import StoreKit

// 申请退款
func requestRefund(for transaction: Transaction) async {
    do {
        let refundStatus = try await transaction.beginRefundRequest(
            in: view.window!.windowScene!
        )

        switch refundStatus {
        case .success:
            // 退款申请已提交
            showRefundSubmittedMessage()
        case .userCancelled:
            // 用户取消了申请
            break
        }
    } catch {
        // 处理错误
        print("Refund request failed: \(error)")
    }
}

14:14

关键点:

  • transaction.beginRefundRequest(in:) 发起退款申请
  • 系统显示退款原因选择界面
  • 退款批准后服务器收到 REFUND 通知
  • 退款被拒绝后服务器收到 REFUND_DECLINED 通知
  • 沙盒环境支持退款测试

Invoice Lookup API

03:44

用户联系客服说 “我买了东西但没收到”。客服可以要求用户提供订单号(order ID),然后通过 Invoice Lookup API 查询。

GET https://api.storekit.itunes.apple.com/inApps/v1/lookup/{orderId}

返回:

{
  "status": 0,
  "signedTransactions": [
    {
      "transactionId": "1000000123456789",
      "originalTransactionId": "1000000098765432",
      "productId": "com.example.coins",
      "purchaseDate": 1620000000000,
      "quantity": 100
    }
  ]
}

04:20

关键点:

  • status 0 表示有效,1 表示订单号无效,2 表示无匹配交易
  • 返回 JWS 格式的签名交易数据
  • 可以验证交易状态和退款状态
  • 帮助客服快速定位问题

Refund Lookup API

06:02

查询某个用户的所有退款记录:

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

适合处理服务器 outage 后补同步退款数据。

06:44

关键点:

  • originalTransactionId 查询
  • 返回该用户的所有退款交易
  • 适合补同步和审计
  • 返回 JWS 格式数据

Subscription Extension API

09:40

如果服务出现故障(如直播中断),你可以免费延长用户的订阅时间作为补偿。

PUT https://api.storekit.itunes.apple.com/inApps/v1/subscriptions/extend

{
  "originalTransactionId": "1000000098765432",
  "extensionDuration": 7,
  "extensionReason": 1,
  "requestIdentifier": "unique-request-id"
}

10:23

关键点:

  • 每个订阅每年最多延长 2 次
  • 每次最多延长 90 天
  • 需要提供原因代码
  • 用户会收到邮件通知
  • 延长期不计入 85% 分成的一年期限

Consumption API

19:12

当用户申请退款时,Apple 会向你的服务器发送 CONSUMPTION_REQUEST 通知。你可以在 12 小时内回复消费数据,帮助 Apple 做退款决策。

PUT https://api.storekit.itunes.apple.com/inApps/v1/consumption/{originalTransactionId}

{
  "customerConsented": true,
  "consumptionStatus": 1,
  "consumptionPlatform": 1,
  "sampleContent": 1,
  "deliveryStatus": 0,
  "appAccountToken": "uuid-string",
  "accountTenure": 365,
  "playTime": 120,
  "lifetimeSpend": 99.99,
  "userStatus": 0
}

20:00

关键点:

  • customerConsented:用户是否同意分享数据
  • consumptionStatus:0=未消费,1=部分消费,2=完全消费,3=已转让
  • deliveryStatus:0=成功交付,1=交付失败
  • 必须在 12 小时内回复
  • 数据帮助 Apple 做更准确的退款决策

核心启发

  1. 在应用内提供订阅管理入口。用户不需要离开应用就能查看和修改订阅。入口 API:AppStore.showManageSubscriptions(in:)

  2. 在应用内提供退款申请入口。减少用户给差评或联系 Apple 支持的概率。入口 API:transaction.beginRefundRequest(in:)

  3. 用 Invoice Lookup API 辅助客服。用户报问题时,用订单号快速查询交易状态。入口 API:GET /inApps/v1/lookup/{orderId}

  4. 用 Subscription Extension API 补偿服务故障。直播中断或服务器故障时,免费延长用户订阅。入口 API:PUT /inApps/v1/subscriptions/extend

  5. 回复 Consumption Request 参与退款决策。提供消费数据,减少不合理的退款。入口 API:PUT /inApps/v1/consumption/{originalTransactionId}

关联 Session

评论

GitHub Issues · utterances