我正在跟踪此处找到的有关应用内购买的教程:https://hackernoon.com/swift-how-to-add-in-app-purchases-in-your-ios-app-c1dc2fc82319
我已经测试了使用沙盒用户购买非消耗性应用内购买。然后,我创建了一个新的沙箱用户,并按下使用新的用户名和密码登录的“还原购买”按钮,令我惊讶的是,调用payQueueRestoreCompletedTransactionsFinished并将其设置为“ .restored”,而无需首先购买该应用。
因此,我想知道恢复应用内购买如何验证用户首先购买了该应用。似乎没有这样做。
IAPHandler的以下代码。请注意,“ restored”绝不会打印到通过transactionStates的paymentQueue函数的控制台:
import UIKit
import StoreKit
enum IAPHandlerAlertType{
case disabled
case restored
case purchased
func message() -> String{
switch self {
case .disabled: return "Purchases are disabled in your device!"
case .restored: return "You've successfully restored your purchase!"
case .purchased: return "You've successfully bought this purchase!"
}
}
}
class IAPHandler: NSObject {
static let shared = IAPHandler()
//let CONSUMABLE_PURCHASE_PRODUCT_ID = "testpurchase"
let NON_CONSUMABLE_PURCHASE_PRODUCT_ID = "HCUnlocked"
fileprivate var productID = ""
fileprivate var productsRequest = SKProductsRequest()
fileprivate var iapProducts = [SKProduct]()
var purchaseStatusBlock: ((IAPHandlerAlertType) -> Void)?
// MARK: - MAKE PURCHASE OF A PRODUCT
func canMakePurchases() -> Bool { return SKPaymentQueue.canMakePayments() }
func purchaseMyProduct(index: Int){
if iapProducts.count == 0 { return }
if self.canMakePurchases() {
let product = iapProducts[index]
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().add(payment)
print("PRODUCT TO PURCHASE: \(product.productIdentifier)")
productID = product.productIdentifier
} else {
purchaseStatusBlock?(.disabled)
}
}
// MARK: - RESTORE PURCHASE
func restorePurchase(){
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().restoreCompletedTransactions()
}
// MARK: - FETCH AVAILABLE IAP PRODUCTS
func fetchAvailableProducts(){
// Put here your IAP Products ID's separated by commas
// i.e. CONSUMABLE_PURCHASE_PRODUCT_ID, NON_CONSUMABLE_PURCHASE_PRODUCT_ID
// as the objects list in NSSet
let productIdentifiers = NSSet(objects: NON_CONSUMABLE_PURCHASE_PRODUCT_ID
)
productsRequest = SKProductsRequest(productIdentifiers: productIdentifiers as! Set<String>)
productsRequest.delegate = self
productsRequest.start()
}
}
extension IAPHandler: SKProductsRequestDelegate, SKPaymentTransactionObserver{
// MARK: - REQUEST IAP PRODUCTS
func productsRequest (_ request:SKProductsRequest, didReceive response:SKProductsResponse) {
if (response.products.count > 0) {
iapProducts = response.products
for product in iapProducts{
let numberFormatter = NumberFormatter()
numberFormatter.formatterBehavior = .behavior10_4
numberFormatter.numberStyle = .currency
numberFormatter.locale = product.priceLocale
let price1Str = numberFormatter.string(from: product.price)
print(product.localizedDescription + "\nfor just \(price1Str!)")
}
}
}
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
print("paymentQueueRestoreCompletedTransactionsFinished")
purchaseStatusBlock?(.restored)
}
func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {
print(error)
}
// MARK:- IAP PAYMENT QUEUE
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction:AnyObject in transactions {
if let trans = transaction as? SKPaymentTransaction {
switch trans.transactionState {
case .purchased:
print("purchased")
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
purchaseStatusBlock?(.purchased)
break
case .failed:
print("failed")
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
break
case .restored:
print("restored")
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
break
default: break
}}}
}
}
我的视图中有一个调用restorePurchase的操作:
@IBAction func restorePurchaseAction(_ sender: Any) {
IAPHandler.shared.restorePurchase()
}
在viewWillAppear()中,我具有PurchaseStatusBlock来查看类型是否设置为“ .restored”状态,并更改UI以允许他们再次使用购买的功能:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
IAPHandler.shared.purchaseStatusBlock = {[weak self] (type) in
guard let strongSelf = self else{ return }
if type == .purchased {
strongSelf.applyPurchaseSettingsWithUIFX()
}
else if type == .restored {
strongSelf.applyPurchaseSettingsWithUIFX()
}
}
}