paymentQueueRestoreCompletedTransactionsFinished: vs updatedTransactions:

10,032

Solution 1

There is an excellent WWDC Video about using StoreKit, it is WWDC2012 Session 302.

To isolate each purchase, your updatedTransactions method could look something like this:

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {

        for (SKPaymentTransaction *transaction in transactions) {

            switch(transaction.transactionState) {
                case SKPaymentTransactionStatePurchased:
                    // Unlock content
                    //... Don't forget to call `finishTransaction`!
                    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                    break;
                case SKPaymentTransactionStatePurchasing:
                    // Maybe show a progress bar?
                    break;
                case SKPaymentTransactionStateFailed:
                    // Handle error
                    // You must call finishTransaction here too!
                    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                    break;
                case SKPaymentTransactionStateRestored:
                    // This is the one you want ;)
                    // ...Re-unlock content...
                    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                    break;
             }
         }
}

Once you've determined that the purchase is being restored, you can make content available as you see fit - preferably by calling a separate method from within that switch statement and passing the transaction as a parameter. The implementation is up to you of course.

Solution 2

  1. Call [[SKPaymentQueue defaultQueue] addTransactionObserver:self] in (void)viewDidLoad or equivalent if applicable.
  2. Then call [[SKPaymentQueue defaultQueue] restoreCompletedTransactions].
  3. (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions will be called accordingly through (2).

If you don't call the method in (1), the application will never reach (3) to restore transactions in the first place.

Solution 3

I had this same issue with paymentQueueRestoreCompletedTransactionsFinished never getting called. I fixed by going to iTunes & Aoo Stores in Settings and logged out of the sandbox test account and tried it again. Worked as expected the next time after being prompted to login again on a restore.

Share:
10,032
hzxu
Author by

hzxu

Updated on July 24, 2022

Comments

  • hzxu
    hzxu almost 2 years

    I am restoring completed transactions (recurring) with

    [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
    

    and in

    - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
    

    I got a list of history transactions restored, made by the app, but the method:

    - (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
    

    is not even called once, so I wonder which one should I use? I did some research and found that updatedTransactions: method should be used with checking transaction state, but if I got a list of transactions restored, it is just meaningless to treat them all as transactions. Which one should I use? Does paymentQueueRestoreCompletedTransactionsFinished only gives me the latest one (ie sandbox subscription expires in several minutes and I got a full list of history transactions made when testing, in updatedTransactions).

  • hzxu
    hzxu over 11 years
    Yes I did do 1. the problem is the method in 3. gives me a list of all subscription the sandbox account has made. I only need the one which is successfully restored.
  • hzxu
    hzxu over 11 years
    Yes, but what I got is more than 1 transactions restored for the same product ID, then do I use the transaction with most recent transactionDate?
  • Ephemera
    Ephemera over 11 years
    Hmm that shouldn't be happening... That possibly means, previously, the transaction wasn't completed with finishTransaction:. I'd reset your App (clean build and delete data from the iOS Simulator) to get rid of the queued transactions. Before you do that though, where are you setting up your TransactionObserver?
  • Takagi
    Takagi almost 11 years
    Maybe missing break in the SKPaymentTransactionStatePurchasing case?
  • Chirag Shah
    Chirag Shah over 7 years
    @hzxu i have same problem, Did you find any solution?
  • Henry Mueller
    Henry Mueller about 3 years
    I am pretty sure I would never have tried this as a fix, but it was exactly my issue. Thank you very much! I certainly hope this is a "dev environment" issue... seems like a lot of apps would break if this happened in prod.