56

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:

  1. Is anyone else seeing this?

  2. 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:

  1. How can I prevent such dead transactions (transaction has not been finished, user has no network, meanwhile changes App-ID)?
  2. How can you prune the SkPaymentQueue?
Cœur
  • 37,241
  • 25
  • 195
  • 267
montuno
  • 867
  • 1
  • 7
  • 15
  • I've been experiencing this as well. – Aloha Silver May 03 '11 at 15:13
  • 1
    It must depend on some Transaction that has been interupted with another AppStore-Account: http://stackoverflow.com/questions/6971740/in-app-purchase-sign-in-to-itunes-store-after-skpaymentqueue-defaultqueue-a. The User has to try all AppStore-Accounts he ever used and if he finds the right one, the Message won't appear again. But that cannot be the solution. It has be ensured, that no transactions with old/former AppStore-Accounts pop up. Maybe that is an Apple "Bug"? – Rene Berlin Oct 19 '11 at 15:15
  • Where have you added your transaction observer? – βhargavḯ May 23 '12 at 08:41
  • @montuno How did you end up fixing this issue? – SAHM Jul 21 '12 at 20:55
  • Sometimes iTunes on the test server acts a little wonky. In my app, it would keep asking for verification after I called `[[SKPaymentQueue defaultQueue] addTransactionObserver:paymentProcessorDelegate];`. It does this sporadically, _and only today_, so I'm expecting the problem to "fix itself" somehow later. – bobobobo Dec 08 '13 at 05:12
  • Apple provides some Best Practices on that: https://developer.apple.com/library/content/technotes/tn2387/_index.html – Cœur Jun 29 '17 at 14:52

14 Answers14

32

I had the same problem.make sure that you call

[[SKPaymentQueue defaultQueue] finishTransaction:transaction]; 

for all three states of the transactions: SKPaymentTransactionStatePurchased, SKPaymentTransactionStateRestored, SKPaymentTransactionStateFailed.

blwinters
  • 1,911
  • 19
  • 40
Ilker Baltaci
  • 11,644
  • 6
  • 63
  • 79
  • 3
    Yeah but I'm not even _getting_ any transactions. I even inserted delegate for each of the [5 SKPaymentTransactionObserver delegate methods](https://developer.apple.com/library/ios/documentation/StoreKit/Reference/SKPaymentTransactionObserver_Protocol/Reference/Reference.html). The iTunes store asks me to sign in _every time_ I start my app now.. – bobobobo Dec 09 '13 at 01:15
  • Troubled by the same issue, this helped me so much! – pipipi Jun 19 '14 at 16:05
  • Situation: you had registered some testuser1@t.com and tested IAP with it and not finished some transaction. Then you registered testuser2@t.com. So, if you open app (be wanting to test it with testuser2@t.com), you will see dialog with input credentials for testuser1@t.com! Even if you delete testuser1@t.com user from ITC - this dialog will appeared again, until you input correct credentials for your old user (testuser1@t.com). After this dialog willn't appear! It is working for me – iVader Mar 21 '16 at 07:38
8

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:

  1. Run your app from Xcode.
  2. Wait for the prompt to come up. Type in the password for the account it wants and tap OK.
  3. Press the Home button on the device.
  4. Kill the app from Xcode.
  5. Delete the app from the device.
  6. Log out of iTunes & App Store in the Settings app.
  7. Turn off the device and then turn it back on.
  8. Purchase something from the App Store. When it prompts you, log in with a production Apple ID account. (I'm assuming you should be able to just log in with a production account in iTunes & App Store under the Settings app but this is how I did it).
  9. Go back to Xcode and run your app again. (This should be a new install, as you deleted the app before.)
  10. Wait for the login prompt to come up.
  11. Tap Cancel. A dialog saying "Sign In Required. Tap Continue and sign in to check for downloads. [Environment: Sandbox]" should come up. This was a key difference from before. I never had this dialog come up when I pressed Cancel when it was asking me for the password.
  12. Tap Continue.
  13. Enter the password for the account.

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!

Aero
  • 390
  • 5
  • 9
  • 1
    Worked for me. Steps 11 through 13 are the critical steps that solve the problem. I am not certain which or how many of steps 1 through 10 are necessary to trigger it. For the record, I did not remove the test sandbox account (Step 0) and I did not purchase anything from the App Store (Step 8). I did log in with a production account in Settings instead though (as suggested in Step 8). – Mark A. Durham Sep 01 '15 at 14:47
  • 1
    I just did 1 to 10,and then in 11th step i tapped on cancel,thats it.It really worked :) – Infaz Jul 28 '16 at 11:45
  • The docs for `addTransationObserver:` state "This may require that the user authenticate." - so this is seemingly correct/expected behavior if you call that method. – pkamb Oct 28 '19 at 21:37
8

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:

  • Delete the sandbox test user. This makes it impossible to resolve the problem and you will have to contact Apple developer support to resolve manually.
  • If you delete the sandbox test user, when you are subsequently repeatedly prompted to log in as that user and complete the transaction, you can't, hence the name Endless Loop problem. Nor will you be able to add the deleted test user again; the developer portal says the user id has already been used.
  • Delete the App or re-install iOS or any other such nonsense. It has no effect, doesn't solve the problem and wastes a lot of time.

DO:

  • Call Finish for 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:

