我有通常的存储套件队列观察者代码:
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呈现一定?
答案 0 :(得分:2)
关于应用内购买和StoreKit的时间和信息,您的手指已到了一个严重的问题。
这里出了问题,您(商店观察员)收到paymentQueue(_:updatedTransactions:)
,并且此时两件事同时发生,导致出现竞争状况:
运行时显示“您已全部设置”警报。
您尝试放置UIAlertController(并启动其他各种活动)。
正如您正确地说的那样,您不会收到任何事件来告诉您用户何时取消了运行时的“一切就绪”警报。那么如何在警报结束后的 处做些事情?
此外,如果您尝试在系统发出“所有人都准备好”警报的同时发出警报,您将无声地失败 – 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)
}
}
}
}
我已经反复测试了这种方法(尽管很难,因为测试存储套件中的东西效果很差),而且看起来是完全可靠的。
答案 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)
}
}
}
}
}
我用网络连接错误和用户取消错误多次测试了该代码。对我来说效果很好。