在没有钥匙串和UserDefaults的情况下实施应用内购买

每个开发人员最终面临的应用内购买实施步骤之一是选择合适的购买记录持久性策略,这将使应用重新启动后可以访问付费内容。

坚持购买的最明显方法是在UserDefaults中存储一些值,该值将指示某些内容是否已解锁。 Owen Brown和Pietro Rea在UserDefaults上的两个教程中展示了这种方法,其中UserDefaults用于存储布尔标志以指示非消耗性产品的购买状态,以及Date实例以保留订阅到期日期。 由于缺少数据完整性保护,因此通常会批评这种解决方案,因为UserDefaults存在的内容作为普通二进制plist存储在应用程序捆绑包的“首选项”文件夹中,因此用户可以使用iMazing,iFunBox或iExplorer等软件进行编辑由AndrésIbañez在他2014年的帖子中展示。

尽管这是事实,但我想提一下,自从iOS 8.3开始,Apple在文件系统访问中引入了严格的权限限制,从而消除了从非越狱设备上从外部访问应用程序内部文件的权限。 说到越狱,值得提醒的是,近几年来它的流行性一直在下降,以至于先驱者说越狱已经死了。 从个人观察,我可以说,为最新的iOS版本发布越狱需要花费更多的精力。 从iOS 10开始,黑客至少需要6个月的时间才能越狱,普通的iOS用户可以使用。 这就是为什么我认为应用程序用户的任何重要部分篡改应用程序文件的机会都非常低的原因。

尽管如此,使用Keychain代替UserDefaults并不需要花费很多精力,如Axel Kee在他的帖子中所示。 原理是相同的-存储类似“购买”的字符串,作为购买产品的标识符。 值得一提的是,由于iOS 11(以及iOS 10.3 Beta)在卸载应用后会删除钥匙串中与应用相关的所有记录,因此,如果您希望在应用安装之间坚持进行应用内购买,则钥匙串将无济于事不再。

但是,还有另一种方法可以检查用户是否购买了某些东西,而无需依赖UserDefaultsKeychain而是使用收据,该收据在每次购买时都会由OS自动更新。 即使为此目的使用收据的想法已在Apple的“应用内购买编程指南”中明确记录,但似乎这种方法在第三方教程中并未引起注意。 造成这种情况的一个原因可能是这种持久性策略仅适用于非消耗性产品和自动续订的订阅。 如果您正在实施消耗性或非续订性订阅,那么您将拥有钥匙串或iCloud。 应用收据使用的第二个障碍是其复杂的结构,需要大量的技巧才能读取必要的信息。 Bill Morefield的教程很好地展示了在没有第三方依赖的情况下在Swift中读取应用收据所需要的内容。 值得庆幸的是,来自Cocoanetics的人们创建了一个Kvitto库,使使用应用程序收据的工作变得轻松。

最近,我使用应用程序收据作为购买的永久记录,在名为电子工程师助手的应用程序中成功实现了非消耗性购买和自动续订。 InAppPurchaseManager读取收据的方法如下所示:

该方法的前4行检查是否存在IN_APP_PURCHASE环境变量,该变量可在使用模拟器时轻松模拟各种应用内购买。 您可以在Axel Kee的这篇文章中阅读有关使用环境变量模拟应用内购买的更多信息。

该方法的其余部分只是通过比较产品标识符来解析收据以找到相关条目,并使用switch语句内的元组以及三元运算来返回适当的购买状态。

另一种值得签出的方法是paymentQueue(_:updatedTransactions:)

在这种方法中,我仅将事件转发到BehaviorRelay (RxSwift库中的类),并在处理完所有交易后从应用收据中读取购买状态。

您可以在此要点中查看我的InAppPurchaseManager的完整代码。 多亏了RxSwiftKvitto和应用程序收据,实现了应用程序内购买的实现并没有造成太大麻烦。