[[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.

Cliff Ribaudo
  • 8,932
  • 2
  • 55
  • 78
  • 1
    Not really sure why people are down voting this?! Clearly the people down voting are either ignorant of the facts or simply vindictive. As a long time iOS Developer and someone who was recently seriously messed up by one of the answers here to "Delete Test Users" I assure you, DON'T DO IT. – Cliff Ribaudo Jun 22 '16 at 09:26
  • I guess people downvote because it is not stated clear enough that you suggest finishing all transactions as a temporary solution while testing/debugging. Some other people might use your suggestion and their app will go into production with .deferred or .purchasing states being cleared right away (which is not good for app in Production). – Vitalii Jan 30 '17 at 19:15
  • What are you talking about?! I don't suggest finishing transactions is a TEMPORARY solution. One must always finish the transaction regardless of if in testing or production.... so if YOU down voted perhaps you should reconsider that or show me exactly where it indicated it was temporary. – Cliff Ribaudo Feb 03 '17 at 15:50
  • 1
    Cliff, I didn't downvote. I upvoted 'cause your answer helped me. The answer is bold, that's why I made a guess on your question "why ppl downvoting?"... You are definitely right that the app should be designed (and well tested) in such a way that all transactions do end up being finished after all, otherwise things go bad. My guess is that some people might have read your suggestion literally - they could try finishing everything right away in the paymentQueue(_:updatedTransactions:) and were disappointed, because they were finishing transactions in "purchasing" and "deferred" states. – Vitalii Feb 03 '17 at 21:21
  • Ok, I understand now ;) Some people did down vote it for some reason. Not sure why as it is actually the most correct answer. A lot of developers first reaction when they run into trouble is to delete the sandbox user and that will be trouble. – Cliff Ribaudo Feb 06 '17 at 13:57
  • I know this is an old answer, but it is helpful - particularly the "Do Not" section. @CliffRibaudo, I think the misunderstanding is people confusing where you say "all transactions" for all states. Transactions have to be "finished" on the queue for the "Purchased", "Restored" AND "Failed" states. Attempting to finish at any other states will throw an exception. – siburb Nov 25 '17 at 04:40
4

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.

Peter B. Kramer
  • 16,385
  • 1
  • 16
  • 20
  • That sounds very similar to a problem I had that existed way before auto renewables existed. Unfortunately those popups were tied to MY personal main account, so I had them show up like every once a week or more and I had to press cancel like 30-50 times before they gave up. After many years I was able to fix it by going back to a past test app I had been testing IAP implementations with. Creating that app again with the same bundle identifier, I was able to catch some really old unfinished transactions, finish them off, and the problems I had **a few years** were then gone. – Jonny Sep 01 '16 at 02:27
3

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.

Maxim Lavrov
  • 326
  • 5
  • 14
  • I actually did the same thing with an app I helped develop. Probably the easiest solution. – F.X. Jul 12 '12 at 20:46
1

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:

  1. input the password for each account no matter how many times app store ask for--I input 6 times for 3 account--until it never ask again.
  2. go to the setting and sign out the apple ID.
  3. quit the app normally--don't terminate it in Xcode. then kill the process in task list.
  4. remove the app from device (simply remove the app won't work it'll still ask for password )
  5. reboot the device
  6. Run the app again from Xcode/in your case reinstall the app from app store.

inspired by Expected sequence when using iTunes test user

pkamb
  • 33,281
  • 23
  • 160
  • 191
highwing
  • 111
  • 5
1

Here's how I can consistently reproduce and resolve this issue:

iOS 8.4, development build of the app.

  1. Use a test(sandbox) Apple Account.

  2. Restore purchased transactions.

    [[SKPaymentQueue defaultQueue] restoreCompletedTransactions]
    
  3. Immediately close the app.

  4. Log out of test account (through settings)

  5. 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.

pkamb
  • 33,281
  • 23
  • 160
  • 191
user3335999
  • 392
  • 1
  • 2
  • 17
1

If anyone is seeing this and is using GoogleMobileAds.framework then you may also need to call

[GADMobileAds disableAutomatedInAppPurchaseReporting];

in -application:didFinishLaunchingWithOptions:

0

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.

pschwamb
  • 809
  • 6
  • 11
0

bugs related to in app purchases fixed in the iOS update 5.1.1 http://support.apple.com/kb/DL1521

user513790
  • 1,225
  • 1
  • 13
  • 22
0

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.

timv
  • 3,346
  • 4
  • 34
  • 43
0

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.

Hannes
  • 3,752
  • 2
  • 37
  • 47
linka
  • 1
0

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)

Maciek Czarnik
  • 5,950
  • 2
  • 37
  • 50
  • 1
    This is BAD ADVICE. NEVER, EVER delete the sandbox test user. The simple solution is to call [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; If you deleted the test user you will be unable to do that and go into the "Endless Loop" IAP hell that can only be resolved via a TSI – Cliff Ribaudo Jun 11 '16 at 10:00
  • Thats not true @CliffRibaudo – Maciek Czarnik Jun 11 '16 at 10:01
  • Yes it IS true. NEVER, EVER, EVER, delete the sandbox test user in an effort to try to resolve incomplete IAPs. Read the numerous posts on "Endless Loop" problem on Apple Developer forums. You should actually delete this answer is it will create problems for people who follow it. – Cliff Ribaudo Jun 11 '16 at 10:35
  • @CliffRibaudo you're underestimating my knowledge and the fact, that sometimes IAP sandbox acts weird. I know about -finishTransaction: (obviously) and in most cases it works, but what you see in documentation is NEVER, EVER, EVER 100% how it looks like in reality. Actually you should have known that as an experienced (I believe) developer – Maciek Czarnik Jun 11 '16 at 11:01
0

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.

Community
  • 1
  • 1
pkamb
  • 33,281
  • 23
  • 160
  • 191