2017-11-24 8 views
0

私は現在、SwiftベースのiOSアプリでアプリ内購入を提供しています。私は重い持ち上げを行うStoreクラスを持っており、ストアのビューを管理するStoreViewControllerを持っています。現在、購入ボタンを押すと、店舗にはかなりの時間がかかります(最小10秒以上)。つまり、ボタンを繰り返し押すか、購入をあきらめることができます。私はそれを変更して、ボタンを押すとボタンを無効にし、購入プロセスが続行される準備が整うまで、スピナーなどを表示するように変更したいと思います。私がすでに持っているコードでは、これを行うための好ましい方法/場所は何でしょうか?App Storeがアプリ内購入のために応答するのを待っている間に 'ローディングスピナー'などを実行するにはどうすればよいですか?

Storeクラス:

import Foundation 
import StoreKit 

protocol ClassStoreDelegate: class { 
    func storeUpdateReceived(store: Store) 
} 

class Store: NSObject, SKProductsRequestDelegate, SKPaymentTransactionObserver { 
    // Properties 
    weak var delegate: ClassStoreDelegate? 
    var list = [SKProduct]() 
    var p = SKProduct() 
    var localPrice: String? 
    var presentAlert = false 
    var alertTitle = "Alert" 
    var alertMessage = "Unfortunately something went wrong" 
    var purchaseSuccess = false 

    // Methods 
    // Calling the delegate method 
    func storeUpdate() { 
     delegate?.storeUpdateReceived(store: self) 
    } 

    // Buy the product 
    func buy(productId: String) { 
     var foundProduct = false 
     var counter = 0 
     while counter < list.count && !foundProduct { 
      if (list[counter].productIdentifier == productId){ 
       p = list[counter] 
       foundProduct = true 
      } 
      counter = counter + 1 
     } 
     buyProduct() 
    } 

