저는 현재 Swift 기반 iOS 앱에서 인앱 구매를 제공하고 있습니다. 나는 무거운 짐을하는 스토어 클래스를 가지고 있고 저장소 뷰를 관리하는 StoreViewController를 가지고있다. 현재 구매 버튼을 누르면 응답 시간이 매우 오래 걸립니다 (최소 10 초 이상). 즉, 버튼을 반복해서 누르거나 구매를 포기할 수 있습니다. 버튼을 누르면 버튼이 비활성화되고 구입 프로세스가 계속 될 준비가 될 때까지 회 전자 또는 유사한 것을 표시하도록 변경하려고합니다. 내가 이미 가지고있는 코드에서이 작업을 수행하는 데 선호되는 방법/장소는 무엇입니까?앱 스토어가 인앱 구매로 응답하기를 기다리는 동안 '로딩 스피너'또는 유사한 방법을 실행하는 방법은 무엇입니까?
스토어 클래스 :
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