应用内购买消耗品自动恢复
Posted
技术标签:
【中文标题】应用内购买消耗品自动恢复【英文标题】:In-App Purchase consumable being restored automatically 【发布时间】:2017-05-04 17:28:39 【问题描述】:我正在做我的第一次应用内购买,一个奇怪的行为是正在恢复消耗品而不是创建新交易。
我已经跟着tutohttps://www.raywenderlich.com/122144/in-app-purchase-tutorial
我发现了一种优雅的方法。
这是我的 StoreKit 助手:
import StoreKit
public typealias ProductIdentifier = String
public typealias ProductsRequestCompletionHandler = (_ success: Bool, _ products: [SKProduct]?) -> ()
open class IAPHelper : NSObject
fileprivate let productIdentifiers: Set<ProductIdentifier>
fileprivate var purchasedProductIdentifiers: Set<ProductIdentifier> = Set()
fileprivate var productsRequest: SKProductsRequest?
fileprivate var productsRequestCompletionHandler: ProductsRequestCompletionHandler?
static let IAPHelperPurchaseNotification = "IAPHelperPurchaseNotification"
public init(productIds: Set<ProductIdentifier>)
productIdentifiers = productIds
super.init()
SKPaymentQueue.default().add(self)
// MARK: - StoreKit API
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)
print("Buying \(product.productIdentifier)...")
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
public func isProductPurchased(_ productIdentifier: ProductIdentifier) -> Bool
return purchasedProductIdentifiers.contains(productIdentifier)
public class func canMakePayments() -> Bool
return SKPaymentQueue.canMakePayments()
public func restorePurchases()
SKPaymentQueue.default().restoreCompletedTransactions()
// MARK: - SKProductsRequestDelegate
extension IAPHelper: SKProductsRequestDelegate
public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse)
print("Loaded list of products...")
let products = response.products
productsRequestCompletionHandler?(true, products)
clearRequestAndHandler()
for p in products
print("Found product: \(p.productIdentifier) \(p.localizedTitle) \(p.price.floatValue)")
public func request(_ request: SKRequest, didFailWithError error: Error)
print("Failed to load list of products.")
print("Error: \(error.localizedDescription)")
productsRequestCompletionHandler?(false, nil)
clearRequestAndHandler()
private func clearRequestAndHandler()
productsRequest = nil
productsRequestCompletionHandler = nil
// MARK: - SKPaymentTransactionObserver
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)
print("complete...")
validateReceipt()
deliverPurchaseNotificationFor(identifier: transaction.payment.productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction)
private func restore(transaction: SKPaymentTransaction)
guard let productIdentifier = transaction.original?.payment.productIdentifier else return
print("restore... \(productIdentifier)")
deliverPurchaseNotificationFor(identifier: productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction)
private func fail(transaction: SKPaymentTransaction)
print("fail...")
if let transactionError = transaction.error as? NSError
if transactionError.code != SKError.paymentCancelled.rawValue
print("Transaction Error: \(transaction.error?.localizedDescription)")
SKPaymentQueue.default().finishTransaction(transaction)
private func deliverPurchaseNotificationFor(identifier: String?)
guard let identifier = identifier else return
purchasedProductIdentifiers.insert(identifier)
UserDefaults.standard.set(true, forKey: identifier)
UserDefaults.standard.synchronize()
NotificationCenter.default.post(name: NSNotification.Name(rawValue: IAPHelper.IAPHelperPurchaseNotification), object: identifier)
我可以买一次,第二次自动恢复:
此应用内购买已被购买。它将恢复为 免费
当我收到此消息时,没有调用任何 IAPHelper 方法。
我的 iTunes 显示它是消耗品:
即使卸载购买的应用程序仍在恢复中。
在我的第一次测试中,它看起来确实像一个 Apple 错误,我可以在没有此消息的情况下购买 2..3 次。
如果不是bug,如何防止这种情况发生?
【问题讨论】:
【参考方案1】:对于那些陷入这种愚蠢情况的人,这里有一些 WA 和解决方案:
queue.finishTransaction(transaction)
重要提示:在您的paymentQueue
方法中完成事务:
public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction])
for transaction in transactions
switch (transaction.transactionState)
case .purchased:
complete(transaction: transaction)
queue.finishTransaction(transaction)
break
case .failed:
fail(transaction: transaction)
queue.finishTransaction(transaction)
break
case .restored:
restore(transaction: transaction)
queue.finishTransaction(transaction)
break
case .deferred:
break
case .purchasing:
break
这样可以避免这种情况。
如果您已经卡在它上面,这里是解决方法,仅用于测试目的!
for transaction in SKPaymentQueue.default().transactions
print(transaction)
SKPaymentQueue.default().finishTransaction(transaction)
您可以将它放在一个临时按钮上,并在测试时一键清除所有交易。
至少它今天救了我的命。
【讨论】:
为我工作.. 非常感谢 为我工作。谢谢。 感谢您为我节省了时间! 如何使用 StoreKit 2 做到这一点?以上是关于应用内购买消耗品自动恢复的主要内容,如果未能解决你的问题,请参考以下文章