Renewal transactions not arriving on device?

I am trying to implement an auto-renewable subscription for the first time and I'm having so much trouble with erratic behaviour from the Sandbox environment that at this point, I'm not sure if the behaviour I'm expecting is correct or not. I can't seem to get two tests in a row to behave the same way.


I'm registering an SKPaymentTransactionObserver observer ASAP on startup, I can create a subscription and it arrives properly (after several retries but lets ignore that for the moment), then I wait 5-6 minutes expecting that some background process will add a renewal transaction to my SKPaymentQueue before the expiry time of the subscription.


If I then restart my app, sometimes (but not always), the renewal transaction will be delivered to my SKPaymentTransactionObserver after the restart and the subscription then works correctly until the next expiry.


At that point, restoring purchases usually works, but that's not been reliable either because of frequent errors just connecting to the App Store.


So what's the story here? Have I missed some step somewhere to get those renewals delivered to the device?

Answered by PBK in 413916022

Your app will get hit with a call to updatedTransactions when it enters the foreground as long as you left a transaction observer in place. If you removed the transaction observer (I do that) then your app will be hit with a call to updatedTransactions when it adds a transaction observer. I do not know whether there will be a call to updatedTransactions if the app is in the foreground when a renewal transaction is approved. Certainly it is called when it is in the foreground and there is an original purchase.


In the edge case of that renewal transaction being approved while the app is in the foreground - should it not result in a call to updatedTransactions - you can ignore the discrepency between Apple's records and the app's records. The discrepancy will continue after the app enters background and will be aligned the next time the app enters foreground.

In the sandbox, with time speeded up, you get only 5 renewals for any test user. Then it stops renewing. In the past, that test user never got any more renewals. More recently (I haven't tested it in a few months) a test user gets reset and after 24 hours they would get 5 renewals if they subscribed again.


You need to have an observer to get a call to updatedTransactions. If you removeTransactionObserver it won't work.


You need to finishTransaction on every transaction otherwise the system does crazy things.

Ok I've double checked those things and I had them all covered.

My remaining question is, should I be expecting the transactions to just appear in SKPaymentQueue when Apple processes the renewal or do I need to schedule as task of some sort to check for renewals?


I'm aware of server to server notifications and those are on my to do list, but I'm looking for clarity on the expected on-device behaviour.

The expected behavior is to add a transaction observer (addTransactionObserver) and await a call to updatedTransactions. Once you get a call to updatedTransactuions you can inspect the receipt to verify the accuracy of the information coming into updatedTransactions.

So the problem is that's not happening when I think it should. updatedTransactions is not getting called. If the app is running and the foreground, the expiry time passes and nothing happens.


It seems that the renewal does happen on apples end, because I am able to use restore purchases to get the transaction, but if the app is running and in the foreground, I don't get the transaction. Sometimes it arrives on startup if I restart the app, sometimes it doesn't.

When exactly should the renewal transaction arrive on the SKPaymentQueue?

When developing for Auto-Renewal; this was a common problem that I ran into. I wouldn't always receive all 6 transactions. More often I'd receive just the first one, then nothing else. Sometimes it would 3 or 4.


In the end I re-wrote my whole system with the aim of capturing enough information to try to determine if this was my problem or Apple's. I stored the date and time of the last unexpected restored transaction, (you know when the user has tried a restoredCompletedPurchases as you request that, so when you get a restoredTransaction that wasn't trigger by this, then it's highly likely it's a Auto-Renewal).


I then displayed a screen to the user, showing this information and when the receipt was last updated. I then offered the user a series of numbered options.


1. Restore Purchases.

2. Refresh Recipt.

3. Manually Renew.

4. Contact us.


When the user clicked on Contact Us, it provided all this information and a human readable version of IAP transactions in the receipt, also what steps the user had tried to get this to work. I used a mailto: url, which would then create an e-mail in the users prefered e-mail client, allowing the user see exactly what information is being shared with us.


I never got to see how this performed in the real world as Apple rejected my usage of Auto-Renwal and told me I need to make it non-Renewal Subscriptions, to which I'm currently stuck as on a brand new 16" MacBook Pro I can't renew a subscription.


> When exactly should the renewal transaction arrive on the SKPaymentQueue?

I found when it works, the only time I received a transaction was on application launch. But it can take several minutes to proogate.


Hope that this helps.

Again, don't look for it in the queue. Look for it as a call to updatedTransactions which should occur as long as there is an observer. I never look in the queue for transactions. I always rely on a call to updatedTransactions when I add an observer.


You are worrying about an edge case that is never significant in production but might be an issue in the sandbox - although I recall it worked just fine in teh sandbox. In production the renewal is sent many hours before expiration. Therefore, unless the user keeps the app in foreground for those many hours they will always be able to process the renewal when they first enter foreground. As long as there is an observer present, or as soon as you add an observer, the transaction will cause a call to updatedTransactions.

I do see your point about this being an edge case, but that's not exactly what I'm worried about. I've been all over the documentation and WWDC videos and I haven't been able to find clear information anywhere about the timing of when and what triggers these transactions to actually arrive in updatedTransactions. Without that information, I'm left to guess about what a successful test looks like.


I think you may have just touched on it, but I'd like to be sure - are you saying that these transactions are normally added to the queue when the app enters the foreground, but it is normal that nothing would happen if the app is in the foreground when the subscription period expires? Does it normally require a full restart, or is it sufficient to drop out to the home screen and then flip back to the app?

Thanks Rowlands - its helpful to know that I'm not the only one tripping up on this. I think the underlying problem here is that the expected behaviour isn't laid out clearly enough in the documentation. The sandbox adds a lot of unique quirks to the process, and coming up with a satisfactory QA test plan is very difficult without that clarity.

Accepted Answer

Your app will get hit with a call to updatedTransactions when it enters the foreground as long as you left a transaction observer in place. If you removed the transaction observer (I do that) then your app will be hit with a call to updatedTransactions when it adds a transaction observer. I do not know whether there will be a call to updatedTransactions if the app is in the foreground when a renewal transaction is approved. Certainly it is called when it is in the foreground and there is an original purchase.


In the edge case of that renewal transaction being approved while the app is in the foreground - should it not result in a call to updatedTransactions - you can ignore the discrepency between Apple's records and the app's records. The discrepancy will continue after the app enters background and will be aligned the next time the app enters foreground.

Tthanks that's the info I was after!

Supplement to edge case comment:


I think you are correct and the transaction hits updatedTransactions only:

1) when the app enters foreground with a transaction observer having been added beforehand

2) when a transaction observer is added

I am having the exact same problem as @derekst991
what is the conclusion to this?

Can I trust that after setting up my transaction observer and performing all the correct steps that updatedTransactions should get called in production even though this is failing with the sandbox?
Renewal transactions not arriving on device?
 
 
Q