Search code examples
iosswiftin-app-purchasestorekit

In-App Purchase is successful, but methods are not called


I'm testing a promoted In-App Purchase, as described here.

Here's how it works:

  1. I construct the system URL.
  2. I send the system URL link to my device.
  3. I tap the link.
  4. My app is automatically opened, and the In App Purchase payment sheet is presented.
  5. I tap the "Purchase" button (or whatever it's called), and enter my password to complete the transaction.
  6. The transaction appears to be successful and an alert appears that says, "You're all set. Your purchase was successful".

The problem is, some code that should run depending on the state of the transaction seems not to. I'm not sure how that's possible, but there you go.

So, the deferredTransactionHandler, handlePurchase, handleFailedPurchase, and handleRestoredPurchase methods appear not to be invoked.

class StoreObserver: NSObject, SKPaymentTransactionObserver, SKProductsRequestDelegate { 
    var productRequest: SKProductsRequest?
    var isAuthorizedForPayments: Bool {
        return SKPaymentQueue.canMakePayments()
    }
    var products = [SKProduct]()


    func paymentQueue(_ queue: SKPaymentQueue, shouldAddStorePayment payment: SKPayment, for product: SKProduct) -> Bool {
        //The user has initiated a promoted In-App Purchase directly from the app's product page.

        //Show the UI:
        SceneDelegate.mainData.showAppStorePromotionUI = true
        
        //"Return true to continue the transaction in your app. Return false to defer or cancel the transaction."
        return true
    }

    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for transaction in transactions {
            switch transaction.transactionState {
                case .purchasing: break
                case .deferred: deferredTransactionHandler(transaction)
                case .purchased: handlePurchase(transaction)
                case .failed: handleFailedPurchase(transaction)
                case .restored: handleRestoredPurchase(transaction)
                @unknown default: fatalError("unknownPaymentTransaction")
             }
          }
    }
}

How do I know these methods aren't being called? 1) Inside these methods, I update the UI to reflect that the transaction has completed (the UI is never updated, though), and 2) Inside these methods I try to present an alert (but the alert is never presented). Here's how I'm doing that:

func handlePurchase(_ transaction: SKPaymentTransaction) {
    //Update the UI
    SceneDelegate.mainData.showAppStorePromotionUI = false

    //Present an alert so you know this function ran
    let alert = UIAlertController(title: "Alert", message: "handlePurchase()", preferredStyle: .alert)
    alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { action in
            
    }))
    let topViewController = UIApplication
            .shared
            .connectedScenes
            .flatMap { ($0 as? UIWindowScene)?.windows ?? [] }
            .first { $0.isKeyWindow }?.rootViewController
        
    topViewController?.present(alert, animated: true, completion: nil)

    //Complete the transaction  
    SKPaymentQueue.default().finishTransaction(transaction)
}

Why does it seem that these functions are not being called? What am I missing?

Thank you!


Solution

  • Sigh. It was a stupid mistake on my part.

    I'd been testing something, and had forgotten to remove a line in my SceneDelegate's sceneWillResignActive(_:) in which I removed the observer. So, every time the payment sheet was presented, the observer was removed, which messed everything up.

    func sceneWillResignActive(_ scene: UIScene) {
        //Removing this line solved the problem
        //SKPaymentQueue.default().remove(SceneDelegate.inAppPurchases)
    }