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