I am implementing iOS 7+ in app purchases (consumables, like gold coins) with server validation. The workflow is the standard one:
Make purchase:
[[SKPaymentQueue defaultQueue] addTransactionObserver:self]; SKPayment* payment = [SKPayment paymentWithProduct:productToBuy]; [[SKPaymentQueue defaultQueue] addPayment:payment];
Listen for the purchase success event:
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions { for (SKPaymentTransaction *transaction in transactions) { if (transaction.transactionState == SKPaymentTransactionStatePurchased || transaction.transactionState == SKPaymentTransactionStateRestored) { NSURL *receiptUrl = [[NSBundle mainBundle] appStoreReceiptURL]; if ([[NSFileManager defaultManager] fileExistsAtPath:[receiptUrl path]]) { NSData *receiptData = [NSData dataWithContentsOfURL:receiptUrl]; NSString *receiptStr = [receiptData base64EncodedStringWithOptions:0]; // send receipt to our server for validation // MY QUESTION IS WHAT TO DO ON NEXT STARTUP IF CANNOT CONNECT TO OUR SERVER AT THIS POINT ...
At this point we send the purchase receipt to our server. If the server finds it valid we consume the purchase:
for (SKPaymentTransaction* transaction in transactions) { if ([[transaction transactionIdentifier] isEqualToString:transactionId]) { currentTransaction = transaction; break; } } if (([currentTransaction transactionState] == SKPaymentTransactionStatePurchased || [currentTransaction transactionState] == SKPaymentTransactionStateRestored)) { [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; [[SKPaymentQueue defaultQueue] finishTransaction:currentTransaction]; ...
My problem is what should I do if our server is down/user's phone loses signal at the server validation (at (3))? In this case the receipt will never will validated thus the user will have a purchase in a stuck state. (Also in my tests I see my app asking to log in into iTunes in this case; but logging in has no effect.)
I tried to add an observer to the payment queue at every startup to check for incomplete transactions, but this asks the user to log in to iTunes, thus its not a good solution.