Perhaps I am simply not looking in the correct places, but I am surprised at the lack of documentation around cross-platform apps incorporating renewing subscriptions.
I have a cross-platform (iOS and Android) Ionic app with a Rails API for the back-end. I am using https://github.com/AlexDisler/cordova-plugin-inapppurchase as a wrapper around the iOS/Google store SDKs.
My question revolves around subscription renewal:
From what I gather, it is recommended that I have a daily job checking each of my subscriptions for their expiration date. If a subscription is about to expire, I can send the receipt stored in my database to either Google/Apple and check if the subscription has been renewed. If it has, I update the expiration date and keep the subscription active. If the subscription has not been renewed, I mark the subscription as inactive.
Now, what happens if a user renews a subscription? How will I know that a subscription has been renewed? And when do I check for subscription renewal? Seems like my options are:
Every day, check every expired subscription for renewal. Problems with this: 1) as the number of users grows, so will the number of users with expired subscriptions. Eventually, this will result in checking many, many expired subscriptions every night. 2) A user will be unable to access subscription-only content between the time they renew their subscription through the app/play store and the nightly subscription-checking job is run.
Every time a user with an expired subscription logs into the app, check to see if they have renewed their subscription. Problems with this: 1) My app uses token authentication. Therefore, users are not required to login with each use. So, if a user renews their subscription, but their token is still valid, the app will have no way of knowing that their subscription is up-to-date.
Is there another option? What am I missing here?
I would suggest using a combination of both options.
When a user opens your app you should send a separate request to your backend that will fetch the receipt a check if its renewed and cache the expiration date and the time it was checked. Then I would have another job run nightly that doesn't check all the expired receipts, but clears the expiration date cache if it hasn't been checked within a certain period. Then, the next time a user opens the app, the cache will be empty and and will be fetched.
I'm working on adding Android subscriptions to RevenueCat but it won't be ready for a couple months.
Related
I've implemented a recurring subscription for Android In App Billing, but I'm wondering how the apps knows that the subscription is renewed. In testing, at least, the subscription is ended after 1 day. Will it be continued when the app is published on the store?
On iOS the testing subscription is renewed a couple of times. Enough to let you test when the subscription is renewed, but what is the best way to do this on Android?
Can I use the purchaseToken to let my server query Google Play API or do ever renewed subscription get a new purchaseToken?
In android IAP, The purchase token expires when the user manually cancels the subscription or disables the auto-renew. Otherwise, you will get a valid purchase token every time. In test mode, the tester's subscription automatically gets expired after 5 minutes but in production, it will work fine. So don't get worried about the production behavior. If you are running the app as a tester, you will get the below payment modes on the payment flow start.
You will have 2 options to test your implementation
Test Card(Always Approves)
Test Card(Always Declines)
By testing both of the cards, you can be sure about the implementation. Your app should be capable of handling both responses from IAP. If both flows goes well, You shouldn't be worried about it. You are ready to roll-out it on production. Here is the Official Docs, may help you to understand the entire flow.
If you designed custom flow to manage IAP, You can verify the IAP Token from backend using the Google Play Developer API and allow the user to consume the feature accordingly. For the custom flow, You can send custom JWT token from backend according to IAP Token expiry and set custom JWT Token exp claim. By using this method you can check the custom token is expired or not in the client-side, If it's happened so, You can fetch the new IAP token and send it to your backend. Your backend should validate that IAP token and issue new JWT token to user and cycle goes on. Let me know if you want the custom flow, I'll post it here.
You simply periodically query the Google Play server to check the items that the user own, if it is a subscription, it will reply that he/she owns it while it is active and therefore has not expired.
Do not forget to verify the signature of the received data, and much better using a server side verification
Android - protecting in app purchases with server side verification
I would like to let users purchase a good for 3 months for one time.
In subscriptions, even the user can cancel a subscription, since the cancellation of purchases is not possible inside application and the way to cancel a subscription is not straight-forward i think this would return us with a lot of user complaint due to forgotten subscription fees.
Managed product purchases are permanent so they don't work in my case.
Is there a way to make one time purchases with expiry date?
There are no such products out of the box. You have to implement it in your backend. You may use managed product and handle expiration date manually in the app with synchronization with your server.
You may try to hack it without backend comparing purchase date and correct current time (some trusted time server).
About to build a subscription product into our Android app, but a little unclear on the best way to know about canceled subscriptions. The only way we are planning on letting the user cancel is for them to go to Google Play Store and explicitly cancel, but in this case, our backend won't be notified.
The Google Play Developer API docs explicitly say you must not query the API for the status of all subscriptions so how are we supposed to know which users have cancelled their subscription?
Any help much appreciated!
According to In-App Subscription documentation there is no mechanism to detect when the user cancels the subscription. Since it is not canceled immediately. Instead it waits for the end of the cycle for the subscription to expire.
Excerpt from document (source)
When the user cancels a subscription, Google Play does not offer a
refund for the current billing cycle. Instead, it allows the user to
have access to the canceled subscription until the end of the current
billing cycle, at which time it terminates the subscription. For
example, if a user purchases a monthly subscription and cancels it on
the 15th day of the cycle, Google Play will consider the subscription
valid until the end of the 30th day (or other day, depending on the
month)
The app won't receive any kind of notification when user cancels the subscription.
The behavior of subscription is whenever you query the inventory in the app SKU will be returned if subscription is valid. When the subscription expires the SKU won't be returned when you query the inventory.
According to the documentation in this link
It is okay to run a batch query whenever subscription is nearing the end
Excerpt from document (source):
Query for subscription status only at expiration — Once your server
has retrieved the expiration date of subscription tokens, it should
not query the Google Play servers for the subscription status again
until the subscription is reaching or has passed the expiration date.
Typically, your servers would run a batch query each day to check the
status of expiring subscriptions, then update the database
The following server api lets you query the subscription status:
https://developers.google.com/android-publisher/api-ref/purchases/subscriptions#resource-representations
The variables autoRenewing and cancelReason will let you know if the subscription has been canceled.
By using the above API you would be able to implement a system wherein the subscription nearing expiration can be queried for status and then determine whether they are canceled or not.
Full details for subscription cancellation can be found at this link.
Note:
Documentation states that you should continue to provide the content as long as the user has valid subscription. If you are planning to deny access to the content if someone canceled the subscription will go against the Google Policy
Excerpt from document (source)
Important: In all cases, you must continue to offer the content that
your subscribers have purchased through their subscriptions, as long
any user is able to access it. That is, you must not remove any
content while any user still has an active subscription to it, even if
that subscription will terminate at the end of the current billing
cycle.
It looks like it's now possible to receive server-side notifications about subscriptions changes (renewal, cancellation...):
The In-app Billing API provides server push notifications that give developers the capability to monitor state changes for Play-managed subscriptions.
See this page for more details: https://developer.android.com/google/play/billing/billing_subscriptions.html#realtime-notifications
Before I explain my question, let me give an example situation.
A user of a magazine app subscribes to the monthly subscription on the month of August and September. If the user reformats the phone, the app should be able to restore both August and September month's magazines.
The problem with this is that, the In-App Billing API returns only the latest subscription and whether the subscription is active.
Also, I want the users to be able view the previous months' magazines even if they have canceled their subscription.
Is there a way to keep track of all payments made by the user?
This likely would involve your own independent servers and "developer payload" information. As stated in this Subscriptions link:
Include business logic in your app to notify your backend servers of subscription purchases, tokens, and any billing errors that may occur. Your backend servers can use the server-side API to query and update your records and follow up with customers directly, if needed.
In other words, you should be keeping track of this--unfortunately.
Further, you can check this api reference as to whether a user's subscription purchase is valid.
There is a "Subscription with Free Trial" in my android app, and the BillingService would get the Purchased status after buying subscription product.
But, the BillingService does not get the Expired status after canceling the subscription.
However, accroding to Android Developer,
"If necessary, the user can cancel the subscription at any time during
the trial period. In this case, Google Play marks the subscription as
expired immediately, rather than waiting until the end of the trial
period."
but My app does not get the status.
I wonder that When does android app get the "Expired" status after canceling the subscription during the trial period.
I've noticed this too. In my case the purchase state only changed at the end of the (7-day) trial period even though I cancelled within minutes of purchasing the trial subscription.
I'm currently waiting for another cancelled trial to expire - it's been 3 days now and the purchase state is still 0 ("purchased successfully").
Update:
So it seems you either need to restore transactions periodically (Google says you should not do this "because of performance impacts") or you need a web-server with code to check the subscription details using the the server-side API http://developer.android.com/google/play/billing/v2/billing_subscriptions.html#play-dev-api. Your app would then query your web-server which would only check with Google's services when the expiry date has been reached.
I have tested this case in a non-test environment, i.e. productive environment.
I received a ACTION_PURCHASE_STATE_CHANGED notification with EXPIRED state some 4 hours after cancelling the subscription. (I've cancelled the subscription a few minutes after the purchase. Trial period is 7 days)
Trying to re-purchase the subscription after the EXPIRED notification returned "Already owned" a couple of times, and after that I was able to re-purchase (without the trial period, as documented).
I do not have the Google server API implemented, so I don't know what would the status be. However, on the Merchant site, the order and the Order CSV download show the item as CHARGED.
So, what has changed since the previous answer?
Productive environment vs Google test environment
Possibly a Google bug fix
Once I implement the Google server API query, I will update this answer.
UPDATE:
I have implemented the Google Server API check, and it shows correctly that the subscription was cancelled a few minutes after the purchase. This API check was done 3 days after purchase, well within the 7 days trial.
My conclusion at this point in time is that user cancellations within the trial period are handled correctly by Google.