基于StoreKit 2应用交易的商业模式变更生产环境异常求助
我按照苹果官方文档指引在应用主视图实现了商业模式变更逻辑,该逻辑在模拟器、物理设备及TestFlight测试环境均运行正常,但发布至App Store生产环境后出现异常——所有新老用户都被要求订阅。测试环境能正常获取交易信息并输出日志,但生产环境无法查看控制台日志,也无法正常获取内容。
沙箱收据信息
AppTransaction.shared obtained: { "applicationVersion" : "1", "bundleId" : ***** "deviceVerification" : "6M0Nnw14nSEOBVTPE\\/\\/EfnWSwLm7LFSlrpFEwxgH74SBHp5dSzBEm896Uvo42mwr", "deviceVerificationNonce" : "8a8238c0-0aee-41e6-bfb0-1cfc52b70fb6", "originalApplicationVersion" : "1.0", "originalPurchaseDate" : 1375340400000, "receiptCreationDate" : 1737577840917, "receiptType" : "Sandbox", "requestDate" : 1737577840917 }
测试环境验证日志
New business model change: 1.7 Original version components: ["1", "0"] Major version: 1, Minor version: 0 This user is premium. Original version: 1.0
核心逻辑代码
.task { do { let shared = try await AppTransaction.shared if case .verified(let appTransaction) = shared { let newBusinessModelVersion = (1, 7) // Represented as (major, minor) let versionComponents = appTransaction.originalAppVersion.split(separator: ".") if let majorVersion = versionComponents.first.flatMap({ Int($0) }), let minorVersion = versionComponents.dropFirst().first.flatMap({ Int($0) }) { if (majorVersion, minorVersion) < newBusinessModelVersion { self.premiumStatus.isPremium = true isPremium = true } else { let customerInfo = try await Purchases.shared.customerInfo() self.premiumStatus.isPremium = customerInfo.entitlements["premium"]?.isActive == true isPremium = self.premiumStatus.isPremium } } else { print("Error: obtaining version components") } } else { print("Not verified") } } catch { print("Error processing transaction: \(error.localizedDescription)") } }
问题分析
从测试数据来看,沙箱环境中originalAppVersion为1.0,能正确解析版本号并判定老用户为Premium。生产环境异常的可能原因:
生产环境
originalAppVersion格式不符合预期
代码依赖版本号按.分割为主、次版本,但生产环境中该字段可能是纯数字(如1)或其他格式,导致解析失败进入else分支,进而调用订阅检查逻辑,老用户因无订阅记录被判定为非Premium。AppTransaction生产环境验证失败
生产环境中AppTransaction.shared可能返回.unverified,导致代码跳过Premium判定逻辑,默认用户无权限。版本比较逻辑的硬编码风险
新商业模式版本硬编码为(1,7),若生产环境中老用户的originalAppVersion等于或高于该版本,会进入订阅检查分支,而老用户无订阅则被要求订阅。
解决方案
1. 增加版本解析容错处理
修改版本解析逻辑,当无法获取次版本时默认设为0,避免因格式问题导致逻辑走偏:
let versionComponents = appTransaction.originalAppVersion.split(separator: ".") let majorVersion = versionComponents.first.flatMap(Int.init) ?? 0 let minorVersion = versionComponents.dropFirst().first.flatMap(Int.init) ?? 0
2. 集成生产环境日志上报
由于生产环境无法查看控制台日志,接入第三方日志工具(如Firebase Crashlytics、Sentry),上报关键节点信息:
if case .verified(let appTransaction) = shared { // 上报原始版本号 Crashlytics.crashlytics().log("Original app version: \(appTransaction.originalAppVersion)") let versionComponents = appTransaction.originalAppVersion.split(separator: ".") let majorVersion = versionComponents.first.flatMap(Int.init) ?? 0 let minorVersion = versionComponents.dropFirst().first.flatMap(Int.init) ?? 0 Crashlytics.crashlytics().log("Parsed version: \(majorVersion).\(minorVersion)") // ... 后续逻辑 } else { Crashlytics.crashlytics().log("AppTransaction verification failed") }
3. 添加兜底逻辑保护老用户
当版本解析失败或验证失败时,默认赋予老用户Premium权限,避免影响正常使用:
} else { // 版本解析失败,默认老用户为Premium self.premiumStatus.isPremium = true isPremium = true Crashlytics.crashlytics().log("Version parsing failed, fallback to premium") }
4. 确认生产环境originalAppVersion格式
通过日志上报或用户反馈,确认生产环境中originalAppVersion的实际格式,确保版本解析逻辑覆盖所有可能情况。
5. 检查订阅SDK生产环境配置
确认Purchases SDK(如RevenueCat)的生产环境API密钥是否正确,避免因配置错误导致订阅状态获取失败。
内容的提问来源于stack exchange,提问作者GMarkoslansvka

