StoreKit 2内购产品错误报告模块无法识别StoreKitError求助
StoreKit 2 加载内购产品错误处理问题
我正在用StoreKit 2配置非消耗型内购产品,苹果在App Store Connect/Xcode的内购配置文档里建议提交审核前要测试43种错误场景,但不管是苹果官方还是其他在线示例,都没给出覆盖这些错误的代码实现。
目前我主要卡在**加载产品(load product)**相关的错误处理上。根据苹果对products(for:)方法的说明:
若存在无效标识符或App Store无法找到对应标识符,这些标识符会被排除在返回值外;
products(for:)函数可能因系统相关错误抛出StoreKitError。
测试加载产品错误时,所有场景都只显示带加载轮(progressView())的空白页面,而且代码里的错误捕获switch语句还报错,比如**"Type '[Product]' has no member 'systemError'"**,看起来代码识别不了我自定义的StoreKitError枚举。
以下是StoreModel的部分代码:
@MainActor final class StoreModel: ObservableObject { enum StoreKitError { case networkError(URLError) case systemError(any Error) case userCancelled case notAvailableInStorefront case notEntitled case unknown } public enum PurchaseFinishedAction { case dismissStore case noAction case displayError } func fetchProducts() async throws -> PurchaseFinishedAction { let action: PurchaseFinishedAction do { products = try await Product.products( for: productIDs) } catch { switch products { case .networkError(URLError): action = .displayError case .systemError(any Error): action = .displayError case .userCancelled: action = .noAction case .notAvailableInStorefront: action = .displayError case .notEntitled: action = .displayError case .product.unknown: action = .displayError } } return action } }
代码问题分析
- 错误分支里不该
switch products:products是请求成功时才会赋值的数组,错误场景下它的类型是[Product],根本没有自定义枚举的case,这是报错的核心原因。 - 未处理系统错误映射:
Product.products(for:)抛出的是系统自带的StoreKit.Error,不是自定义的StoreKitError枚举,需要手动做类型转换和映射。 - Switch case写法错误:比如
.networkError(URLError)这种写法不符合Swift枚举匹配语法,应该用模式匹配绑定错误值。
修正后的代码示例
@MainActor final class StoreModel: ObservableObject { @Published var products: [Product] = [] let productIDs: [String] = ["your.product.id1", "your.product.id2"] enum StoreKitError { case networkError(URLError) case systemError(any Error) case userCancelled case notAvailableInStorefront case notEntitled case invalidProductIDs case unknown } public enum PurchaseFinishedAction { case dismissStore case noAction case displayError } func fetchProducts() async -> PurchaseFinishedAction { let action: PurchaseFinishedAction do { products = try await Product.products(for: productIDs) // 处理无效产品ID场景:返回产品数量少于请求ID数量 if products.count != productIDs.count { action = .displayError } else { action = .noAction } } catch { let customError = mapToCustomError(error) switch customError { case .networkError, .systemError, .notAvailableInStorefront, .notEntitled, .invalidProductIDs, .unknown: action = .displayError case .userCancelled: action = .noAction } } return action } // 系统错误转自定义错误的映射方法 private func mapToCustomError(_ error: Error) -> StoreKitError { guard let storeKitError = error as? StoreKit.Error else { return .systemError(error) } switch storeKitError { case .networkError(let urlError): return .networkError(urlError) case .userCancelled: return .userCancelled case .notAvailableInStorefront: return .notAvailableInStorefront case .notEntitled: return .notEntitled default: return .unknown } } }
关键补充说明
- 无效ID单独处理:
products(for:)不会为无效ID抛出错误,只会过滤掉这些ID,所以需要对比请求ID数量和返回产品数量来识别该场景。 - 加载状态控制:在View层要结合
products的空状态、fetchProducts的返回action来管理加载轮显示,比如请求开始时显示加载轮,结束后隐藏,失败时展示错误提示。 - 错误场景测试:可以用Xcode的StoreKit测试工具或Sandbox环境模拟错误,比如断网测试网络错误、用未配置的ID测试无效ID场景等。
内容的提问来源于stack exchange,提问作者Galen Smith
相关产品推荐
相关产品推荐

