My application went to some odd state in IAP sandbox... Every time I launch application it is asking for password of particular test user. I guess due to unfinished transaction. I really want to finish that transaction, but it's not possible. Some background info and what I have done for it:
- I've deleted that test user from itunesconnect
- As soon as application launches I call
[[SKPaymentQueue defaultQueue] addTransactionObserver:self]
- No payment queue update notification is received after I enter password for that particular test user, or hit cancel
[SKPaymentQueue defaultQueue].transactions.count
is always 0
, so I can't manually finish unfinished transactions
- I've delete app from device, restarted device - still asking for password
- I am logging out of user from Settings -> iTunes & App Store
- After I cancel dialog box asking for password, somehow I am able to login with another test user, but next time I am still getting dialog box for password of old test user.
The only thing is left to change bundle id, which is not desirable in my case. Hopefully someone knows alternative ways how to get rid of unfinished transaction.
I'm putting this here because there are a lot of really bad, bad answers out there that provide WRONG information on how to resolve this problem. It is not that rare, or mysterious or an Apple bug, it's part of the App store design and there to help you get your IAP built right.
DO NOT:
- Ever, ever, ever delete the sandbox test user. This makes it impossible to resolve the problem and you will be in endless loop hell until the transaction eventually goes away.... it does go away but it takes a long time, like days or weeks.
- If you delete the sandbox test user, when you are subsequently repeatedly prompted (like EVERY TIME your App sets up IAP) to log into the test user store account to finish the transaction, you can't because the user has been deleted. Nor will you be able to add the test user back because the developer portal will say that user id has already been used.
- Do not: delete the App or re-install iOS or any other such BS. It has no effect, doesn't solve the problem and wastes a lot of time.
DO:
- Call FINISH on ALL transactions. If one is interrupted for some reason, simply complete on a subsequent run of the App. The app will be repeatedly sent the payment queue notice until you call finish on it, giving you the opportunity to call
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
This is intentional and a pre-caution against interrupted transactions.
That's it! Finish all transactions, else you will be sent to the Endless Loop hell of repeated requests to sign into a non-existent test user App Store account every single time your App launches on that device :(
You might need to repeat these steps a few times to it to work.
Finish the transaction as soon as your transaction observer delegate method is called.
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions) {
// Temporary code to solve the loop issue
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
/*
switch (transaction.transactionState) {
// Call the appropriate custom method.
case SKPaymentTransactionStatePurchased:
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
default:
break;
}
*/
}
}
Now you run the app and login with the deleted sandbox account. The method above should fire and finish the transaction right away. If the transactions array is nil, try calling the finish code before the FOR loop.
I got this to work again by calling the following code to be executed once. You may be asked a last time for the password to be entered, but after the code has been executed, the "exorcism" is done and you're free to remove the code again.
#ifdef DEBUG
for (SKPaymentTransaction *transaction in [[SKPaymentQueue defaultQueue] transactions]) {
NSLog(@"finish transactions pending sind last load...");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
#endif