StoreKit 2业务模型变更功能App Store上线后失效求助
问题分析与解决方案:App Store上线后AppTransaction业务模型变更功能失效
可能的问题原因
1. 版本号字符串比较的逻辑错误
直接使用字符串比较originalMajorVersion < newBusinessModelMajorVersion存在逻辑漏洞:字符串是按字符逐个对比ASCII码,比如"10"会被判定为小于"2"(因为'1'的ASCII码小于'2'),如果生产环境中存在原始版本号为多位数的用户,会直接导致判断逻辑反转,触发功能失效。
2. 错误处理完全缺失
你的catch块是空实现,生产环境中一旦出现异常(设备未联网、App Store验证服务器故障、账号授权失败等),代码会直接跳过UserDefaults的设置步骤。而hasPurchased的默认值为false,这会直接导致符合条件的老用户无法获取权限。
3. UserDefaults初始化逻辑有漏洞
你仅在hasPurchased为false时调用检查函数,若首次调用因异常失败,后续不会再尝试重新检查,用户会一直处于未授权状态。
4. OriginalAppVersion格式异常
生产环境中originalAppVersion可能出现非预期格式:
- 部分老用户的原始版本号包含字母(如"1.0b"),拆分后无法转成有效数字
- 极端场景下(比如用户在应用转为免费后首次下载),
originalAppVersion可能为空字符串,此时versionComponents[0]会触发数组越界,被catch捕获后同样不会设置UserDefaults。
修复方案
1. 替换字符串比较为数字比较
将版本号的主版本号转为整数后再对比,彻底避免字符串比较的逻辑错误:
func checkOriginalVersion() async { guard #available(iOS 16, *) else { return } do { let shared = try await AppTransaction.shared guard case .verified(let appTransaction) = shared else { // 验证失败,默认视为新用户 UserDefaults.standard.set(false, forKey: "hasPurchased") return } let newBusinessModelMajorVersion = 2 let versionComponents = appTransaction.originalAppVersion.split(separator: ".") guard let originalMajorStr = versionComponents.first, let originalMajorVersion = Int(originalMajorStr) else { // 版本格式异常,默认视为新用户 UserDefaults.standard.set(false, forKey: "hasPurchased") return } print("Original version: ", originalMajorVersion) let hasPurchased = originalMajorVersion < newBusinessModelMajorVersion UserDefaults.standard.set(hasPurchased, forKey: "hasPurchased") } catch { // 捕获所有错误,记录日志并设置默认值 print("Failed to check original version: \(error.localizedDescription)") UserDefaults.standard.set(false, forKey: "hasPurchased") } }
2. 完善重试与错误处理逻辑
修改viewDidAppear中的调用逻辑,增加重试机制,避免单次异常导致永久失效:
private var checkAttempts = 0 private let maxCheckAttempts = 3 override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) Task { guard checkAttempts < maxCheckAttempts else { return } let hasPurchased = UserDefaults.standard.bool(forKey: "hasPurchased") if !hasPurchased { checkAttempts += 1 await checkOriginalVersion() // 若仍未获取到结果,延迟重试 if !UserDefaults.standard.bool(forKey: "hasPurchased") && checkAttempts < maxCheckAttempts { try? await Task.sleep(nanoseconds: 2 * 1_000_000_000) // 延迟2秒 await checkOriginalVersion() } } } }
3. 增加版本格式容错处理
在解析版本号时,增加对空值、非数字格式的判断,确保任何场景下都能设置hasPurchased的值。
额外建议
- 增加生产环境日志收集:在获取AppTransaction、版本判断等关键节点添加日志,方便后续排查问题
- 测试边缘场景:覆盖原始版本号为多位数、带字母、空字符串的情况,确保逻辑覆盖所有可能
内容的提问来源于stack exchange,提问作者Salvo89
相关产品推荐
相关产品推荐

