macOS平台StoreKit2的AppTransaction.shared验证异常问题咨询
问题:StoreKit2的AppTransaction验证无法区分盗版应用?
之前用Receigen生成的收据验证代码,因为苹果弃用exit code 173,换成了StoreKit2方案,参考官方文档写了以下代码:
Swift 实现
@objc class ValidateReceipt: NSObject { @objc func validate() async -> Bool { do { let verificationResult = try await AppTransaction.shared switch verificationResult { case .verified(_ /*let appTransaction*/): // StoreKit verified that the user purchased this app and // the properties in the AppTransaction instance return true; default: // The app transaction didn't pass StoreKit's verification return false; } } catch { // Handle errors return false; } } }
Objective-C 调用代码
ValidateReceipt *validateReceipt = [[ValidateReceipt alloc] init]; [validateReceipt validateWithCompletionHandler:^(BOOL result) { if (result) { // Successful app purchase validation } else { // App purchase validation failure } }];
但测试发现,不管切换App Store账号、退出登录,甚至直接运行全新Release包,.verified分支都会执行。我需要验证用户用的是正规购买的应用(而非盗版),现在对这个方法的有效性存疑,想知道它的实际作用,能不能满足我的需求?
分析与解答
1. AppTransaction.shared的实际作用
AppTransaction.shared核心是验证应用安装的签名合法性,而非用户的购买行为:
- 它仅检查应用是否通过合法渠道(App Store、TestFlight或开发者证书)签名分发,不关联当前登录Apple ID的购买记录。
- 盗版应用若绕过苹果签名校验(比如越狱重签名、篡改签名),也可能让该方法返回
.verified——因为它只校验本地签名有效性,不做联网购买记录验证。
2. 测试场景全返回.verified的原因
- 切换/退出Apple ID:
AppTransaction不绑定当前登录账号,只要应用本身签名合法就会通过校验。 - 全新Release包:如果你用自己的开发者证书打包,签名本身是合法状态,自然触发
.verified分支,和是否在App Store购买无关。
3. 如何实现盗版应用验证需求
要区分用户是否实际购买过应用,需要结合以下手段:
- 联网收据验证:将应用收据提交至苹果App Store验证服务器,远程确认购买记录的真实性。StoreKit2中可结合
Transaction.currentEntitlements实现,或保留传统的收据上传校验逻辑。 - 本地签名与包完整性校验:检查应用签名、包内容是否被篡改,防止重签名的盗版应用通过校验。
- 服务器端凭证关联:在自有服务器记录用户购买凭证,验证时比对设备信息与购买记录的绑定关系。
4. 注意事项
- 苹果不鼓励过度的本地盗版校验,过度逻辑可能影响正常用户体验(比如网络不佳时的误判)。
- 关键校验代码需做混淆或加密,避免被逆向破解。
内容的提问来源于stack exchange,提问作者KT_
相关产品推荐
相关产品推荐

