我们的应用程序是在 Unity 中开发的,并针对 iOS 和 Android 构建。对于 iOS 应用内购买,我们使用 Prime31 StoreKit 插件。我们现在使用 5/24/14 版本的插件,但是当我们升级到 3/14/14 版本时,第一次注意到这个问题。
执行某些操作(例如 restoreCompletedTransactions())时会发生该行为。它首先会说“paymentQueueRestoreCompletedTransactionsFinished”并显示有关购买的信息,包括其交易状态。
paymentQueueRestoreCompletedTransactionsFinished
transactionUpdatedEvent: <StoreKitTransaction> ID: test_monthly, quantity: 1, transactionIdentifier: 1000000113168263, transactionState: Restored
productPurchaseAwaitingConfirmationEvent: <StoreKitTransaction> ID: test_monthly, quantity: 1, transactionIdentifier: 1000000113168263, transactionState: Restored
然后它尝试完成所有待处理的事务。如果有任何卡住的事务(事务在finishTransaction: 被调用后返回),控制台将报告它正在告诉事务完成,但会说0 已经更新,除了第一次,它会说所有其中已更新:
transactions that have been updated by the payment queue: 0
transactions that are currently in the payment queue (and possibly stuck there): 59
finishing transaction: 1000000113168314 : test_monthly
StoreKit: transaction completed: <SKPaymentTransaction: 0x190d49f0>
finalizing and asking the payment queue to finish transaction: <SKPaymentTransaction: 0x190d49f0>
finishing transaction: 1000000113168318 : test_monthly
....
对于 59 笔交易中的每笔交易,它将显示这三行(“完成交易”、“交易完成”、“完成...”),一旦完成所有 59 笔交易,它将重复整个区块,从“productPurchaseAwaitingConfirmationEvent”(具有不同的交易 id)到第 59 笔交易的最后一次“敲定”,总共 59 次。因此,如果有 n 个事务,它将创建 n^2 个日志消息。当我按下该场景中的其他按钮时,例如“获取保存的交易”和“完成所有待处理的交易”,它告诉我有 0 个交易需要保存或完成。
之后,如果它循环遍历所有事务足够多次,它会将所有事务更新为已恢复,将这些行打印 n^2 次:
purchaseSuccessfulEvent: <StoreKitTransaction> ID: test_monthly, quantity: 1, transactionIdentifier: 1000000113168959, transactionState: Restored
....
最后,它将从 paymentQueue 中删除每笔交易,仅打印这些行 n 次(但下次恢复时会重新添加它们):
paymentQueue:removedTransaction: <SKPaymentTransaction: 0x1961d070>
...
以下是此行为的问题:
- 循环处理这些事务需要很长时间,并且在发生这种情况时应用程序会挂起。
- 如果 n 足够大(大约超过 25 个事务),应用程序会在循环足够多的时间后耗尽内存并崩溃。当它循环卡在支付队列中的交易时,它会在该部分崩溃。
- 现在每个测试帐户都有一个有限的生命周期。每次使用帐户时,许多事务都可能会卡住,最终帐户可能会变得不可用,因为如果 n 足够大,遍历卡住事务的存储操作将始终崩溃。
该行为发生在 Prime31 插件代码中,并且可以在插件提供的演示场景中重现。
- 创建一个新项目并导入 Prime31 StoreKit 插件包。
- 将您的产品名称放在 StoreKitGUIManager.cs 中的“请求产品数据”按钮部分下。
- 创建一个沙盒商店并用产品填充它(我们有非消耗品和每月订阅以及一周的免费试用期)。
- 设置项目的包 ID 以匹配沙箱的包 ID。
- 将项目的版本号设置为较高的数字(在我们的例子中,它大约是 1200 或更高。我不知道为什么,但我注意到如果版本号设置为 1200 或更高,它会循环更多事务(危险, 可能会崩溃)并且对于 1200 以下的版本(更安全)循环的数量要少得多。我认为这与我们开始使用免费试用的版本一致。)
- 构建到 iOS。
- 创建一个测试用户并让它与您的商店执行许多交易,这应该会在支付队列中累积一些卡住的交易。
- 单击恢复按钮并输入该测试帐户的登录名和密码并观看控制台。
以下是我的问题:
- 这种行为是只发生在沙盒中,还是在实时生产中也会发生?无论哪种方式,我们如何验证它不会在现场制作中发生,或者我们可能做的任何修复都不会破坏现场制作?
- 我们如何解决此问题或创建一种解决方法,使我们能够在不遇到问题的情况下正确恢复事务或其他功能?
- 如果我们可以做到(2),我们可以使用该应用程序并恢复旧帐户的功能,还是我们不再能够使用它们并且必须创建以前没有任何交易的新帐户?