В моем живом приложении пользователи продолжают получать эту ошибку для расходных материалов. Это очень случайная ошибка, которая случается редко.
Эта покупка в приложении уже куплена. Будет восстановлено бесплатно.
В моем приложении я запретил пользователям нажимать кнопку «Купить сейчас», если процесс покупки приложения не завершен.
Я уже прочитал решение по следующим вопросам
Песочница пытается восстановить расходный IAP
Мой IAP не работает. Ошибки в funcquequeue
У меня SKPaymentQueue.default (). Add () в двух местах в моем коде, как показано ниже. Я также вызываю SKPaymentQueue.default (). FinishTransaction (транзакция) для каждой транзакции.
Может кто-нибудь сообщить мне, что еще мне нужно проверить, чтобы решить эту проблему?
open class IAPHelper: NSObject {
// Callback
var purchaseStatusBlock: ((IAPHandlerAlertType, String, NSData) -> Void)?
var purchaseFailed: ((SKPaymentTransaction) -> Void)?
private let productIdentifiers: Set<ProductIdentifier>
private var productsRequest: SKProductsRequest?
private var productsRequestCompletionHandler: ProductsRequestCompletionHandler?
public init(productIds: Set<ProductIdentifier>) {
productIdentifiers = productIds
super.init()
SKPaymentQueue.default().add(self) // #1
}
}
А второй
extension IAPHelper {
public func requestProducts(_ completionHandler: @escaping ProductsRequestCompletionHandler) {
productsRequest?.cancel()
productsRequestCompletionHandler = completionHandler
productsRequest = SKProductsRequest(productIdentifiers: productIdentifiers)
productsRequest!.delegate = self
productsRequest!.start()
}
public func buyProduct(_ product: SKProduct, vc: UIViewController) {
let viewController = vc as! PurchaseViewController
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment) // #2
}
}
Сделка
extension IAPHelper: SKPaymentTransactionObserver {
public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch (transaction.transactionState) {
case .purchased:
complete(transaction: transaction)
break
case .failed:
fail(transaction: transaction)
break
case .restored:
restore(transaction: transaction)
break
case .deferred:
break
case .purchasing:
break
}
}
}
private func complete(transaction: SKPaymentTransaction) {
deliverPurchaseNotificationFor(identifier: transaction.payment.productIdentifier)
let receiptURL = Bundle.main.appStoreReceiptURL
let receipt = NSData(contentsOf: receiptURL!)
if (receipt == nil) {
// No local receipt -- handle the error
let alert = UIAlertController(title: "Purchase Error", message: "No local receipt", preferredStyle: UIAlertController.Style.alert)
let okAction = UIAlertAction(title: "Ok", style: UIAlertAction.Style.default) { (action) in
}
alert.addAction(okAction)
return
}
// Callback
purchaseStatusBlock?(.purchased, transaction.payment.productIdentifier, receipt!)
SKPaymentQueue.default().finishTransaction(transaction)
}
private func fail(transaction: SKPaymentTransaction) {
if let transactionError = transaction.error as NSError?,
let localizedDescription = transaction.error?.localizedDescription,
transactionError.code != SKError.paymentCancelled.rawValue {
}
// Callback
purchaseFailed?(transaction)
SKPaymentQueue.default().finishTransaction(transaction)
}
private func restore(transaction: SKPaymentTransaction) {
guard let productIdentifier = transaction.original?.payment.productIdentifier else { return }
deliverPurchaseNotificationFor(identifier: productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction)
}
private func deliverPurchaseNotificationFor(identifier: String?) {
guard let identifier = identifier else { return }
// purchasedProductIdentifiers.insert(identifier)
// UserDefaults.standard.set(true, forKey: identifier)
NotificationCenter.default.post(name: .IAPHelperPurchaseNotification, object: identifier)
}
}