Interrupted Purchase not calling delegate after accepting Tamp;C(接受Tamp;C后未调用代理人中断采购)
问题描述
在实际设备上测试中断的购买,下面的项目#10未在同一会话中出现。仅当- 应用程序已重新启动
- 应用程序转到后台,然后返回前台
(对于#2,我假设这是因为当APP返回前台时,会再次调用
TransactionObserver
?)
这也谈到了类似的事情: Apple In App Purchase, Interrupted purchase in sandbox
https://developer.apple.com/documentation/storekit/original_api_for_in-app_purchase/testing_in-app_purchases_with_sandbox/testing_an_interrupted_purchase
推荐答案
我多周来一直在努力寻找解决此问题的方案。浏览了许多这样的帖子,也浏览了苹果论坛的帖子。
引用线程:
- https://developer.apple.com/forums/thread/674081
- https://developer.apple.com/forums/thread/671492
- https://developer.apple.com/forums/thread/685938
- Apple In App Purchase, Interrupted purchase in sandbox
根据Apple Docs,中断的交易应该在用户同意T&;C/继续中断的购买后发送失败然后购买(但实际上似乎没有发生-请参阅上面的链接帖子)
这就是我最终得到的当前解决方案。这不完全是理想的,但考虑到当时的情况,这是(我发现的)最好的。请参阅链接#3,其中用户观察到调用restoreCompletedTransactions()
实际上能够让事务观察器处理(已完成)中断的事务。通过这种方式,用户不必关闭(后台),然后再次打开应用程序。(请注意,我再次尝试了调用事务观察器的各种方法,但都不起作用)
这是我的解决方案。
private func purchaseFailed(_ transaction: SKPaymentTransaction) {
var failureReason: String = ""
var message: String = ""
var code = Int()
print("(FormatDisplay.datems(Date())) [IAP] Transcation FAILED/CANCELLED")
// https://stackoverflow.com/q/55641652/14414215
// https://adapty.io/blog/ios-in-app-purchases-part-5-list-of-skerror-codes-and-how-to-handle-them
if let skError = transaction.error as? SKError {
switch skError.code { // https://developer.apple.com/reference/storekit/skerror.code
case .unknown:
// https://developer.apple.com/forums/thread/674081
if let underlyingError = skError.userInfo["NSUnderlyingError"] as? NSError {
if underlyingError.code == 3038 {
print(">> General conditions have changed, don't display an error for the interrupted transaction")
failureReason = "ERROR: Unknown Error. Transaction Interrupted"
message = "Transaction Interrupted. Your Purchase is being processed. Please Check Back in 5mins."
code = underlyingError.code
} else {
failureReason = "Unknown or unexpected error occurred"
message = "Oops, something unknown occurred or the transaction was interrupted. If the interrupted purchase was successful, please check back in 5mins."
code = skError.code.rawValue
}
}
break
case .clientInvalid:
failureReason = "ERROR: Invalid Client"
message = "The purchase cannot be completed. Please, change your account or device."
code = skError.code.rawValue
break
case .paymentCancelled:
failureReason = "ERROR: User Cancelled Payment"
message = ""
code = skError.code.rawValue
break
case .paymentInvalid:
failureReason = "ERROR: Invalid Payment"
message = "Your purchase was declined. Please, check the payment details and make sure there are enough funds in your account."
code = skError.code.rawValue
break
case .paymentNotAllowed:
failureReason = "ERROR: Payment not allowed"
message = "The purchase is not available for the selected payment method. Please, make sure your payment method allows you to make online purchases."
code = skError.code.rawValue
break
case .storeProductNotAvailable:
failureReason = "ERROR: Store product not available"
message = "This product is not available in your region. Please, change the store and try again"
code = skError.code.rawValue
break
case .cloudServicePermissionDenied:
failureReason = "ERROR: Cloud service permission denied"
message = "Your purchase was declined"
code = skError.code.rawValue
break
case .cloudServiceNetworkConnectionFailed:
failureReason = "ERROR: Cloud service network connection failed"
message = "he purchase cannot be completed because your device is not connected to the Internet. Please, try again later with a stable internet connection"
code = skError.code.rawValue
break
case .cloudServiceRevoked:
failureReason = "ERROR: Cloud service revoked"
message = "Sorry, an error has occurred."
code = skError.code.rawValue
break
case .privacyAcknowledgementRequired:
failureReason = "ERROR: Privacy Acknowledgement Required"
message = "The purchase cannot be completed because you have not accepted the terms of use of the AppStore. Please, confirm your consent in the settings and then return to the purchase."
code = skError.code.rawValue
break
case .unauthorizedRequestData:
failureReason = "ERROR: Unauthorized Request Data"
message = "An error has occurred. Please, try again later."
code = skError.code.rawValue
break
case .invalidOfferIdentifier:
failureReason = "ERROR: Invalid offer identifier"
message = "The promotional offer is invalid or expired."
code = skError.code.rawValue
break
case .invalidSignature:
failureReason = "ERROR: Invalid Signature"
message = "Sorry, an error has occurred when applying the promo code. Please, try again later."
code = skError.code.rawValue
break
case .missingOfferParams:
failureReason = "ERROR: Missing offer params"
message = "Sorry, an error has occurred when applying the promo code. Please, try again later."
code = skError.code.rawValue
break
case .invalidOfferPrice:
failureReason = "ERROR: Invalid offer price"
message = "Sorry, your purchase cannot be completed. Please, try again later."
code = skError.code.rawValue
break
case .overlayCancelled:
failureReason = "ERROR: overlay Cancelled"
message = ""
code = skError.code.rawValue
break
case .overlayInvalidConfiguration:
failureReason = "ERROR: Overlay Invalid Configuration"
message = ""
code = skError.code.rawValue
break
case .overlayTimeout:
failureReason = "ERROR: Overlay Timeout"
message = ""
code = skError.code.rawValue
break
case .ineligibleForOffer:
failureReason = "ERROR: Ineligible Offer"
message = "Sorry, your purchase cannot be completed. Please, try again later."
code = skError.code.rawValue
break
case .unsupportedPlatform:
failureReason = "ERROR: Unsupported Platform"
message = "Sorry, unsupported Platform"
code = skError.code.rawValue
break
case .overlayPresentedInBackgroundScene:
failureReason = "ERROR: Overlay Presented In Background Scene"
message = ""
code = skError.code.rawValue
break
@unknown default:
failureReason = "ERROR: Unknown Default"
message = "Oops. Something Has Happened. Please try again later."
code = skError.code.rawValue
break
}
let title = "Error"
let errorMsg = failureReason
if message != "" {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
DisplayAlert.presentIapFailed(title: title, message: message, errMsg: errorMsg)
}
}
failureReason += " ErrorCode: (code)"
}
print("(FormatDisplay.datems(Date())) [IAP] (failureReason)")
print("(FormatDisplay.datems(Date())) [IAP] -- (transaction.error?.localizedDescription ?? "")")
print("(FormatDisplay.datems(Date())) [IAP] -- (transaction.error.debugDescription)")
print("(FormatDisplay.datems(Date())) [IAP] -- Calling SKPaymentQ.FinishTransaction")
SKPaymentQueue.default().finishTransaction(transaction)
purchaseCompletionHandler?(true)
}
这是用户按"确定"按钮后调用restoreCompletedPurchases()
的purchaseIapFailed()
的内容。
static func presentIapFailed(title: String, message: String, errMsg: String) {
let root = UIApplication.shared.keyWindow?.rootViewController
let alertController = UIAlertController(title: title,
message: message,
preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "OK", style: .cancel, handler: {( action: UIAlertAction ) in
print(" displayAlert - presentIapFailed: (errMsg) - OK Pressed")
// Call RestorePurchases to force replaying the transaction list.
Medals.store.restorePurchases()
}))
root?.present(alertController, animated: true, completion: nil)
}
交易恢复后,将继续触发后续代码进行购买,发送(购买完成/成功)通知,然后弹出警告消息,告知用户购买成功且已入账。
这篇关于接受T&;C后未调用代理人中断采购的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:接受T&;C后未调用代理人中断采购
基础教程推荐
- android 应用程序已发布,但在 google play 中找不到 2022-01-01
- 如何在 UIImageView 中异步加载图像? 2022-01-01
- 在 gmail 中为 ios 应用程序检索朋友的朋友 2022-01-01
- Android:对话框关闭而不调用关闭 2022-01-01
- 当从同一个组件调用时,两个 IBAction 触发的顺序是什么? 2022-01-01
- Kivy Buildozer 无法构建 apk,命令失败:./distribute.sh -m “kivy"d 2022-01-01
- UIWebView 委托方法 shouldStartLoadWithRequest:在 WKWebView 中等效? 2022-01-01
- 如何在没有IB的情况下将2个按钮添加到右侧的UINavigationbar? 2022-01-01
- 如何在 iPhone 上显示来自 API 的 HTML 文本? 2022-01-01
- 如何让对象对 Cocos2D 中的触摸做出反应? 2022-01-01