I have a few questions that will help me understand things better if answered:
Is there a way to differentiate between a fresh subscription and the renewal of a previously-purchased one?
Does the subscription go through the renewal process immediately after the expires_date is hit? It seems that sometimes (in the Sandbox, at least) my subscriptions will renew 30-60 seconds before the expires_date.
Does the renewal always happen at a consistent time after the expires_date is hit? For instance, if I launch my app and expires_date has been passed, when will the renewal occur (assuming the user didn't cancel)? Or rather, when will my app know that the renewal has occurred on Apple's end?
Scenario: app is launched and expires_date has passed for one of my subscriptions. Should I send a receipt to Apple to see if that subscription was renewed, or should I wait a couple seconds to see if the renewal process occurs?
Thanks!
I will attempt to answer my own question:
To do this, I store expires_date of the subscription in NSUserDefaults once the initial purchase is completed. When the subscription expires, I remove the object from NSUserDefaults. This allows me to determine if any subsequent subscriptions are a renewal (expires_date exists in NSUserDefaults - update with new expires_date upon renewal completion) or a fresh purchase (expires_date does not exist, either because it was removed upon a previous subscription expiration or the product has never been purchased).
This question is irrelevant - what I do is compare expires_date stored in NSUserDefaults to current_date every time the app enters the foreground. If current_date has passed expires_date, I call my server to verify the receipt with Apple. Apple returns the status of the subscription to my server (0 means the subscription is valid, 21006 means it has expired, and all others are trivial as far as my app is concerned) and the server forwards it to my app. In this manner, it doesn't matter how long it takes my app to be alerted of a renewal (aka the subscription has already technically renewed through Apple but my app doesn't yet know) because I know for certain whether the subscription has expired or not.
In the sandbox, renewals seem to be very untrustworthy. Sometimes my subscriptions will renew five or six times (the standard, according to Apple), sometimes once, and sometimes not at all. For the record, the 7 day subscriptions don't renew a lot more often than the 30 day subscriptions. It would be nice to have the same reliability in the sandbox as we do in the live servers so I can write code accordingly (and stress less), but I digress. The only sure-fire and consistent way I've discovered to make the subscriptions alert my app that they've renewed is when expires_date has passed && I force close/relaunch my app. Sometimes toggling between background and foreground states works, but in my experience this is much less reliable - I have a feeling that this would work [better] in the live servers though.
What I do is check with my server (which in turn checks with Apple) when I notice that expires_date has passed. So it doesn't matter if the renew occurs before/after/never, because my server tells me for certain the status of the subscription.
I hope this information helps others who have the same questions I did!
Related
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.
I'm developing the subscription logic for my application and wondering whether the app receipt will reflect an automatically renewed subscription before the transaction has been received and marked as completed?
Scenario: subscription has expired, but user has auto-renew turned on. He opens my application, which notices subscription has expired. While waiting for the new transaction to arrive, it checks the latest receipt for the current status. Will the latest in-app purchase receipt (latest_receipt_info -> lastObject) be for the previous transaction that just expired, or will it be the new updated transaction even though that has not yet been delivered to my application and marked as completed?
Should I treat an expiration date in the past (without is_in_billing_retry_period being true) as an expired subscription, or should I wait for any new transactions to tick in?
After some testing I have determined that the latest receipt indeed does contain the most recent expiration date, despite this not being delivered to the device and marked as completed.
There was however a small overlap just after the subscription had expired where the receipt was not yet updated with the latest transaction, and as such claimed the subscription had expired despite it automatically renewing. Giving it a few minutes however seemed to do the trick, as it now claimed the subscription was still valid despite the transaction itself not being received by the application.
If anyone can confirm this or provide additional insight, I'd be very appreciative.
I'm trying to work out the best way to get updated receipt expiration when an iOS auto-renewing subscription renews. I know that what's supposed to happen is that it will be delivered via the SKPaymentQueue transaction observers. However,
This only happens when the app launches. My app is vertical market style app that might run for hours or days, so checking at launch isn't enough.
Transaction observer delivery doesn't seem to be reliable. In testing I've had subscriptions that should have renewed but where no new info was delivered to the transaction observer even after relaunching.
But of course it's also possible to get updated info on demand by revalidating the receipt with Apple. Given the above two issues, I'm thinking I'll need to run a timer that just periodically
Checks if the subscription should renew "soon", i.e. within some TBD period in the future (maybe within the next day).
If so, attempts to get updated info from Apple by revalidating the receipt.
How do other people handle this? The timer approach seems ridiculous but I haven't come up with anything better yet.
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];
We are using non-renewing subscriptions in our iOS application and are confused to when and where expired subscriptions are removed. For instance we show two subscriptions (7 days and 30 days). The user then purchases one of the subscriptions and we save that in NSUserDefaults along with storing in database on the server (creation date, subscription type, expiration date). Now the confusion we have is when the user is past their 7 days (or 30 days), how do we expire the subscription?
We were thinking of doing it in didFinishLaunchingWithOptions however what happens if the user stays logged in and never terminates their application,
I would do it in applicationDidBecomeActive. This is called every time they launch the app even if it was never terminated. I would guess you would be pretty safe with this. If someone is willing to keep your application open constantly to prevent the expiration, then they are pretty dedicated to your app! Also, most people would not know how you checked their subscription so they would probably not think to keep it open.
You should also think about storing their subscription in NSUserDefaults. What if they remove the app and reinstall it? Do you check your database and reload that value into defaults? If it is a small amount of data you could store it in the keychain. The keychain values are not deleted when the app is removed.
You could check every time the user brings your app to the foreground. To do that, do your check in the app delegate's -applicationWillEnterForeground method. If you want to go a step further, you could use that method to set up a timer that will fire when the subscription expires. That would let you expire the subscription as soon as it ends, even if the end comes while the user is using the app.