2017-05-04 13 views
2

私は最初のアプリ内購入を行っています。新しいトランザクションを作成する代わりに消耗品が復元されているという奇妙な動作があります。アプリ内購入消耗品が自動的に復元される

私はエレガントなアプローチを見つけたtuto https://www.raywenderlich.com/122144/in-app-purchase-tutorial

を追ってきました。私は一度購入することができるよ

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) 
    } 
} 

、第二、それが自動的に復元されています:これはアプリ内購入はすでに買ってきた

は、ここに私のStoreKitヘルパーです。 を無料で復元します。

このメッセージが表示されたら、IAPHelperメソッドが呼び出されません。でも、アプリをアンインストールする

[1]: https://i.stack.imgur.com/sPy

まだ復元されて購入し:それを示す

私のiTunesは消耗品です。

私は最初のテストとしてAppleのバグのように見えますが、私はこのメッセージがなくても2..3回購入することができます。

バグでない場合はどうすればこのような状況を防ぐことができますか?この愚かな状況で立ち往生したものについては

答えて

3

、ここでいくつかの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) 
    } 

テンポラリボタンに配置して、1回のタップでテスト中にすべてのトランザクションをクリアすることができます。

少なくとも、今日は私の人生を救った。

+0

ありがとうございました非常に –

+0

これは非常に役に立ちました、ありがとう!..同じチュートリアルで同じ問題.. –

関連する問題