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

2

29

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.

Francoisefrancolin answered 16/8, 2016 at 11:36 Comment(7)
Can you try clearing google play app cache from device settings > applications and then test?Acuna
Thank you for your answer, however, I cannot ask my users to do that. I did test it for myself, with no results.Francoisefrancolin
Are you calling getStringArrayList("INAPP_PURCHASE_DATA_LIST") on the result of getPurchases? Is there only a single item in the array?Annadiana
Hi, yes I am calling that. For INAPP_PURCHASE_DATA_LIST I get an array of INAPP_PURCHASE_DATA, and yes, as the docs say, each INAPP_PURCHASE_DATA is a json containing the original receipt information, initial purchaseTime and initial purchaseToken. But it does not contain the renewal data, after the subscription had renewed.Francoisefrancolin
I don't think the subscription order numbers are dead, I just checked a test subscription myself and the sequence is there. It sounds like you're app is a victim of over aggressive caching and there doesn't appear to be a way to clear the cache from within the app. Try launching the play store on the device, that should load the new purchases.Annadiana
Can you confirm is this still the case?Hennessy
I don't know. I still use a daily cronjob which updates subscriptions status by querying google using the Purchases API developers.google.com/android-publisher/api-ref/purchases/…Francoisefrancolin
P
1

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

Pulsimeter answered 6/9, 2016 at 19:53 Comment(0)
N
0

You will get purchase token of initial payment.From that purchase token you have to query Google Play's API fro subscription token as subscription in app purchase is getting auto renewed.So requesting Google Play's API is the only way to get the status of Subscription in app.

Neuter answered 8/9, 2016 at 6:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.