DDRider62
DDRider62

Reputation: 833

restoreCompletedTransactions returns incomplete information in sandbox environment

I am having quite some trouble with restoreCompletedTransactions while developing an iPhone application. All the issues listed below occur when working in the sandbox environment. The app is not yet selling. It's being developed with Xcode 4.3.2 running in simulator 5.0 and 5.1. The problems I get are:

  1. Every time the application starts and the call to addTransactionObserver is placed, updatedTransactions is called with a transaction being purchased. On each callback my code calls finishTransaction: to complete the purchase, and yet this issue keeps happening every time I start the application. A confirmation for exactly the same purchase comes in.
  2. Invoking [[SKPaymentQueue defaultQueue] restoreCompletedTransactions] will not list all the non-consumable items purchased with the account. I have 2 purchases of non-consumable items and only 1 is returned every time. If I try to purchase the item missing in the list, I will get a message indicating that the item has already been purchased. The missing item in the list is NOT the one for which I get problem 1 (listed above).

At this point I am completely stuck. My application relies on the AppStore for returning information on non-consumables, since we are not saving this data in our own servers. But we need to make sure the AppStoreKit returns the list with ALL the purchased items. Not just some.

Here is the relevant code I am using to test restoreCompletedTransactions:

- (void) paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    NSLog(@"updatedTransactions started. -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ");
    NSLog(@"Number of transactions received: %d.", [transactions count]);
    int count = 0;
    for (SKPaymentTransaction *trans in transactions)
{
    NSLog(@"Data for transaction %d: ", ++count);
    NSString *transId = [trans transactionIdentifier];
    switch ([trans transactionState])
    {
        case SKPaymentTransactionStatePurchasing:
            NSLog(@"Purchasing transaction: %@", transId);
            if (transId == nil)
            {
                NSLog(@"    Original transaction Id: %@", [[trans originalTransaction] transactionIdentifier]);
            }

            NSLog(@"     No action taken in update");
            break;
        case SKPaymentTransactionStateFailed:
            NSLog(@"Purchase transaction failed for transaction %@", transId);
            NSLog(@"     Error %d (%@)", [[trans error] code], [[trans error] localizedDescription]);
            NSLog(@"     Action Taken:  finish transaction.");
            [queue finishTransaction: trans];
            break;
        case SKPaymentTransactionStatePurchased:
            NSLog(@"Purchased transaction %@", transId);
            NSLog(@"     Purchased qty %d of  product %@", [[trans payment] quantity], [[trans payment] productIdentifier]);
            NSLog(@"     Action: called [queue finishTransaction:] to complete purchase");
            [queue finishTransaction: trans];
            break;
        case SKPaymentTransactionStateRestored:
        {
            SKPayment *paym = [trans payment];
            SKPaymentTransaction *origTrans = [trans originalTransaction];
            SKPayment *origPayment = [[trans originalTransaction] payment];
            NSLog(@"Transaction restored: %@ with original transaction %@", transId, [[trans originalTransaction] transactionIdentifier]);
            NSLog(@"     TRANSACTION DATA:");
            NSLog(@"           purchased %d of product %@ on %@.", 
                  [paym quantity], 
                  [paym productIdentifier], 
                  [[trans transactionDate] description]);

            NSLog(@"     ORIGINAL TRANSACTION DATA:");
            NSLog(@"           purchased %d of product %@ on %@.", 
                  [origPayment quantity], 
                  [origPayment productIdentifier], 
                  [[origTrans transactionDate] description]);

            NSLog(@"     No action taken.");
            break;
        }

        default:
            NSLog(@"Unexpected transaction state:  %d", [trans transactionState]);
            NSLog(@"     No action taken.");
            break;
    }
}

NSLog(@"");
NSLog(@"updatedTransactions ended. -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ");
}

- (void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
NSLog(@"Restore completed transactions finished.");
NSLog(@"     Number of transactions in queue:  %d", [[queue transactions] count]);
for (SKPaymentTransaction *trans in [queue transactions])
{
    NSLog(@"          transaction id %@ for product %@.", [trans transactionIdentifier], [[trans payment] productIdentifier]);
    NSLog(@"          original transaction id: %@ for product %@.", [[trans originalTransaction] transactionIdentifier],
          [[[trans originalTransaction] payment]productIdentifier]);
    }
NSLog(@"");
}

// Method to restore transactions when user clicks button in application
- (void) onRestoreCompletedTransactions:(id)sender
{
    [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}

Upvotes: 6

Views: 2323

Answers (2)

Tom McHale
Tom McHale

Reputation: 41

An SKProductsRequest will get you back a list of SKProduct instances. The SKProduct class does not to my reading have purchased info. I think you really do want to use restoreCompletedTransactions and get back a list of SKPaymentTransaction instances. That said, I am having the same problem with a sandboxed account. I get back an incomplete list of transaction (23 out of 48). But if I do select to buy a non consumable that is purchased but not restored, the store that it is an already purchased item and will send back a restore for that item.

Any luck solving this?

Upvotes: 0

James Paolantonio
James Paolantonio

Reputation: 2194

Are you trying to call restoreCompletedTransactions everytime the application is starting? If you want a list of all transactions you would make a SKProductsRequest

 SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productsSet];
    productsRequest.delegate = self;
    [productsRequest start];

If you want to get the completedTransactions and are not getting back everything, please show the logs.

Upvotes: 0

Related Questions