永远不会出现确认应用内购买的警报
alert confirming in-app purchase never appears
我有常用的商店工具包队列观察器代码:
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)
}
}
}
问题是在我有评论 "put up an alert thanking the user" 的地方该怎么办。这看起来很简单:我正在创建一个 UIAlertController 并调用 present
来显示它。但有时不出现!
问题似乎与运行时发出自己的警报 ("You're all set") 有关。我没有收到任何通知,所以我不知道这正在发生。我怎样才能确定显示我的 UIAlertController?
问题
您指出了有关应用内购买和 StoreKit 的时间和信息的严重问题。
这里出了什么问题是你(商店观察员)收到 paymentQueue(_:updatedTransactions:)
并且在那一刻 两件事同时发生 ,导致竞争条件:
运行时发出“准备就绪”警报。
您尝试放置您的 UIAlertController(并启动各种其他活动)。
正如您所说的那样,您不会收到 任何 事件来告诉您用户何时关闭了运行时的“一切就绪”警报。那么在警报结束后,你如何做一些事情呢?
此外,如果您尝试在系统发出“您已准备就绪”警报的同时发出警报,您将无声无息地失败 —您的 UIAlertController 警报将永远不会出现。
解决方案
解决方案是识别当系统的“您已准备就绪”警报启动时,您的应用已停用。我们可以检测到这一事实并注册以在您的应用再次激活时收到通知。并且那是用户关闭“您”的时刻“一切就绪”警报!
因此,现在您可以安全地发出 UIAlertController 警报。
像这样(使用我的 delay
实用程序,参见 ;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)
}
}
}
}
我已经反复测试过这种方法(虽然很困难,因为测试商店套件的东西效果很差),而且它似乎非常可靠。
仅供参考。我在我的应用程序中实现了类似的行为,但我没有观察到马特在问题中描述的问题。当交易失败时,我的应用程序会显示一个警报来描述失败和建议的操作。下面是我的代码:
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)
}
}
}
}
}
我针对网络连接错误和用户取消错误对代码进行了多次测试。它非常适合我。
我有常用的商店工具包队列观察器代码:
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)
}
}
}
问题是在我有评论 "put up an alert thanking the user" 的地方该怎么办。这看起来很简单:我正在创建一个 UIAlertController 并调用 present
来显示它。但有时不出现!
问题似乎与运行时发出自己的警报 ("You're all set") 有关。我没有收到任何通知,所以我不知道这正在发生。我怎样才能确定显示我的 UIAlertController?
问题
您指出了有关应用内购买和 StoreKit 的时间和信息的严重问题。
这里出了什么问题是你(商店观察员)收到 paymentQueue(_:updatedTransactions:)
并且在那一刻 两件事同时发生 ,导致竞争条件:
运行时发出“准备就绪”警报。
您尝试放置您的 UIAlertController(并启动各种其他活动)。
正如您所说的那样,您不会收到 任何 事件来告诉您用户何时关闭了运行时的“一切就绪”警报。那么在警报结束后,你如何做一些事情呢?
此外,如果您尝试在系统发出“您已准备就绪”警报的同时发出警报,您将无声无息地失败 —您的 UIAlertController 警报将永远不会出现。
解决方案
解决方案是识别当系统的“您已准备就绪”警报启动时,您的应用已停用。我们可以检测到这一事实并注册以在您的应用再次激活时收到通知。并且那是用户关闭“您”的时刻“一切就绪”警报!
因此,现在您可以安全地发出 UIAlertController 警报。
像这样(使用我的 delay
实用程序,参见 ;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)
}
}
}
}
我已经反复测试过这种方法(虽然很困难,因为测试商店套件的东西效果很差),而且它似乎非常可靠。
仅供参考。我在我的应用程序中实现了类似的行为,但我没有观察到马特在问题中描述的问题。当交易失败时,我的应用程序会显示一个警报来描述失败和建议的操作。下面是我的代码:
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)
}
}
}
}
}
我针对网络连接错误和用户取消错误对代码进行了多次测试。它非常适合我。