2017-05-04 4 views
2

Ich mache meinen ersten In-App-Kauf und ein merkwürdiges Verhalten ist, dass ein Verbrauchsmaterial wiederhergestellt wird, anstatt eine neue Transaktion zu erstellen.In-App Kauf-Verbrauchsmaterial wird automatisch wiederhergestellt

Ich habe die tuto https://www.raywenderlich.com/122144/in-app-purchase-tutorial

gefolgt Was ich einen eleganten Ansatz gefunden.

hier ist mein StoreKit Helfer:

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

ich in der Lage bin einmal zu kaufen, zweite automatisch wieder hergestellt wird:

Dieses In-App-Kauf wurde bereits gekauft. Es wird wiederhergestellt für frei

Wenn ich diese Nachricht erhalte, wird keiner der IAPHelper-Methoden aufgerufen.

Mein iTunes es zeigt, ist ein Verbrauchs:

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

Auch die App die noch restauriert gekauft zu deinstallieren.

Es sieht wirklich wie ein Apple-Bug aus, als meine ersten Tests konnte ich 2,3 mal ohne diese Nachricht kaufen.

Wenn es kein Fehler ist, wie kann ich diese Situation verhindern?

Antwort

3

die in dieser dummen Situation stecken, sind hier einige WA und Lösung:

queue.finishTransaction(transaction) 

WICHTIG: Beenden Sie die Transaktion in Ihrem paymentQueue Methode:

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

Dies wird die Situation zu vermeiden.

Wenn Sie schon fest sind, hier ist die Arbeit um, nur für Testzwecke!

Sie können es auf eine temporäre Schaltfläche legen und alle Transaktionen löschen, während Sie mit einem Tippen testen.

Zumindest hat es heute mein Leben gerettet.

+0

Arbeitete für mich .. Vielen Dank –

+0

Dies war sehr hilfreich, danke! .. Das gleiche Problem mit dem gleichen Tutorial .. –

Verwandte Themen