TestFlight内应用内购买代码无法正常工作求助
问题:TestFlight及苹果审核环境中StoreKit 2购买按钮无响应
我的应用因购买按钮无法正常使用多次被苹果审核拒绝。该功能在Xcode模拟器及真机测试时完全正常,能正常弹出App Store购买窗口,但在TestFlight测试中点击购买按钮完全无响应。我已向苹果说明使用的是StoreKit 2且无需验证收据,但相关指南并未提供有效帮助。以下是一键触发产品购买的代码,请问为何该功能在常规测试正常,却在TestFlight及苹果审核环境中失效?
Button(action: { Task { try await storeManager.purchase() } }) { Text("Continue") } import Foundation import StoreKit let productIDs = ["my_product_1", "my_product_2"] class StoreManager: ObservableObject { static let shared = StoreManager() @Published var storeProducts: [Product] = [] @Published var purchasedProducts: Set<Product> = [] var transacitonListener: Task<Void, Error>? = nil init() { transacitonListener = listenForTransactions() Task { await loadProducts() await updateCurrentEntitlements() } } func getProduct(index: Int) -> Product? { for product in storeProducts { if product.id == productIDs[index] { return product } } return nil } func getProductPrice() -> String { if let product = getProduct(index: 0) { return product.displayPrice } return "4.99 USD" } func getProductPriceOrigin() -> String { if let product = getProduct(index: 1) { return product.displayPrice } return "9.99 USD" } func isPurchased() -> Bool { return purchasedProducts.contains { $0.id == productIDs[0] } } @MainActor func purchase() async throws -> Transaction? { log("enter") let product: Product? = getProduct(index: 0) if product == nil { log("product nil") return nil } log("before purchase") let result = try await product!.purchase() log("after purchase") switch result { case let .success(.verified(transaction)): purchasedProducts.insert(product!) await transaction.finish() log("success") return transaction case let .success(.unverified(_, error)): print("purchase.success.unverified:", error) log("success unverified") break case .pending: log("pending") break case .userCancelled: log("userCancelled") break default: log("default") break } return nil } @MainActor private func loadProducts() async { do { storeProducts = try await Product.products(for: productIDs) } catch { print("Failed to load product \(productIDs):", error) } } private func listenForTransactions() -> Task < Void, Error > { return Task.detached { for await result in Transaction.updates { await self.handleTransaction(transactionVerification: result) } } } private func updateCurrentEntitlements() async { for await result in Transaction.currentEntitlements { await self.handleTransaction(transactionVerification: result) } } @MainActor private func handleTransaction(transactionVerification result: VerificationResult <Transaction>) async { switch result { case let.verified(transaction): guard let product = self.storeProducts.first(where: { $0.id == transaction.productID }) else { return } self.purchasedProducts.insert(product) await transaction.finish() default: return } } @MainActor func restore() async throws { try await AppStore.sync() } }
可能的原因及解决方案
1. 产品加载异步时序问题
StoreManager初始化时异步加载产品,但购买按钮可能在产品未完成加载时就被点击,导致getProduct(index:0)返回nil,购买流程直接终止。常规测试中产品加载较快,而TestFlight/审核环境的App Store响应或网络速度较慢,触发了这个边界情况。
- 解决方法:
- 给购买按钮添加状态控制,仅当目标产品存在时允许点击:
Button(action: { Task { try await storeManager.purchase() } }) { Text("Continue") }.disabled(storeManager.getProduct(index: 0) == nil) - 在
purchase()方法中,若产品为nil则抛出明确错误,而非静默返回:enum StoreError: Error { case productNotFound } @MainActor func purchase() async throws -> Transaction? { log("enter") guard let product = getProduct(index: 0) else { log("product nil") throw StoreError.productNotFound } // 后续购买逻辑 }
- 给购买按钮添加状态控制,仅当目标产品存在时允许点击:
2. 事务监听任务的生命周期与拼写问题
变量名transacitonListener存在拼写错误(应为transactionListener),可能导致引用异常;同时未处理监听任务的取消逻辑,任务可能被意外取消,无法接收购买回调。
- 解决方法:
- 修正变量名拼写错误,统一为
transactionListener。 - 在
StoreManager的deinit方法中取消监听任务:deinit { transactionListener?.cancel() }
- 修正变量名拼写错误,统一为
3. 未处理购买方法的异常
当前代码中Task { try await storeManager.purchase() }未捕获异常,若购买过程抛出错误(如网络问题),会导致任务静默失败,无任何提示。
- 解决方法:
- 捕获异常并添加用户提示:
Button(action: { Task { do { try await storeManager.purchase() } catch { print("购买失败:\(error.localizedDescription)") // 这里可添加Alert等UI提示告知用户购买失败 } } }) { Text("Continue") }
- 捕获异常并添加用户提示:
4. App Store Connect产品配置问题
TestFlight和审核环境会严格校验产品配置,可能存在以下问题:
- 产品ID
my_product_1在App Store Connect中未创建或状态未设为"可供销售"。 - 应用Bundle ID与App Store Connect配置不匹配。
- 测试账号未添加为TestFlight测试员,或未启用沙盒购买权限。
- 解决方法:
- 核对App Store Connect中产品ID与代码完全一致,且产品状态为激活状态。
- 确认测试员账号已正确配置,TestFlight默认使用沙盒环境测试。
5. 主线程调度问题
虽然purchase()标注了@MainActor,但复杂场景下仍可能出现线程调度异常,需确保所有UI相关状态更新在主线程执行。
- 解决方法:
- 保持
handleTransaction等方法的@MainActor标注,确保purchasedProducts等状态更新在主线程完成。
- 保持
内容的提问来源于stack exchange,提问作者user1385809
相关产品推荐
相关产品推荐

