为沙盒用户恢复应用内购买似乎可以验证新用户,即使他们从未购买过该应用

时间:2018-07-23 19:53:25

标签: ios swift in-app-purchase sandbox restore

我正在跟踪此处找到的有关应用内购买的教程: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()
        }

    }

}

0 个答案:

没有答案