2017-07-06 2 views
0

J'écris ma première application iOS dans Swift et j'ai eu quelques problèmes avec la fonctionnalité d'achats in-app. Je pense que la fonction d'achat fonctionne, mais je ne suis pas sûr de la fonctionnalité de restauration. Je fournis juste un produit qui est une version «pro» de l'application. Ceci est stocké dans l'emplacement par défaut de l'utilisateur et il débloque les fonctionnalités supplémentaires. Ma fonction de restauration est source de confusion, quelqu'un peut-il y jeter un coup d'œil et me dire où je devrais définir ma valeur par défaut? Devrait-il être dans la fonction paymentQueueRestoreCompletedTransactionsFinished ou la fonction paymentQueue?Mon code d'achat de restauration est-il correct et si oui, où dois-je mettre l'action pour changer les valeurs par défaut de l'utilisateur?

import UIKit 
import StoreKit 

class StoreController: UIViewController, SKProductsRequestDelegate, 
SKPaymentTransactionObserver { 

// Properties 
var defaults = UserDefaults.standard 
var list = [SKProduct]() 
var p = SKProduct() 

// Methods 
override func viewDidLoad() { 
    super.viewDidLoad() 
    // Get list of products for the store 
    localTitle.isEnabled = false 
    localDescription.isEnabled = false 
    price.isEnabled = false 
    buy.isEnabled = false 
    restore.isEnabled = false 
    getProducts() 
} 

// Outlets 
@IBOutlet weak var localTitle: UILabel! 
@IBOutlet weak var localDescription: UILabel! 
@IBOutlet weak var price: UILabel! 
@IBOutlet weak var buy: UIButton! 
@IBOutlet weak var restore: UIButton! 

// Actions 
@IBAction func buy(_ sender: UIButton) { 
    print("buy pressed") 
    for product in list { 
     let prodID = product.productIdentifier 
     if(prodID == "com.squidgylabs.pro") { 
      p = product 
      buyProduct() 
     } 
    } 
} 

@IBAction func restore(_ sender: UIButton) { 
    print("restore pressed") 
    SKPaymentQueue.default().add(self) 
    SKPaymentQueue.default().restoreCompletedTransactions() 
} 

// Methods 
func getProducts() { 
    print("starting getproducts function") 
    if(SKPaymentQueue.canMakePayments()) { 
     print("IAP is enabled, loading") 
     let productID: NSSet = NSSet(objects: "com.squidgylabs.pro") 
     let request: SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>) 
     request.delegate = self 
     request.start() 
    } else { 
     print("please enable IAPS") 
    } 
} 


func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) { 
    print("starting productsrequest") 
    let myProduct = response.products 
    for product in myProduct { 
     print("product added") 
     list.append(product) 
    } 
    localTitle.isEnabled = true 
    localDescription.isEnabled = true 
    restore.isEnabled = true 
    buy.isEnabled = true 
    price.isEnabled = true 

    // Update labels 
    localTitle.text = list[0].localizedTitle 
    localDescription.text = list[0].localizedDescription 
    // Format the price and display 
    let formatter = NumberFormatter() 
    formatter.locale = Locale.current 
    formatter.numberStyle = .currency 
    if let formattedPrice = formatter.string(from: list[0].price){ 
     price.text = formattedPrice 
    } 
} 


func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) { 
    print("starting paymentQueueResoreCompletedTransactionsFnished") 
    for transaction in queue.transactions { 
     let t: SKPaymentTransaction = transaction 
     let prodID = t.payment.productIdentifier as String 

     switch prodID { 
     case "com.squidgylabs.pro": 
      print("case is correct product ID in payment...finished") 

     default: 
      print("IAP not found") 
     } 
    } 
} 

func buyProduct() { 
    print("buy " + p.productIdentifier) 
    let pay = SKPayment(product: p) 
    SKPaymentQueue.default().add(self) 
    SKPaymentQueue.default().add(pay as SKPayment) 
} 

func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { 
    print("entering func paymentQueue") 

    for transaction: AnyObject in transactions { 
     let trans = transaction as! SKPaymentTransaction 

     switch trans.transactionState { 
     case .purchased: 
      print("buy ok, unlock IAP HERE") 

      print(p.productIdentifier) 
      let prodID = p.productIdentifier 
      switch prodID { 
      case "com.squidgylabs.pro": 
       print("setting pro in defaults...") 
       defaults.set(true, forKey: "pro") 
      default: 
       print("IAP not found") 
      } 
      queue.finishTransaction(trans) 
      break 
     case .failed: 
      print("buy error") 
      queue.finishTransaction(trans) 
      break 
     case .restored: 
      print("case .restored in paymentQ") 
      SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction) 
      queue.finishTransaction(trans) 
      break 
     default: 
      print("Default") 
      break 
     } 
    } 
} 
} 
+0

Je ne sais pas que cela importe. Votre code est à peu près le même que le mien. Je (re) définit les UserDefaults dans 'paymentQueueRestoreCompletedTransactionsFinished (_ queue: SKPaymentQueue)'. J'effectue cependant 'finishTransaction' dans' paymentQueue (_ queue: SKPaymentQueue, transactions de transactions mises à jour: [SKPaymentTransaction]) '. ** Encore une fois, je ne suis pas sûr que cela compte. J'espère que quelqu'un me corrigera si c'est le cas! ** – dfd

Répondre

0

Cela peut être fait comme ceci. Vous pouvez envisager d'utiliser une autre classe pour l'accès StoreKit au lieu d'un UIViewController. Car

Votre application doit toujours s'attendre à être informée des transactions terminées.

https://developer.apple.com/documentation/storekit/skpaymentqueue/1506042-add

Et Voir les contrôleurs aller et venir. Il pourrait même planter l'application si vous ne supprimez pas l'objet que vous avez ajouté en tant qu'observateur à SKPaymentQueue.

J'ai simple, bibliothèque StoreKit bien documenté sur GitHub que vous pouvez consulter pour obtenir l'idée - https://github.com/suvov/VSStoreKit

+0

Merci pour votre suggestion. Je suis d'accord qu'il est préférable d'avoir la fonctionnalité du kit de magasin dans sa propre classe. Le problème que je rencontrais était de savoir comment revenir au contrôleur de vue. Par exemple. Comment dire au contrôleur de vue: hé nous avons le prix maintenant pour votre bouton d'achat à afficher. Parce que je ne sais pas quel est le nom de l'objet pour le UIViewController lors de l'exécution. Comment dois-je faire cela? J'ai en quelque sorte besoin du contrôleur de vue pour écouter les changements dans l'objet de kit de magasin puis me mettre à jour en conséquence. – laurie

+1

Vous pouvez utiliser le délégué https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html ou NSNotification https://developer.apple.com/documentation/foundation/nsnotification pour "Parlez" à votre ViewController à partir d'un objet qui gère les achats. Ou une fonction de rappel https://medium.cobeisfresh.com/why-you-shouldn-t-use-delegates-in-swift-7ef808a7f16b –