Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android In App Subscription always returns the initial receipt, I never get the renewal

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.

like image 470
tehmaestro Avatar asked Aug 16 '16 11:08

tehmaestro


People also ask

Can t Confirm subscription on Google Play?

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.

Why is my Google Play account on hold?

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.


1 Answers

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:

  • Validate receipt with Google/Apple
  • Query for purchase data from Google/Apple based on the subscription identifier

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

like image 76
pranspach Avatar answered Sep 27 '22 22:09

pranspach