How to properly handle renewal of the autorenewable subscriptions (iOS) - ios

Found this statement in apple documentation:
After a subscription is successfully renewed, Store Kit adds a
transaction for the renewal to the transaction queue. Your app checks
the transaction queue on launch and handles the renewal the same way
as any other transaction.
If I only do this on start:
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
Nothing happens - subscription is not renewed (using test mode).
if I add
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
Then it runs over complete history of purchases which is also not what I want.
What is the proper way to handle it?

One thing you need to understand, when testing auto renewable subscription in sandbox environment, sometimes the subscription doesn't get renewed and you don't get renewal calls from the Store.
This is normal in sandbox and calling restoreCompletedTransactions in sandbox environment sometimes it trigger the renewal on the Store. The duration for the subscription itself is different in the sandbox: Here is a table of duration in sandbox:
Just add [[SKPaymentQueue defaultQueue] addTransactionObserver:self] when your app launches and in production it will get renewed and you will get calls.

Apple in-app purchase storkit document:-
After a subscription is successfully renewed, Store Kit adds a transaction for the renewal to the transaction queue. Your app checks the transaction queue on launch and handles the renewal the same way as any other transaction.
Which means,
If user's subscription is auto renewed and at that time our app is not running, Apple added that renewed transaction in transaction queue. So when you will opened app, we can get those renewed transaction details from transaction queue.
There is another statement mentioned in storekit document like:-
Note that if your app is already running when the subscription renews, the transaction observer is not called; your app finds out about the renewal the next time it’s launched.
Solution: How to handle auto-renewal subscription?
According to Apple storekit best practices, we should add below line in AppDelegate's "didFinishLaunchingWithOptions":-
SKPaymentQueue.defaultQueue().addTransactionObserver(SubscriptionObserverClassReference)
& for verifying subscription, Two ways available:
1) Using Server: Set cron job that verify user subscription arounds user's subscription expiration date. So we can identify user subscription renewed or not based on expiration date.
2) Using StoreKit Observer:- Every time when user subscription is renewed, we get renewed transaction information. So based on that we can take action accordingly.

The commentors and documentation were right: it is sufficient to add transaction observer to the PaymentQueue on start. In my case the renewal has not been triggered for the Sandbox User I used the whole time. I created the new one and it worked!

For my case, in sandbox testing for subscription, it will only auto renew the subscription for 5 only on the FIRST subscription purchase. Subsequent subscription purchase will stop renewing after purchase. The only way to test is to recreate a new sandbox user and test again. Rinse and repeat!

Related

Never Get RENEWAL Notification Type on Apple statusUpdateNotification

I created an API to be called by Apple webhook to work with subscription. I've set the API url in Itunes to be called by the webhook.
According to Apple help site https://help.apple.com/app-store-connect/#/dev7e89e149d in regards to the Testing Auto-Renewable Subscription, when testing auto renewable subscriptions in the test environment, the Apple webhook will make a call to the API after 5 minutes if I select 1 month subscription duration.
But the thing is, after making first purchase, apple webhook doesn't follow up call to the API that I created to renew the subs. Even after I waited for more than 5 minutes. So I can't do any processing from the API to renew user subs in the database.
Is there some configuration that I had to make in order to test the auto renew and make apple webhook call the API to renew the sub?
We've found that Apple's subscription update webook calls are rather unreliable.
Based on experience:
Don't count on Apple to notify you of renewals. The notification may arrive arbitrarily late (often leaving a "gap" in time), or not at all. We've resorted to retaining and retrying the original iTunes-provided receipt to revalidate renewals at the end of subscription periods --the expiration dates will change to account for the renewal.
Don't count on Apple to notify you of cancellations, either. Same as above, calculate subscription duration, and retry receipts at the end of a period (the expiration date will NOT be updated if the subscription is cancelled).
Generally, this involves mapping the additional transactions/in_apps that are returned with the retried receipt to the original_transaction_id --and updating the expires_at accordingly on your end.
Hope this helps!
Update: In WWDC2020 Apple announced that they add a new notification type called DID_RENEW which will be sent after any successful auto-renew. More info on that in this video, starting at around 16:00.
Original answer:
I can't find the page you linked to, however this page may shed light on the subject (emphasis by me):
The App Store attempts to charge the user account 24 hours before an auto-renewing subscription expires. If the renewal is successful, there is no server-to server notification because the auto-renewing subscription did not enter into the expired state. However, in the few cases that iTunes is unable to renew the subscription (generally there was a connection problem with the credit card server) and the auto-renewing subscription is not renewed before the expiration_date passes, the auto-renewing subscription is technically considered expired. iTunes may continue to attempt to renew the subscription. If iTunes is successful, then the RENEWAL event is sent.
Meaning, you're not supposed to receive notifications for renewals, but only for cases where the subscription became expired and only then renewed. This might be the case for sandbox renewals as well.

How to restore and verify auto-renewable subscriptions?

