提醒您确认应用内购买从未出现

时间:2019-03-25 16:20:51

标签: ios swift in-app-purchase

我有通常的存储套件队列观察者代码:

func paymentQueue(_ queue: SKPaymentQueue, 
    updatedTransactions transactions: [SKPaymentTransaction]) {
        for t in transactions {
            switch t.transactionState {
            case .purchasing, .deferred: break // do nothing
            case .purchased, .restored:
                let p = t.payment
                if p.productIdentifier == myProductID {
                    // ... set UserDefaults to signify purchase ...
                    // ... put up an alert thanking the user ...
                    queue.finishTransaction(t)
                }
            case .failed:
                queue.finishTransaction(t)
            }
        }
}

问题是在我有“向用户表示感谢的警报”的评论时该怎么办。看起来很简单:我正在创建一个UIAlertController并调用present来显示它。但是有时它不出现!

问题似乎与运行时发出自己的警报(“一切都准备好”)有关。我对此没有任何通知,所以我不知道这种情况正在发生。如何使UIAlertController呈现一定?

2 个答案:

答案 0 :(得分:2)

问题

关于应用内购买和StoreKit的时间和信息,您的手指已到了一个严重的问题。

这里出了问题,您(商店观察员)收到paymentQueue(_:updatedTransactions:),并且此时两件事同时发生,导致出现竞争状况:

  • 运行时显示“您已全部设置”警报。

  • 您尝试放置UIAlertController(并启动其他各种活动)。

正如您正确地说的那样,您不会收到任何事件来告诉您用户何时取消了运行时的“一切就绪”警报。那么如何在警报结束后的 处做些事情?

此外,如果您尝试在系统发出“所有人都准备好”警报的同时发出警报,您将无声地失败 – UIAlertController警报将永远不会出现。

解决方案

解决方案是识别出系统“您已设置好”警报启动时,您的应用已停用。我们可以检测到这一事实,并在再次激活您的应用程序时进行注册。 是用户取消“您已全部设置”警报的时刻!

因此,现在放上UIAlertController警报是安全的。

就像这样(使用我的delay实用程序,请参见https://stackoverflow.com/a/24318861/341994vc是我们要在其顶部显示警报的视图控制器):

let alert = UIAlertController( // ...
// ... configure your alert here ...
delay(0.1) { // important! otherwise there's a race and we can get the wrong answer
    if UIApplication.shared.applicationState == .active {
        vc.present(alert, animated:true)
    } else { // if we were deactivated, present only after we are reactivated
        var ob : NSObjectProtocol? = nil
        ob = NotificationCenter.default.addObserver(
            forName: UIApplication.didBecomeActiveNotification, 
            object: nil, queue: nil) { n in
                NotificationCenter.default.removeObserver(ob as Any)
                delay(0.1) { // can omit this delay, but looks nicer
                    vc.present(alert, animated:true)
                }
            }
    }
}

我已经反复测试了这种方法(尽管很难,因为测试存储套件中的东西效果很差),而且看起来是完全可靠的。

答案 1 :(得分:0)

仅供参考。我在我的应用程序中实现了类似的行为,但是我没有观察到Matt在问题中描述的问题。我的应用程序显示警告,以描述失败并在事务失败时建议采取的措施。下面是我的代码:

func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
    for transaction in transactions {
        switch transaction.transactionState {
        ...
        case .failed:
            let (reason, suggestion) = parsePaymentError(error: transaction.error)
            SKPaymentQueue.default().finishTransaction(transaction)
            if let purchaseFailureHandler = self.purchaseFailureHandler {
                DispatchQueue.main.async {
                    purchaseFailureHandler(reason, suggestion)
                }
            }
        }
    }
}

我用网络连接错误和用户取消错误多次测试了该代码。对我来说效果很好。