    func buyProduct() { 
     let pay = SKPayment(product: p) 
     SKPaymentQueue.default().add(self) 
     SKPaymentQueue.default().add(pay as SKPayment) 
    } 

    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { 
     for transaction: AnyObject in transactions { 
      let trans = transaction as! SKPaymentTransaction 
      switch trans.transactionState { 
      case .purchased: 
       let prodID = p.productIdentifier 
       switch prodID { 
       case "volume2": 
        VolumeTableViewController.saveUnlocked(volumeUnlocked: 1) 
        purchaseSuccess = true 
        delegate?.storeUpdateReceived(store: self) 
       case "volume3": 
        VolumeTableViewController.saveUnlocked(volumeUnlocked: 2) 
        purchaseSuccess = true 
        delegate?.storeUpdateReceived(store: self) 
       case "volume4": 
        VolumeTableViewController.saveUnlocked(volumeUnlocked: 3) 
        purchaseSuccess = true 
        delegate?.storeUpdateReceived(store: self) 
       case "volume5": 
        VolumeTableViewController.saveUnlocked(volumeUnlocked: 4) 
        purchaseSuccess = true 
        delegate?.storeUpdateReceived(store: self) 
       case "all": 
        for i in 0...VolumeTableViewController.unlocked.count-1 { 
         VolumeTableViewController.saveUnlocked(volumeUnlocked: i) 
        } 
        purchaseSuccess = true 
        delegate?.storeUpdateReceived(store: self) 
       default: 
        delegate?.storeUpdateReceived(store: self) 
       } 
       queue.finishTransaction(trans) 
       break 
      case .failed: 
       alertTitle = "Something went wrong" 
       alertMessage = "Unfortunately the purchase failed" 
       presentAlert = true 
       delegate?.storeUpdateReceived(store: self) 
       queue.finishTransaction(trans) 
       break 
      case .restored: 
       SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction) 
       // Try to pop back after successful restore 
       purchaseSuccess = true 
       delegate?.storeUpdateReceived(store: self) 
       queue.finishTransaction(trans) 
       break 
      default: 
       break 
      } 
     } 
    } 
    // Restore products 
    func restore() { 
     SKPaymentQueue.default().add(self) 
     SKPaymentQueue.default().restoreCompletedTransactions() 
    } 

    func getProducts() { 
     if(SKPaymentQueue.canMakePayments()) { 
      let productID: NSSet = NSSet(objects: "volume2", "volume3", "volume4", "volume5", "all") 
      let request: SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>) 
      request.delegate = self 
      request.start() 
     } else { 
      alertTitle = "Something went wrong" 
      alertMessage = "Your phone does not appear to be set up for making purchases" 
      presentAlert = true 
      delegate?.storeUpdateReceived(store: self) 
     } 
    } 

    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) { 
     let myProduct = response.products 
     for product in myProduct { 
      list.append(product) 
     } 
     delegate?.storeUpdateReceived(store: self) 
    } 

    func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) { 
     let transactionsArray = queue.transactions 
     if (transactionsArray.isEmpty) { 
      alertTitle = "Something went wrong" 
      alertMessage = "We weren't able to find any previous purchases for your account" 
      presentAlert = true 
      delegate?.storeUpdateReceived(store: self) 
     } 
     else { 
      for transaction in transactionsArray { 
       let t: SKPaymentTransaction = transaction 
       let prodID = t.payment.productIdentifier as String 
       switch prodID { 
       case "volume2": 
        VolumeTableViewController.saveUnlocked(volumeUnlocked: 1) 
        delegate?.storeUpdateReceived(store: self) 
       case "volume3": 
        VolumeTableViewController.saveUnlocked(volumeUnlocked: 2) 
        delegate?.storeUpdateReceived(store: self) 
       case "volume4": 
        VolumeTableViewController.saveUnlocked(volumeUnlocked: 3) 
        delegate?.storeUpdateReceived(store: self) 
       case "volume5": 
        VolumeTableViewController.saveUnlocked(volumeUnlocked: 4) 
        delegate?.storeUpdateReceived(store: self) 
       case "all": 
        for i in 0...VolumeTableViewController.unlocked.count-1 { 
         VolumeTableViewController.saveUnlocked(volumeUnlocked: i) 
        } 
        delegate?.storeUpdateReceived(store: self) 
       default: 
        alertTitle = "Something went wrong" 
        alertMessage = "We weren't able to find the correct product" 
        presentAlert = true 
        delegate?.storeUpdateReceived(store: self) 
       } 
      } 
     } 
    } 
    // Format the price and display 
    func formatPrice(price: NSDecimalNumber) -> String { 
     let formatter = NumberFormatter() 
     formatter.locale = Locale.current 
     formatter.numberStyle = .currency 
     if let formattedPrice = formatter.string(from: price){ 
      localPrice = (" \(formattedPrice)") 
     } 
     return localPrice! 
    } 
} 

StoreViewControllerクラス:

let store = Store() // Global store instance 

import UIKit 

class StoreViewController: UIViewController, ClassStoreDelegate { 
    // Properties 
    /* let alert = UIAlertController(title: "Something went wrong", message: 
    "Unfortunately, something went wrong with your request", preferredStyle: UIAlertControllerStyle.alert) */ 
    // Actions 
    @IBAction func btn2(_ sender: UIButton) { 
     store.buy(productId: store.list[0].productIdentifier) 
    } 

    @IBAction func btn3(_ sender: UIButton) { 
     store.buy(productId: store.list[1].productIdentifier) 
    } 

    @IBAction func btn4(_ sender: UIButton) { 
     store.buy(productId: store.list[2].productIdentifier) 
    } 

    @IBAction func btn5(_ sender: UIButton) { 
     store.buy(productId: store.list[3].productIdentifier) 
    } 

    @IBAction func btnAll(_ sender: UIButton) { 
     store.buy(productId: store.list[4].productIdentifier) 
    } 

    @IBAction func btnRestore(_ sender: UIButton) { 
     store.restore() 
    } 
    // Outlets 
    @IBOutlet weak var btn2: UIButton! 
    @IBOutlet weak var btn3: UIButton! 
    @IBOutlet weak var btn4: UIButton! 
    @IBOutlet weak var btn5: UIButton! 
    @IBOutlet weak var btnAll: UIButton! 
    @IBOutlet weak var btnRestore: UIButton! 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     // Disable buttons until prices loaded 
     btn2.isEnabled = false 
     btn3.isEnabled = false 
     btn4.isEnabled = false 
     btn5.isEnabled = false 
     btnAll.isEnabled = false 
     btnRestore.isEnabled = false 

