storekit
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseStoreKit
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.
| Reference | Load When |
|---|---|
| Getting Started | Setting up |
| Products | Loading products, product types, purchasing with |
| Subscriptions | Auto-renewable subscriptions, subscription groups, offers, renewal tracking |
| Transactions | Transaction listener, verification, finishing transactions, restore purchases |
| StoreKit Views | ProductView, SubscriptionStoreView, SubscriptionOfferView in SwiftUI |
只要有极小概率需要用到相关内容,就一定要加载参考文件。 提前获取上下文总好过遗漏模式或犯错。
| 参考资料 | 加载时机 |
|---|---|
| 入门指南 | 设置.storekit配置文件、采用测试优先工作流时 |
| 产品 | 加载产品、了解产品类型、使用 |
| 订阅 | 处理自动续订订阅、订阅组、优惠活动、续订跟踪时 |
| 交易 | 配置交易监听器、验证交易、完成交易、恢复购买时 |
| StoreKit 视图 | 在SwiftUI中使用ProductView、SubscriptionStoreView、SubscriptionOfferView时 |
Core Workflow
核心工作流
- Create configuration file first (before any code)
.storekit - Test purchases locally in Xcode simulator
- Implement centralized with
StoreManager@MainActor - Set up listener at app launch
Transaction.updates - Display products with or custom UI
ProductView - Always call after granting entitlements
transaction.finish()
- 先创建.storekit配置文件(在编写任何代码之前)
- 在Xcode模拟器中本地测试购买流程
- 实现带有的集中式
@MainActorStoreManager - 在应用启动时设置监听器
Transaction.updates - 使用或自定义UI展示产品
ProductView - 授予权益后务必调用
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
常见错误
-
Missingcalls on transactions — Forgetting to call
.finish()after granting entitlements causes transactions to never complete. The user won't see their purchase reflected. Always calltransaction.finish().finish() -
Unsafe StoreManager state — Sharedwithout
StoreManagercan have race conditions. Multiple async tasks can update@MainActorproperties concurrently, corrupting state. Use@Publishedfor thread safety.@MainActor -
No transaction listener at app launch — Not setting uplistener means app crashes or misses refunded/canceled purchases. Listen for transactions immediately in
Transaction.updates, not when user taps purchase button.@main -
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).
-
Ignoring verification failures — App Store verification fails silently sometimes. Not checking verification status means accepting unverified transactions (security risk). Always verify before granting entitlements.
-
遗漏对交易的调用 —— 在授予权益后忘记调用
.finish()会导致交易永远无法完成,用户将看不到购买结果。务必调用transaction.finish()。finish() -
不安全的StoreManager状态 —— 未使用的共享
@MainActor可能存在竞态条件。多个异步任务可能同时更新StoreManager属性,导致状态损坏。使用@Published保证线程安全。@MainActor -
应用启动时未设置交易监听器 —— 未配置监听器会导致应用崩溃或错过退款/取消的购买记录。要在
Transaction.updates中立即监听交易,而不是在用户点击购买按钮时才设置。@main -
硬编码产品ID —— 硬编码ID会增加测试和本地化的难度。应使用配置文件或环境变量存储产品ID。价格同理(从App Store获取,不要硬编码)。
-
忽略验证失败 —— App Store验证有时会静默失败。不检查验证状态意味着接受未经验证的交易(存在安全风险)。授予权益前务必进行验证。