我有通常的商店套件队列观察代码:
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出现?
您已经开始关注应用内购买和StoreKit的严重时间和信息问题。
这里出了什么问题是你(商店观察员)收到paymentQueue(_:updatedTransactions:)
,那时两件事同时发生,导致竞争条件:
正如你正确地说的那样,当用户解除运行时的“你已全部设置”警报时,你不会告诉你任何事件。那么在警报结束后你怎么办?
此外,如果您尝试在系统提出“您已全部设置”警报的同时发出警报,您将无声地失败 - 您的UIAlertController警报将永远不会出现。
解决方案是识别当系统的“你已全部设置”警报启动时,您的应用程序将被停用。我们可以检测到这一事实并注册,以便在您的应用再次激活时收到通知。那是用户解除“你已全部设置”警报的那一刻!
因此,您现在可以安全地提出UIAlertController警报。
像这样(使用我的delay
实用程序,请参阅https://stackoverflow.com/a/24318861/341994; vc
是视图控制器,我们将在上面显示警报):
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)
}
}
}
}
我已经反复测试过这种方法(虽然很困难,因为测试商店套件的工作非常糟糕),而且看起来非常可靠。