PaymentQueue never hitting "purchased" in Sandbox

Hi all. I'm attempting to add consumable IAPs to my IOS application. My code seems to work fine when I'm testing locally using the storekit.configuration; however, when I switched over to Sandbox testing, I get the Purchase pop-up in the app, and my PaymentQueue observer hits the "purchasing" status, but that's it. After I hit Purchase on the pop-up, my PaymentQueue observer never hits again. The purchase pop-up says the purchase was successful in the app, and it goes away, but it pops back up a few seconds later. In testing, my PaymentQueue observer hits and goes to the "purchased" case, so things work as-expected.

I've set my test account up in Sandbox as per Apple's instructions.

Has anyone else run into this? Is there a way for me to see the Queue real-time so I can see what's going on in there?

My app is still in development - I'm testing in TestFlight, but haven't submitted for full AppStore review yet, in case that matters....

Here's the code for my In-App Purchase manager, in case that helps.

//
//  IAPManager.swift
//
//

import Foundation
import StoreKit

final class IAPManager: NSObject, SKProductsRequestDelegate, SKPaymentTransactionObserver {
    
    static let shared = IAPManager()
    
    var products = [SKProduct]()
    
    private var completion: ((Int) -> Void)?
    
    enum Product: String, CaseIterable {
        case tokens_10
        
        var count : Int {
            switch self {
            case .tokens_10:
                return 10
            }
        }
    }
    
    public func GetProducts() {
        //Load all the product in our Product enum in
        let request = SKProductsRequest(productIdentifiers: Set(Product.allCases.compactMap({ $0.rawValue })))
        request.delegate = self
        request.start()
    }
    
    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        print("Products found : \(response.products.count).")
        self.products = response.products
    }
    
    public func purchase(product : Product, completion: @escaping ((Int) -> Void)) {
        //Make sure the user is allowed to purchase stuff
        guard SKPaymentQueue.canMakePayments() else {
            return }
        //Make sure the product IDs match
        guard let storeKitProduct = products.first(where: { $0.productIdentifier == product.rawValue}) else {
            return
        }
        
        self.completion = completion
        
        let paymentRequest = SKPayment(product: storeKitProduct)
        SKPaymentQueue.default().add(self)
        SKPaymentQueue.default().add(paymentRequest)
    }
    
    func paymentQueue(_ queue: SKPaymentQueue,
                      shouldAddStorePayment payment: SKPayment,
                      for product: SKProduct) -> Bool {
        print("Should add payment hit.")
        return true
    }
    
    //MARK Error - 2024-02-02:  Never hitting "case .purchased" when using Sandbox
    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        transactions.forEach( {
            switch $0.transactionState {
            case .purchasing:
                print("Transaction purchasing.")
                break
            case .purchased:
                print("Transaction PURCHASED.")
                if let product = Product(rawValue: $0.payment.productIdentifier) {
                    completion?(product.count)
                }
                SKPaymentQueue.default().finishTransaction($0)
                SKPaymentQueue.default().remove(self)
                break
            case .failed:
                print("Transaction failed.")
                break
            case .restored:
                print("Transaction restored.")
                break
            case .deferred:
                print("Transaction deferred.")
                break
            @unknown default:
                break
            }
        })
    }
    
}

Any help would be greatly appreciated!

Mark

Have exactly the same problem. App works with StoreKit fine, but as soon as I remove StoreKit file and want to testing sandbox version it brings up the payment modal again and again... Also I have the inApp purchases configured in AppStore Connect and all of the details of the inApp purchase (like name, details, price) show up normal, but as soon as I hit buy, i get a confirmation sound but the transaction stays in progress and the buy modal pops up again after 4-5 seconds.

Is this maybe related, that the inApp purchase is currently "in review", or "submitted for review" (I am not able to release the IAP because I need to submit a new app version with that too). I also searched a lot but did not find a solution to that, but at least we have the exactly same issue.

Hey, any update on this? I’m getting the same. is having the in app purchases reviewed the solution? Seems odd you have to get them approved before you can test them.

PaymentQueue never hitting "purchased" in Sandbox
 
 
Q