iOS IAP 测试,提示你物品已经买过了

若是在开发iOS内购的时候,你必定会遇到购买Consumable类物品的需求,好比购买游戏币就是一个很经典的使用场景。最近在测试购买这种消耗品的时候,发现遇到了一个很是奇怪的问题,当你重复购买游戏币的时候,系统提示html

This In-App Purchase has already been bought. It will be restored for free.

该物品已经购买过了,直接恢复便可。git

当你在完成一笔交易的时候,调用StoreKit.SKPaymentQueuefinishTransaction就能够将这个交易标记为已购买,以后应该会没有障碍的继续购买Consumable类的商品。github

那么如今这是什么状况的?让人很是费解。
幸亏发现了这个和我遇到同样问题的开发者,This In-App Purchase Has Aready Been Boughtswift

他也提到,app

Apple has designed the payment queue in such a way as to enable apps to fulfill a purchase before completing - with finishTransaction being the indication that fulfillment is complete. In the case that a failure occurs during fulfillment, the app can recover when SKPaymentQueue calls the app’s observer again.

This is all good and fine - except many developers have encountered a situation where this process breaks down. Their SKPaymentTransactionObserver is never called again, and the user is presented with the dreaded “already bought” dialog and no apparent way to fix the problem.测试

SKPaymentTransactionObserver一直没有被调用,而且显示已经购买的对话框。this

A library (in my case Firebase analytics) is adding its own SKPaymentTransactionObserver before your app adds its own observer. As a result, SKPaymentQueue is calling that observer first, and by the time your observer is added, as far as the payment queue is concerned it has already delivered the notification and there’s nothing left to do.

他帮我找到了缘由——第三方软件(和我同样就是Firebase的问题)。rest

SKPaymentTransactionObserver没有被调用,实际上是由于已经有一个了Observer存在了。code

解决方案也比较简单,就是在初始化第三方软件以前,来添加咱们的Queue。server

由于我在工程里引用了第三方的支付库jinSasaki/InAppPurchase因此下面就用这个为例,简单的写一下解决方案。

class AppDelegate: UIResponder, UIApplicationDelegate {
    // 初始化InAppPurchase
    let iap = InAppPurchase.default
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // 首先在这边加入Transaction Observer
        iap.addTransactionObserver()
    
        // 而后再开启Firebase的设置
        FirebaseApp.configure()
        return true
    }
}

而后就大功告成了。

相关文章
相关标签/搜索