     store.delegate = self // bind the delegate like this? 
     //  alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default)) // Set up the action for the alert button 

     // Get list of products for the store 
     self.navigationItem.title = "Store" 
     // update once the list of products is got from the store object 
     store.getProducts() 
    } 

    // Running the delegate update 
    func storeUpdateReceived(store: Store) { 
     if ((store.list.count) > 0) { 
         btnRestore.setTitle("Restore", for: .normal) 

      if store.list[0].productIdentifier == "all" { 
           btn2.setTitle(store.list[0].localizedTitle + " " + store.formatPrice(price: store.list[0].price), for: .normal) 
      } 
      if store.list[1].productIdentifier == "volume2" { 
       if VolumeTableViewController.unlocked[1] { 
        btn3.isHidden = true 
       } else { 
        btn3.setTitle(store.list[1].localizedTitle + " " + store.formatPrice(price: store.list[1].price), for: .normal) 
       } 
      } 
         if store.list[2].productIdentifier == "volume3" { 
       if VolumeTableViewController.unlocked[2] { 
        btn4.isHidden = true 
       } else { 
        btn4.setTitle(store.list[2].localizedTitle + " " + store.formatPrice(price: store.list[2].price), for: .normal) 
       } 
      } 
      if store.list[3].productIdentifier == "volume4" { 
       if VolumeTableViewController.unlocked[3] { 
        btn5.isHidden = true 
       } else { 
        btn5.setTitle(store.list[3].localizedTitle + " " + store.formatPrice(price: store.list[3].price), for: .normal) 
       } 
      } 
      if store.list[4].productIdentifier == "volume5" { 
       if VolumeTableViewController.unlocked[4] { 
        btnAll.isHidden = true 
       } else { 
        btnAll.setTitle(store.list[4].localizedTitle + " " + store.formatPrice(price: store.list[4].price), for: .normal) 
       } 
      } 

      // Now enable the buttons 
      btn2.isEnabled = true 
      btn3.isEnabled = true 
      btn4.isEnabled = true 
      btn5.isEnabled = true 
      btnAll.isEnabled = true 
      btnRestore.isEnabled = true 
     } 
     if store.purchaseSuccess { 
     performSegueToReturnBack() 
      store.purchaseSuccess = false 
     } 
    } 

    // method to go back when complete 
    func performSegueToReturnBack() { 
     if let nav = self.navigationController { 
      nav.popViewController(animated: true) 
     } else { 
      self.dismiss(animated: true, completion: nil) 
     } 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 
} 

答えて

2

あなたがボタンを押したときに、それは次にボタン

を無効にするように、私はそれを変更したいですボタンを無効にするか、購入インタフェースを非表示にして、すぐにタップしてください彼は買いボタン。購入プロセスは、あなたがすることはできません

を継続する準備ができるまで

とは、スピナーまたは類似したが表示されます。あなたは何が起こっているのかを知る方法がありません。 「購入プロセス」は、ユーザーとランタイムの間の、アプリケーション外のインターチェンジです。あなたは何が起こっているのか知らされていません。ユーザーが購入をキャンセルした場合、またはユーザーのパスワードや店舗アカウントに問題がある場合は、何が起きたかを通知するイベントはありません。だから、もしあなたが特別な "待っている"インターフェースを置くなら、それは永遠に残るかもしれません。

基本的に、質問のタイトルは深い誤解を示しています。 ではなく、 "待機"します。あなたはあなたのアプリの人生を続けるだけです。購入プロセスはで、非同期です。あなたのアプリのプロセスはです。支払いキューがアプリに何か起こったことが伝えられたら、あなたは応答します。それで全部です。

Apple's guidance about thisを参照してください;!。彼らが指摘するように、いくつかの状況下では、支払キューからメッセージが日に到着しない場合がありますあなたはそのために「待機中」はかなり愚かに見えると思います)

だから、正しい手順であります私たちが最初に言ったこと。ユーザーが「購入」をタップした場合、購入インターフェースを無効にするか無効にすると、それだけです。

+0

私は購入用のインターフェイスを提示されたビューコントローラにしています。ユーザーがBuyをタップすると、View Controllerが閉じられ、商品の支払いがキューに入れられます。それで全部です。 – matt

関連する問題