storekit

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

StoreKit

StoreKit

StoreKit 2 patterns for implementing in-app purchases with async/await APIs, automatic verification, and SwiftUI integration.
StoreKit 2 模式:使用async/await API、自动验证和SwiftUI集成实现应用内购买

Reference Loading Guide

参考资料加载指南

ALWAYS load reference files if there is even a small chance the content may be required. It's better to have the context than to miss a pattern or make a mistake.
ReferenceLoad When
Getting StartedSetting up
.storekit
configuration file, testing-first workflow
ProductsLoading products, product types, purchasing with
Product.purchase()
SubscriptionsAuto-renewable subscriptions, subscription groups, offers, renewal tracking
TransactionsTransaction listener, verification, finishing transactions, restore purchases
StoreKit ViewsProductView, SubscriptionStoreView, SubscriptionOfferView in SwiftUI
只要有极小概率需要用到相关内容,就一定要加载参考文件。 提前获取上下文总好过遗漏模式或犯错。
参考资料加载时机
入门指南设置.storekit配置文件、采用测试优先工作流时
产品加载产品、了解产品类型、使用
Product.purchase()
进行购买时
订阅处理自动续订订阅、订阅组、优惠活动、续订跟踪时
交易配置交易监听器、验证交易、完成交易、恢复购买时
StoreKit 视图在SwiftUI中使用ProductView、SubscriptionStoreView、SubscriptionOfferView时

Core Workflow

核心工作流

  1. Create
    .storekit
    configuration file first (before any code)
  2. Test purchases locally in Xcode simulator
  3. Implement centralized
    StoreManager
    with
    @MainActor
  4. Set up
    Transaction.updates
    listener at app launch
  5. Display products with
    ProductView
    or custom UI
  6. Always call
    transaction.finish()
    after granting entitlements
  1. 先创建.storekit配置文件(在编写任何代码之前)
  2. 在Xcode模拟器中本地测试购买流程
  3. 实现带有
    @MainActor
    的集中式
    StoreManager
  4. 在应用启动时设置
    Transaction.updates
    监听器
  5. 使用
    ProductView
    或自定义UI展示产品
  6. 授予权益后务必调用
    transaction.finish()

Essential Architecture

核心架构

swift
@MainActor
final class StoreManager: ObservableObject {
    @Published private(set) var products: [Product] = []
    @Published private(set) var purchasedProductIDs: Set<String> = []
    private var transactionListener: Task<Void, Never>?

    init() {
        transactionListener = listenForTransactions()
        Task { await loadProducts() }
    }
}
swift
@MainActor
final class StoreManager: ObservableObject {
    @Published private(set) var products: [Product] = []
    @Published private(set) var purchasedProductIDs: Set<String> = []
    private var transactionListener: Task<Void, Never>?

    init() {
        transactionListener = listenForTransactions()
        Task { await loadProducts() }
    }
}

Common Mistakes

常见错误

  1. Missing
    .finish()
    calls on transactions
    — Forgetting to call
    transaction.finish()
    after granting entitlements causes transactions to never complete. The user won't see their purchase reflected. Always call
    finish()
    .
  2. Unsafe StoreManager state — Shared
    StoreManager
    without
    @MainActor
    can have race conditions. Multiple async tasks can update
    @Published
    properties concurrently, corrupting state. Use
    @MainActor
    for thread safety.
  3. No transaction listener at app launch — Not setting up
    Transaction.updates
    listener means app crashes or misses refunded/canceled purchases. Listen for transactions immediately in
    @main
    , not when user taps purchase button.
  4. Hardcoded product IDs — Hardcoded IDs make testing and localization hard. Use configuration files or environment variables for product IDs. Same applies to prices (fetch from App Store, don't hardcode).
  5. Ignoring verification failures — App Store verification fails silently sometimes. Not checking verification status means accepting unverified transactions (security risk). Always verify before granting entitlements.
  1. 遗漏对交易的
    .finish()
    调用
    —— 在授予权益后忘记调用
    transaction.finish()
    会导致交易永远无法完成,用户将看不到购买结果。务必调用
    finish()
  2. 不安全的StoreManager状态 —— 未使用
    @MainActor
    的共享
    StoreManager
    可能存在竞态条件。多个异步任务可能同时更新
    @Published
    属性,导致状态损坏。使用
    @MainActor
    保证线程安全。
  3. 应用启动时未设置交易监听器 —— 未配置
    Transaction.updates
    监听器会导致应用崩溃或错过退款/取消的购买记录。要在
    @main
    中立即监听交易,而不是在用户点击购买按钮时才设置。
  4. 硬编码产品ID —— 硬编码ID会增加测试和本地化的难度。应使用配置文件或环境变量存储产品ID。价格同理(从App Store获取,不要硬编码)。
  5. 忽略验证失败 —— App Store验证有时会静默失败。不检查验证状态意味着接受未经验证的交易(存在安全风险)。授予权益前务必进行验证。