views:

55

answers:

2

I am using in-app purchase for an iPhone app. I have a class that acts as SKProductsRequestDelegate and SKPaymentTransactionObserver, and it's all working fine in the currently released version available on iTunes.

However, after recently adding a new non-consumable product and testing it within the Sandbox environment, I'm now encountering a strange problem. Every time I launch the app, the purchase I made yesterday reappears in the transactions list passed to me by paymentQueue:updatedTransactions:, despite the fact that I had called [[SKPaymentQueue defaultQueue] finishTransaction:transaction] already (several times). It's undead!

In my paymentQueue:updatedTransactions: implementation, I have:

for (SKPaymentTransaction* transaction in transactions) 
    switch (transaction.transactionState)
    {
        case SKPaymentTransactionStatePurchased:
        case SKPaymentTransactionStateRestored:
        {
            ....
                DDLog(@"Transaction for %@ occurred originally on %@.", transaction.payment.productIdentifier, transaction.originalTransaction.transactionDate);
                ....

I then process the purchase, download the user content and finally, in another method, do this:

for (SKPaymentTransaction* transaction in [[SKPaymentQueue defaultQueue] transactions])         
            if (([transaction.payment.productIdentifier isEqualToString:theParser.currentProductID]) &&
                 ((transaction.transactionState==SKPaymentTransactionStatePurchased) || (transaction.transactionState==SKPaymentTransactionStateRestored))
               )
            {
                DDLog(@"[[ Transaction will finish: product ID = %@; date = %@ ]]", transaction.payment.productIdentifier, transaction.transactionDate);
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
            }

As you may have noticed, I'm not holding on to the original transaction object for the sake of simplicity, and it's relatively easy to find it later from the call to [[SKPaymentQueue defaultQueue] transactions]. Regardless, I do indeed see the expected output; that the transaction is completed and that it precisely matches the product ID and date of the original transaction. However, next time I run the app the whole things starts over! It's like the iTunes Store was never notified that the transaction completed, or refuses to acknowledge it.

A: 

hello, did you solve this issue?

martin jacala
A: 

This issue was also raised in the developer forums, and the general conclusion was that it was down to a difference in the handling of transactions in iPhone OS 4.0. The problem only seems to occur when there is a significant delay between receiving a notification of the finished transaction and calling finishTransaction on the payment queue. In the end we didn't find an ideal solution, but what we did was this:

  1. As soon as the transaction arrives, process it and record a value in the user preferences if processing was successful.

  2. The next time that transaction appears in the queue, which may not be until the next launch of the app, immediately call finishTransaction on it.

Our products are "non-consumable" so it's enough to check that the product paid for is valid and error-free to safely ignore any 'undead' repeated transactions from iTunes. For consumable products one would need to save more information about the purchase, such as the original payment date, to make sure that future transaction notifications can be matched to purchases that were already processed.

Craig McMahon