I have a problem with my Android app. I am trying to implement a monthly subscription. I have created the IAP, the app is in beta and I am register as a tester.
Everything works as expected when purchasing the subscription. I am able to purchase it as a tester, which means the subscription is not actually charged, and it also gets renewed everyday.
But here is where my problem starts. I always get the original receipt, with the original purchaseTime
and purchaseToken
. Whenever the app starts, I call queryInventoryAsync
and I expect to get the latest renewal receipt. But I always get the ORIGINAL receipt.
Is my thinking wrong? Shouldn't I be getting the renewed receipt, with the new orderID
? (as google docs say, I should get an orderID
like GPA.blabla..0|1|2
. I know there are some caching mechanisms, but I've waited for three days, and I still get the original order, while I should be getting the latest one.
I always use cordova with crosswalk, and I use the following plugin for purchases: https://github.com/j3k0/cordova-plugin-purchase . I don't know if it matters, it shouldn't as it uses the same IABHelper class used by every other plugin, but maybe it is something wrong with their code?
I logged the exact response received from the call to mService.getPurchases(3, mContext.getPackageName(), itemType, continueToken);
and it contains the wrong data (original receipt). Why? :(
Did anybody else have a similar issue? Is it because of testing the subscription? Will it work when actually buying? I already started testing with real money, but it will take a week until the subscription renews.
Thank you so much.
Edit: Clearing the cache from Google Play Store app is not an option. I cannot ask my users to do that. Also, I did test this, and it doesn't work!
Edit 2 Production subscription (real money, no testing) doesn't work either!. Still getting the original receipt!
Edit 3 I haven't solved this issue yet. What would be the correct way to detect the renewals? Should I just run a cronjob on the backend and query each subscription against Google's Purchase Status API?
Edit 4 Thank you for the answers. I am already using the Purchase Status API on the backend to determine if the subscription was renewed or not. But it kinda sucks, cause what if I get 100.000 subscriptions? The script that goes through all of them and queries Google's API will take a very looooong time .. and the script should probably run daily!
But lets clear things up.
Does this mean the official documentation is outdated?.
Are the GPA.blabla..0 GPA.blabla..1
style renewals dead?
Edit 5 December 2016 Update: I've been running subscriptions in production for a couple of months now, and I still do NOT get renewals with ..0, ..1 . What I did is setup a cronjob that runs daily. It goes through my active subscriptions and queries them against Google's Purchase API. If the API returns a different expiration date than the one saved in my database, it means the subscription has renewed.
Edit 6 July 2017 Update I still rely on my daily script, which parses all subscriptions, and updates their status by querying Google using the Purchases API https://developers.google.com/android-publisher/api-ref/purchases/subscriptions . It has been working great so far.
Edit 7 October 2018 Update Google now has real time notifications: https://developer.android.com/google/play/billing/realtime_developer_notifications
I implemented these notifications and use them together with the daily cronjob to obtain the real status and expiration date for each subscription.
A quick tip: Query subscriptions in batches! I did some tests, and I was able to bundle up to 1.000 subscriptions in the same request. The limit is imposed by the API's max response size.
If you can't find your subscriptions, check that you're signed in to the correct account. Make sure to sign in to the Google Account that has your subscriptions. Learn how to add an account or switch accounts. The email you used with the subscription app may be different than your Google Account.
As mentioned in Android Developers Blog, Account hold is a state the user enters after a renewal fails due to a payment issue. During account hold, the user loses access to the subscription while Google notifies the user and retries the payment method.
Google Play's original receipt is what you use to query Google Play's API for subscription information. Apple's IAP works very similarly. For these in-app-purchase mechanisms, you use the subscriptionId from the receipt to query Google/Apple's API to determine subscription validity.
These in-app-purchase mechanisms work like this because of fraud prevention and users can change subscription information without your app's involvement.
This is the API you should be interested in:
GET /{packageName}/purchases/subscriptions/{subscriptionId}/tokens/{token} Checks whether a user's subscription purchase is valid and returns its expiry time.
The general flow for in-app-purchase validation is:
You shouldn't trust the data returned in a receipt on the device, just the data returned from a Apple/Google remote API.
Another StackOverflow discussion on this topic: Android : inApp purchase receipt validation google play
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With