In App Purchase - detect whether user has already made that purchase

Viewed 231

I have the following code to make In-App-Purchases. Everything works fine and the user is able to purchase (non-consumable) on button click.

Currently I call getProducts() and restorePurchases() inside of AppDelegate - when the user has already made a purchase, I assume it will be fetched with restorePurchases() - how can I detect whether a specific product with its ID has already been purchased to f.e. hide that button.

import Foundation
import StoreKit

class IAPService: NSObject {

    private override init() {}
    static let shared = IAPService() 
    var products = [SKProduct]()
    let paymentQueue = SKPaymentQueue.default() 
    private var purchasedProductIdentifiers: Set<String> = []

    func getProducts() {
        let product: Set = ["123456"]
        let request = SKProductsRequest(productIdentifiers: product)
        request.delegate = self
        request.start()
        paymentQueue.add(self)
    }

    func purchase() {
        guard let productToPurchase = products.first else { return }
        print(productToPurchase)
        let payment = SKPayment(product: productToPurchase)
        paymentQueue.add(payment)
    }

    func restorePurchases() {
        paymentQueue.restoreCompletedTransactions()
    }

}

extension IAPService: SKProductsRequestDelegate {

    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        self.products = response.products
        for product in response.products {
            print(product.localizedTitle)
        }
    }

}

extension IAPService: SKPaymentTransactionObserver {

    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for transaction in transactions {
            print(transaction.transactionState.status(), transaction.payment.productIdentifier)
            switch transaction.transactionState {
            case .purchasing: break
            default: queue.finishTransaction(transaction)
            }
        }
    }

}

extension SKPaymentTransactionState {
    func status() -> String {
        switch self {
        case .deferred: return "deferred"
        case .failed: return "failed"
        case .purchased: return "purchased"
        case .purchasing: return "purchasing"
        case .restored: return "restored"
        }
    }
}
1 Answers

You need to check callback of updatedTransactions for the needed productIdentifier and it's state purchased/restored

func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
    for transaction in transactions {
        if transaction.payment.productIdentifier == "someId" && ( transaction.transactionState == .purchased || transaction.transactionState == .restored ) {
            // purchased / resorted
        } 
    }
}

Useful links

https://www.raywenderlich.com/5456-in-app-purchase-tutorial-getting-started

in-app purchase in Swift with a single product

Related