Reputation: 877
My app is using in-app purchases, and most of my users can purchase just fine without any problems. For these folks, my app downloads the content after the purchase succeeds and they are happy.
However, for a growing number of my users, once they complete a successful in-app purchase they are being asked for their App Store password every time the app starts up after that. I believe this is happening on the call to:
[[SKPaymentQueue defaultQueue] addTransactionObserver:observer];
which I am calling on startup in accordance with step 6 in Apple's in-app purchase guide:
My guess is that, for some reason, Apple's in-app purchase servers aren't registering that the transaction finished successfully - even though I call
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
when the transaction is completed and my content has been successfully downloaded.
2 questions:
Is anyone else seeing this?
Does anyone have a suggested fix?
BOUNTY EDIT:
Its a transaction which was made with a different Apple-ID. Thats why it cannot be finished unless you type in the right credentials into the dialog. The Question should be either:
SkPaymentQueue
? Upvotes: 56
Views: 17631
Reputation: 35052
You said:
However, for a growing number of my users, once they complete a successful in-app purchase they are being asked for their App Store password every time the app starts up after that. I believe this is happening on the call to:
[[SKPaymentQueue defaultQueue] addTransactionObserver:observer];
Note that the docs for add(_ observer:
/ addTransationObserver:
state that the call may cause the user to authenticate with the App Store, so this appears to be expected behavior.
// Observers are not retained. The transactions array will only be synchronized with the server while the queue has observers. This may require that the user authenticate.
open func add(_ observer: SKPaymentTransactionObserver)
open func remove(_ observer: SKPaymentTransactionObserver)
So in addition to other answers here, it may be that you should stop calling add observer
until you are ready to potentially display an App Store login prompt.
Upvotes: 0
Reputation: 111
I had the same problem when testing IAP.
I tested with 3 test account. The app kept asking for password for both accounts. Even if I didn't touch any purchase/restore button or addTransactionObserver
.
I think this is because some previous transaction has not finished correctly, but [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
can't help at all.
So here's what I did to solve this problem:
inspired by Expected sequence when using iTunes test user
Upvotes: 1
Reputation: 421
Here's how I can consistently reproduce and resolve this issue:
iOS 8.4, development build of the app.
Use a test(sandbox) Apple Account.
Restore purchased transactions.
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions]
Immediately close the app.
Log out of test account (through settings)
Launch app
Now every time I launch the app it will pop up the "login" form. It doesn't matter if I enter the password or not. It doesn't matter if I make purchases or restore the purchases. It doesn't matter if I delete and re-install the app. Every time I launch the app, the iTune login is presented.
Fix: Hard reboot the device.
Here's what I don't know. Will this happen in a production environment (published app and actual apple login)? I hope not.
Upvotes: 1
Reputation: 9039
DO NOT DELETE THE ANSWER HERE. It was this particular Stackoverflow question that misled me and messed me up for days.
I'm putting this here because there are a lot of really bad answers that provide WRONG information on how to resolve the problem.
DO NOT:
DO:
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
That's it, Finish all transactions! Else you will be sent to the hell of the Endless Loop of sign in requests every single time your App launches on that device.
Upvotes: 8
Reputation: 225
If anyone is seeing this and is using GoogleMobileAds.framework then you may also need to call
[GADMobileAds disableAutomatedInAppPurchaseReporting];
in -application:didFinishLaunchingWithOptions:
Upvotes: 1
Reputation: 390
I had the same problem of having the login prompt coming up at the call:
[[SKPaymentQueue defaultQueue] addTransactionObserver:observer];
It would also come up every now and then even when I wasn't using my app (on the home screen or in other apps), which was really annoying. Looking around, there seem to be so many suggested answers to this issue but I finally found a solution from a combination of what I've gathered.
Note: Before step 1, I had removed the test sandbox account in iTunes Connect. I'm not sure if that would affect the solution.
To solve the problem this is what I did:
That's it. From then on the login prompt stopped coming up whenever I ran my app and also stopped coming up at random times.
Hope this helps!
Upvotes: 8
Reputation: 11787
I had the same problem.make sure that you call
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
for all three states of the transactions: SKPaymentTransactionStatePurchased, SKPaymentTransactionStateRestored, SKPaymentTransactionStateFailed.
Upvotes: 32
Reputation: 6201
I resolved it by deleting the iTunes Connect test user account related with this issue. App actually asked once again to sign in, but then it disappeared (I've also deleted app, restarted iPhone and logged in as a normal non-sandbox user, made a real restore in other non-sandbox app and then launched the app)
Upvotes: 0
Reputation: 16563
There is a problem called the "endless loop". It was big issue back in the early days of auto renewables when, for about a week, the servers did not limit renewals to 5. A device that gets a transaction and doesn't call finishTransaction will get that transaction delivered to the device about once a week until that particular test user logs in and calls finishTransaction. If you switch to airplane mode you can 'clear' those transactions for another week - but they come back.
Upvotes: 4
Reputation: 1
You know, I resolved this problem by making a modify in my updatedTransactions. I didn't add the [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
for all situations.
Upvotes: 0
Reputation: 3366
Check for the following as I had it in my viewDidLoad method. I had an app rejected when apple wanted me to go from non-consumable to consumable, however I left the following line in my viewDidLoad method: (I thought the password prompt was a issue with swapping from the test user to normal user back to the test user)
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
Once removed the request for password stopped.
And I have left: [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
in and the app has now been approved just fine.
Upvotes: 0
Reputation: 1235
bugs related to in app purchases fixed in the iOS update 5.1.1 http://support.apple.com/kb/DL1521
Upvotes: 0
Reputation: 809
Deleting and re-installing the app will remove any old transactions associated with another itunes account. If you are still seeing transactions posted to the notification queue, then you likely had some branch in your logic that did not call finishTransaction.
You need to to call finishTransaction on all transactions that are posted to paymentQueue:updatedTransactions:, even ones with SKPaymentTransactionStateFailed.
Upvotes: 0
Reputation: 336
I suspect that this is a correct behaviour. When you set a delegate SKPaymentQueue try to check if there are some transactions to finalize. There may be no not finished transactions but the fact of checking requires to login in iTunes. And I think you can do nothing with it.
It generally has some sense, but it is pretty annoying for users who have set up asking for a password on each transaction (some child protection for instance). So the only way to struggle with it is to set delegate explicitly when you are about to request iTunes. For example you can add some button like "Restore my purchases". Not very beautiful but definitely less annoying.
Upvotes: 3