Karz
Karz

Reputation: 557

iOS "This in-app purchase has already been bought" pop-up

I'm getting an issue on my iOS app: when I touch the 'buy' button to purchase an IAP product, a pop-up appears showing this message:

This In-App purchase has already been bought. It will be restored for free.

I never had this pop-up before, and my products are only non-renewing subscriptions, so I wonder why this message appears when buying subscriptions.

When I touch ok to close this pop-up, the purchase is not performed.

Here is my code:

for transaction in transactions {
        switch transaction.transactionState {

        case SKPaymentTransactionState.Purchased, SKPaymentTransactionState.Restored:
            print("Transaction completed successfully.")
            SKPaymentQueue.defaultQueue().finishTransaction(transaction)
            transactionInProgress = false
            // Sauvegarde le produit acheté
            savePurchasedProduct(transaction.transactionDate!);
            break

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

        default:
            break
        }
    }

Upvotes: 9

Views: 16348

Answers (3)

Maulik Vekariya
Maulik Vekariya

Reputation: 554

We can also get all transactions and mark as completed by using below method.

You can add below code in viewdidload method.

for transactionPending in SKPaymentQueue.default().transactions {
        SKPaymentQueue.default().finishTransaction(transactionPending)
    }

I tried lot of other solutions but this works for me.So, now i can buy product multiple times.

Upvotes: 6

Darrell Root
Darrell Root

Reputation: 844

I had the same problem with a non-recurring subscription. It was saying that it had already been purchased, it would restore for free, but not let me buy another subscription extension.

Part of the problem was my transaction switch logic:

    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for transaction in transactions {
            switch transaction.transactionState {
            case .purchased:
                complete(transaction: transaction)
            case .restored:
                restore(transaction: transaction)
                break
...

For case .purchased I was calling:

        SKPaymentQueue.default().finishTransaction(transaction)

But for case .restored I never called finishTransaction. Somehow during development I must have missed a finishTransaction and had one "in the queue" which I was never finishing.

My fix was to modify my restoreTransaction to (after making sure the subscription was recorded in my licenses object) call .finishTransaction. I checked that I didn't duplicate the subscription checking for unique transaction IDs.

Then I attempted to purchase 2 more times. The first time the transaction was finished, and the 2nd time I was able to buy again!

Upvotes: 0

user3578549
user3578549

Reputation:

I had the same issue. Fixed it here:
My IAP isn't working. Bugs at func Paymentqueue

Here is the solution I had found:

Delete

SKPaymentQueue.defaultQueue().addTransactionObserver(self) 

everywhere you have it and put it once (ONLY ONCE) in a place where it will be executed each time your app boots up (I put it in viewDidLoad()).

This will check for all unfinished transactions and terminate them once the app has loaded, thus removing any possible errors before your users triggers an IAP.

P.S.: Also, this wasn't my issue, but make sure to finishTransaction() for each PurchaseState, like here:

func paymentQueue(queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
    print("Add Payment")

    for transaction:AnyObject in transactions{
        let trans = transaction as! SKPaymentTransaction
        print(trans.error)
        switch trans.transactionState{
        case .Purchased:
            print("IAP unlocked")
            print(p.productIdentifier)

            let prodID = p.productIdentifier as String
            switch prodID{
            case "IAP id":
                print("Keep on")
                keepOn()
            default:
                print("IAP not setup")
            }
            queue.finishTransaction(trans)
            break
        case .Failed:
            print ("Buy error")
            queue.finishTransaction(trans)
            break
        default:
            print("default: Error")
            break
        }
    }
}

Never forget this:

queue.finishTransaction(trans)  

Upvotes: 6

Related Questions