First off there seem to be many questions on SO regarding this topic but most seem outdated and not considering APIs that are available in iOS 9.
1) How are purchases restored?
When a user taps the Restore Purchase button for auto-renewable subscriptions on >=iOS 9, should a SKReceiptRefreshRequest or SKPaymentQueue.defaultQueue().restoreCompletedTransactions() be called? Currently I verify the receipt file to determine the active subscription and parse for the latest_receipt_info, is a receipt file also created on the device when restoreCompletedTransactions is called?
2) How can an auto-renewable subscription be verified?
To verify that an auto-renewable subscription on >= iOS 9 is still active and not cancelled I would call SKReceiptRefreshRequest every time the user launches the app. But the docs say:
Include some mechanism in your app to let the user restore their
purchases, such as a Restore Purchases button. Restoring purchases
prompts for the user’s App Store credentials, which interrupts the
flow of your app: because of this, don’t automatically restore
purchases, especially not every time your app is launched.
Should I call it only once a day or is there another way to verify the subscription?
Update:
For 2) just found this here:
Perform receipt validation immediately after your app is launched,
before displaying any user interface or spawning any child processes.
Implement this check in the main function, before the
NSApplicationMain function is called. For additional security, you may
repeat this check periodically while your application is running.
Apparently the receipt can be validated without user interaction. It is even recommended to do it on one's own server for security purpose. So as long as the receipt is validated by the App Store server there is no need for a receipt refresh request.

iOS in App purchase Auto-renewal sandbox transaction state

I am testing auto renewing subscription in the sandbox environment and each time it gets renewed, it seems to fire off SKPaymentTransactionStatePurchased state. I did some searching and found this post - Do auto-renewable subscriptions send an SKPaymentTransactionStatePurchased transaction when they auto-renew?. The poster replied that auto renewal fires off 'SKPaymentTransactionStateRestored'. I was wondering if anyone can clarify on why the poster is seeing different state than I am or this have changed?
Also, for my situation that auto renewal fires off SKPaymentTransactionStatePurchased state, is there a way I can differentiate whether the user purchase the subscription first time or it is a renewal?

How to get a full list of user's in-app purchases/transactions from iOS App Store?

Here is my situation: in my app I have a set of consumable in-app purchases. All purchases sent to server to be validated and activated. But there is a possibility to encounter situation when user performed a purchase (paid money) but something happens during purchase activation (lost connection, server error, etc). In result both app and server do not know about purchase (lets take situation that app lost purchase data for some reason). So I need to get user's purchases/transaction from app store.
I've tried [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
but it does not return consumable purchases.
Is there any way to get a list of all purchases/transactions from app store?
Two possibilities:
1) If the interaction fails with your server, don't finish the transaction (ie, don't remove the transaction from the queue). That way your transaction observer will get it again and you can try your server again.
2) Finish the transaction, but store enough info on the app (eg, NSUserDefaults) to try again with the server later. You can start a timer that will try again later.

iOS In-App Purchasing and Detecting Auto-Renewable Subscription

I have a couple questions regarding the process of detecting that a subscription has been auto-renewed.
Currently I have my sandbox test environment all set up, I am able to purchase a 1 month subscription and all of that works nice and dandy.
My questions are as follows:
Do I need to verify the initial receipt (or really any subsequent receipts) of the in app purchases? If so, for what reasons?
Does my app get notified via a paymentQueue:updatedTransactions: call when the auto-renew has happened? Both in the sandbox environment and in the production environment.
So far, I have not seen the StoreKit notify me of a renewed subscription (in the sandbox environment) but I have also read that it is finicky and might not.
Any general tips with Auto-Renewable subscriptions that I should take into account?
Thanks for your help and time!
1. Regarding Receipt Validation
Receipt validation is your means of performing extra security checks before you unlock the users content. Think of a receipt as a lotto ticket. A client comes to you with the "Winning Ticket". Depending on how valuable you consider the reward to your Lottery you can either give said individual their winnings, or you can contact Apple and check whether the user actually purchased this ticket through them.
The client could have got this lotto ticket through some malicious means be it a jail broken device etc and so its really up to you to decide whether you want to verify the receipt or not.
2. Regarding Renewal Notification
The official documentation states the following:
After a subscription is successfully renewed, Store Kit adds a
transaction for the renewal to the transaction queue. Your app checks
the transaction queue on launch and handles the renewal the same way
as any other transaction. Note that if your app is already running
when the subscription renews, the transaction observer is not called;
your app finds out about the renewal the next time it’s launched.
So you should definitely be getting receipt renewal notifications in your app. Don't forget that you should always add yourself as the observer of StoreKit's paymentQueue in order for this to work, something like this in your app delegates didFinishLaunching would work:
//where YourObserver is an object that is alive for the apps lifecycle
[[SKPaymentQueue defaultQueue] addTransactionObserver:YourObserver];

Resources