StoreKit 2 是 Apple 推出的新一代內購開發框架(適配 iOS 15+/macOS 12+/tvOS 15+),相比初代大幅簡化內購流程、強化異步處理與用户體驗,是開發 App 內購(IAP)的首選方案。以下聚焦核心流程、關鍵 API 與實戰要點,適配 Swift 開發場景。

一、核心優勢

  1. 簡化流程:用 Product Transaction 等結構化 API 替代初代繁雜的代理回調,代碼更簡潔;
  2. 異步安全:全流程基於 async/await 異步編程,避免回調地獄,適配現代 Swift 開發;
  3. 用户體驗優化:支持內購恢復、價格本地化、交易狀態實時追蹤,減少用户操作成本;
  4. 合規適配:內置收據驗證、退款處理邏輯,符合 App Store 審核規範。

二、開發前置準備

1. 開發者後台配置

  • 登錄 App Store Connect,創建 App 內購項目(消耗型、非消耗型、訂閲型),填寫產品 ID、價格、描述等信息;
  • 開啓 “App 內購買項目” 權限,配置沙盒測試賬號(用於測試內購流程,避免真實扣費)。

2. 工程配置

  • Xcode 版本 ≥ 13.2(需支持 iOS 15+ 部署目標);
  • 項目 Signing & Capabilities 中開啓 In-App Purchase 能力;
  • 導入框架:import StoreKit

三、核心開發流程

1. 加載內購產品

通過產品 ID 加載 App Store 配置的內購項目,獲取價格、描述等信息:

swift

// 定義產品 ID(需與 App Store Connect 一致)
let productIDs = ["com.xxx.app.consumable", "com.xxx.app.subscription.monthly"]

// 加載產品
func fetchProducts() async throws -> [Product] {
    let products = try await Product.products(for: productIDs)
    // 按產品類型/價格排序(可選)
    return products.sorted { $0.price < $1.price }
}

// 調用示例
Task {
    do {
        let products = try await fetchProducts()
        // 展示到 UI(如價格、購買按鈕)
        for product in products {
            print("產品名:\(product.displayName),價格:\(product.price)")
        }
    } catch {
        print("加載產品失敗:\(error.localizedDescription)")
    }
}

2. 發起購買請求

調用 purchase() 方法發起購買,處理交易結果:

swift

func purchaseProduct(_ product: Product) async throws -> Transaction? {
    // 發起購買
    let result = try await product.purchase()
    
    switch result {
    case .success(let verification):
        // 驗證交易有效性
        switch verification {
        case .unverified(let transaction, let error):
            print("交易驗證失敗:\(error.localizedDescription)")
            return nil
        case .verified(let transaction):
            // 完成交易(必須調用,否則交易狀態異常)
            await transaction.finish()
            return transaction
        }
    case .userCancelled:
        print("用户取消購買")
        return nil
    case .pending:
        print("交易待處理(如家長審核)")
        return nil
    @unknown default:
        return nil
    }
}

// 調用示例(綁定到購買按鈕點擊事件)
Task {
    if let product = products.first { // 取第一個產品示例
        do {
            let transaction = try await purchaseProduct(product)
            if transaction != nil {
                print("購買成功,解鎖功能")
                // 此處處理解鎖付費功能邏輯
            }
        } catch {
            print("購買失敗:\(error.localizedDescription)")
        }
    }
}

3. 恢復已購項目

用户重裝 App / 切換設備時,恢復過往購買(重點適配非消耗型 / 訂閲型內購):

swift

func restorePurchases() async {
    do {
        // 恢復所有已購交易
        for await result in Transaction.currentEntitlements {
            switch result {
            case .unverified(let transaction, let error):
                print("恢復驗證失敗:\(error)")
            case .verified(let transaction):
                // 解鎖對應功能
                print("恢復成功:\(transaction.productID)")
                await transaction.finish()
            }
        }
    } catch {
        print("恢復失敗:\(error.localizedDescription)")
    }
}

4. 驗證交易(可選但推薦)

本地驗證交易有效性,或調用 App Store 服務器 API 驗證(避免篡改):

swift

// 本地基礎驗證(簡化版)
func verifyTransaction(_ transaction: Transaction) -> Bool {
    guard transaction.revocationDate == nil else {
        // 交易已撤銷(退款),鎖定功能
        return false
    }
    return true
}

四、關鍵注意事項

  1. 沙盒測試:必須使用沙盒賬號測試,真實賬號會觸發真實扣費;測試訂閲時,可通過 App Store Connect 加速訂閲週期(縮短測試時長);
  2. 交易狀態:所有交易必須調用 finish() 方法,否則會重複觸發;
  3. 訂閲管理:訂閲型內購需監聽 Transaction.updates 事件,處理訂閲續訂、過期、取消等狀態;
  4. 審核合規:App 內需提供 “恢復購買” 按鈕,訂閲型內購需清晰展示價格、續訂規則,避免誤導用户;
  5. 錯誤處理:覆蓋網絡異常、用户取消、家長控制、地區限制等場景,給出友好提示。

五、常見問題

  1. 產品加載失敗:檢查產品 ID 與 App Store Connect 一致、網絡正常、沙盒環境配置正確;
  2. 購買提示 “無法連接到 App Store”:確認設備登錄沙盒賬號、網絡無代理、Xcode 簽名配置正確;
  3. 訂閲恢復失敗:確保 Transaction.currentEntitlements 遍歷完整,處理 revocationDate 非空場景。

總結

StoreKit 2 以 async/await 為核心,大幅降低內購開發複雜度。核心流程可總結為:配置產品 ID → 加載產品 → 發起購買 → 驗證交易 → 解鎖功能 → 處理恢復 / 退款,重點關注沙盒測試與合規適配,即可快速完成內購功能開發。