App keeps asking for Apple ID after opening view with SKPaymentTransactionObserver

312 views Asked by At

So I know the problem is the ViewController with the IAP, but unsure how to fix it.

I add SKPaymentQueue.defaultQueue().addTransactionObserver(self) in viewDidLoad and have the delegates for the class; SKProductsRequestDelegate, SKPaymentTransactionObserver.

I use the methods to carry out transactions for purchases, restore any purchases and make any changes needed for non consumable purchases.

But regardless what the user does, after loading the IAPViewController the app keeps prompting the user to login. Its mostly when the user exits the app then opens it back up.

I tried adding SKPaymentQueue.defaultQueue().removeTransactionObserver(self) when dismissing the view however that didn't seem to work.

Does anyone have any suggestions ?? I had to pull my app from review because of this bug :(

Here's the full code;

class IAPViewController: UIViewController, SKProductsRequestDelegate, SKPaymentTransactionObserver {

var productIDs: Array<String!> = []
var productsArray: Array<SKProduct!> = []

var selectedProductIndex: Int!
var transactionInProgress = false

override func viewDidLoad() {
    super.viewDidLoad()


    productIDs.append("com.COMPANY.NAME.BUY01")
    productIDs.append("com.COMPANY.NAME.BUY02")
    productIDs.append("com.COMPANY.NAME.BUY03")
    productIDs.append("com.COMPANY.NAME.BUY04")

    requestProductInfo()
    SKPaymentQueue.defaultQueue().addTransactionObserver(self)
 }

@IBAction func purchase04(sender: AnyObject) {

    selectedProductIndex = 0
    transactionAction()


}

@IBAction func restoreAction(sender: AnyObject) {
    SKPaymentQueue.defaultQueue().addTransactionObserver(self)
    SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
}


    //StoreKit


    func transactionAction() {
        let payment = SKPayment(product: self.productsArray[self.selectedProductIndex] as SKProduct)
        SKPaymentQueue.defaultQueue().addPayment(payment)
        self.transactionInProgress = true

    }

    //Request Products
    func requestProductInfo() {
        if SKPaymentQueue.canMakePayments() {
            let productIdentifiers = NSSet(array: productIDs)
            let productRequest = SKProductsRequest(productIdentifiers: productIdentifiers as! Set<String>)

            productRequest.delegate = self
            productRequest.start()

        }
        else {
            print("Cannot perform In App Purchases.")
        }

    }

    func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {
        if response.products.count != 0 {
            for product in response.products {
                print("\(product.localizedTitle)")
                productsArray.append(product)
            }
        }
        else {
            print("There are no products.")
        }

        if response.invalidProductIdentifiers.count != 0 {
            print("\(response.invalidProductIdentifiers.description)")
        }

        print("Number of products in productsArray \(productsArray.count) - Number of products in productIDs \(productIDs.count)")

}


    //Payment Observer
    func paymentQueue(queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for transaction in transactions {
            switch transaction.transactionState {
            case SKPaymentTransactionState.Purchased:
                print("Transaction completed successfully.", terminator: "")
                self.deliverProduct(transaction)
                SKPaymentQueue.defaultQueue().finishTransaction(transaction)
                transactionInProgress = false

            case SKPaymentTransactionState.Failed:
                print("Transaction Failed", terminator: "");
                SKPaymentQueue.defaultQueue().finishTransaction(transaction)
                transactionInProgress = false

            default:
                print(transaction.transactionState.rawValue, terminator: "")
            }
        }
    }

    func deliverProduct(transaction:SKPaymentTransaction) {

        if transaction.payment.productIdentifier == "com.COMPANY.NAME.BUY01"
        {
            print("Consumable Product 1 Purchased")

        }
        else if transaction.payment.productIdentifier == "com.COMPANY.NAME.BUY02"
        {
            print("Consumable Product 2 Purchased")
        }
        else if transaction.payment.productIdentifier == "com.COMPANY.NAME.BUY03"
        {
            print("Product 3 purchased")
        }
        else if transaction.payment.productIdentifier == "com.COMPANY.NAME.BUY04"
        {
            print("Product 4 purchased")
        }

    }

//Restore Purchases

func paymentQueueRestoreCompletedTransactionsFinished(queue: SKPaymentQueue) {
    print("Transactions Restored")

    let purchasedItemIDS = []


    for transaction:SKPaymentTransaction in queue.transactions {

        if transaction.payment.productIdentifier == "com.COMPANY.NAME.BUY04"
        {
            print("Consumable Product Purchased")

        }

    }

    let alertController = UIAlertController(title: "Restored Purchases", message: "Your purchases have been restored. ", preferredStyle: .Alert)

    let OKAction = UIAlertAction(title: "OK", style: .Default) { (action) in
        // ...
    }
    alertController.addAction(OKAction)

    self.presentViewController(alertController, animated: true) {
        // ...
    }

}

@IBAction func exit(sender: AnyObject) {
    self.dismissViewControllerAnimated(true, completion: nil)

        SKPaymentQueue.defaultQueue().removeTransactionObserver(self)

}

}
1

There are 1 answers

3
Michael On

It sounds like you have not called finishTransaction as per the documentation here:

Transactions stay in the payment queue until they are removed. StoreKit will call your observer’s paymentQueue: updatedTransactions: every time that your app launches or resumes from background until they are removed. To that effect, your customers may be repeatedly asked to authenticate their purchases or be prevented from purchasing your products.

Call finishTransaction: on your transaction to remove it from the queue. Finished transactions are not recoverable. Therefore, be sure to provide your content, to download all Apple-hosted content of a product, or complete your purchase process before finishing your transaction. See Finishing the Transaction for more information.

Do you know that one of the two calls to finishTransaction is actually running?