Ashton Cofer
Ashton Cofer

Reputation: 19

iOS App prompting user to "Confirm Your In-App Purchase" with password after a restore purchase

I am currently trying to implement a "Restore Purchase" button on my non-consumable in app purchase. However, although the restore purchase button does function correctly (restores a user's past purchase), the app also prompts the user with a "Confirm Your In-App Purchase" alert. This type of alert isn't supposed to occur during a restore purchase and should only occur during an actual purchase. "Confirm Your Purchase" alert screenshot

enter image description here

Note that a user can press cancel on the "Confirm Your Purchase" alert and the restore purchase will still occur.

Below is the code that I am using:

class RemoveAdsViewController: UIViewController, SKPaymentTransactionObserver, SKProductsRequestDelegate {

    @IBOutlet weak var removeAdsButton: UIButton!
    @IBOutlet weak var restorePurchaseButton: UIButton!

    var product: SKProduct?
    var productID = "<INSERT_PRODUCT_ID>"

    @IBAction func removeAds(_ sender: Any) {
        let paymentRequest = SKMutablePayment()
        paymentRequest.productIdentifier = productID
        SKPaymentQueue.default().add(paymentRequest)
    }

    @IBAction func restorePurchase(_ sender: Any) {
        SKPaymentQueue.default().restoreCompletedTransactions()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        removeAdsButton.isEnabled = false
        restorePurchaseButton.isHidden = true

        if (!removedAds) {
            removeAdsButton.setTitle("Connecting to App Store...", for: .normal)
            removeAdsButton.titleLabel?.font = removeAdsButton.titleLabel?.font.withSize(20)
            SKPaymentQueue.default().add(self)
            getPuchaseInfo()
        } else {
            removeAdsButton.setTitle("Purchased", for: .normal)
        }
    }

    func getPuchaseInfo() {
        if SKPaymentQueue.canMakePayments() {
            let request = SKProductsRequest(productIdentifiers: NSSet(object: self.productID) as! Set<String>)
            request.delegate = self
            request.start()
        } else {
            removeAdsButton.setTitle("Purchase Disabled", for: .normal)
        }
    }

    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        let products = response.products
        if (products.count == 0) {
            DispatchQueue.main.async {
                self.removeAdsButton.setTitle("Purchase Not Found", for: .normal)
            }
        } else {
            product = products[0]
            DispatchQueue.main.async {
                self.removeAdsButton.isEnabled = true
                self.restorePurchaseButton.isHidden = false
                self.removeAdsButton.setTitle("Remove Ads (\(self.product!.localizedPrice))", for: .normal)
                self.removeAdsButton.titleLabel?.font = self.removeAdsButton.titleLabel?.font.withSize(28)
            }
        }
        let invalids = response.invalidProductIdentifiers
        for product in invalids {
            print("product not found: \(product)")
        }
    }

    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for transaction in transactions {
            switch transaction.transactionState {
            case SKPaymentTransactionState.purchased:
                //user purchased remove ads
                SKPaymentQueue.default().finishTransaction(transaction)
                removeAdsButton.setTitle("Purchased", for: .normal)
                removeAdsButton.isEnabled = false
                restorePurchaseButton.isHidden = true
                removedAds = true
                UserDefaults.standard.set(true, forKey: "removedAds")

            case SKPaymentTransactionState.restored:
                //user restored purchase
                SKPaymentQueue.default().finishTransaction(transaction)
                removeAdsButton.setTitle("Purchased", for: .normal)
                removeAdsButton.isEnabled = false
                restorePurchaseButton.isHidden = true
                removedAds = true
                UserDefaults.standard.set(true, forKey: "removedAds")

            case SKPaymentTransactionState.failed:
                SKPaymentQueue.default().finishTransaction(transaction)

            default:
                break
            }
        }
    }

}
extension SKProduct {
    var localizedPrice: String {
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        formatter.locale = priceLocale
        return formatter.string(from: price)!
    }
} 

How can I make it so that the "Confirm Your In-App Purchase" alert doesn't occur during the restore purchase?

Upvotes: 0

Views: 677

Answers (1)

enc_life
enc_life

Reputation: 5169

That prompt will occur anytime you're trying to access the receipt file and it isn't present. It sounds like what you may be experiencing is that sandbox receipts aren't actually available on the device until after you purchase.

In production, a receipt is generated for the Apple Id upon downloading the app, so a user can restore at any time and won't see that prompt. In sandbox, the receipt is not available when you install the app - it gets added to the app files after a purchase is made. To fully test restores in sandbox, you'll need to make a purchase, let it expire, then trigger the restore - if you uninstall or rebuild from XCode at any point the receipt is cleared. This is just one of the joys of Apple sandbox :)

Upvotes: 1

Related Questions