17

I have an android app with renewable monthly subscriptions. In this app I want to notify user some info when his subcription continues in next month.

As I can see renewals in merchant center(orderId ends with eg. ..0, ..1), but when querying the inventory my purchase orderId is same as befor eq.

{
    "orderId": "GPA.XXXX-YYYY-XXXX-ZZZZZ",
    "packageName": "my.packageName",
    "productId": "my.sku",
    "purchaseTime": 1456398623654,
    "purchaseState": 0,
    "developerPayload": "mypayload",
    "purchaseToken": "token",
    "autoRenewing": true
}

What bothers me more is that purchaseTime also doesn't change.

So my question is: If there is any way to detect in app that renewal occured?

Edit:

I'm using Google Play Developer API to get subscription info and then calculate number of renewals myself.

Axxxon
  • 703
  • 2
  • 11
  • 27

4 Answers4

17

Order id for all recurrences are returned in orderId field of the INAPP_PURCHASE_DATA JSON field (in V3) with each recurring transaction appended by an integer.

Subscription order numbers

To help you track transactions relating to a given subscription, Google payments provides a base Merchant Order Number for all recurrences of the subscription and denotes each recurring transaction by appending an integer as follows:

GPA.1234-5678-9012-34567 (base order number)
GPA.1234-5678-9012-34567..0 (first recurrence orderID)
GPA.1234-5678-9012-34567..1 (second recurrence orderID)
GPA.1234-5678-9012-34567..2 (third recurrence orderID) ...

But due to local caching you might not get the latest information. So try clearing cache from application manager to first see if you get correct purchase information.

Since purchase query this way is not reliable, it makes more sense to call Google Play Developer Purchases.subscriptions: get API from a backend to get Purchases.subscriptions resource which will return expiryTimeMillis of current subscription.

{
  "kind": "androidpublisher#subscriptionPurchase",
  "startTimeMillis": long,
  "expiryTimeMillis": long,
  "autoRenewing": boolean,
  "priceCurrencyCode": string,
  "priceAmountMicros": long,
  "countryCode": string,
  "developerPayload": string,
  "paymentState": integer,
  "cancelReason": integer
}
random
  • 10,238
  • 8
  • 57
  • 101
  • What you have provided is a way to query Google Play Developer API for subscription, this can be done from the server side. But the questions states querying the inventory on device side. – Anirudha Agashe Apr 20 '16 at 09:44
  • 1
    If it cannot be checked reliably on device-side, isn't it better to try other options that helps achieve purpose which is to check if subscription is renewed? – random Apr 20 '16 at 10:00
  • Fair enough. But just so you know that in the documentation they clearly stated that the purchase details won't be returned when you query inventory if the subscription has expired or is no longer valid. I have posted the link in my answer. – Anirudha Agashe Apr 20 '16 at 10:40
  • Only if subscription has expired you won't get its purchase details. But if it is active, you will get its expiry time. If the subscription in auto-renewing, I am hoping we'll be able to calculate next recurring transaction start time using current one's expiry time. And with an auto-renewing subscription, till there is no failed transaction or cancellation, there will be an active subscription. – random Apr 20 '16 at 10:46
  • @random I've tried to clear cache of my app and even google play store app , tested on few devices(with same google account) and still I get same orderId for purchase. Is this normal? Additionaly I have a question: Are there any backend services ready for use where i supply needed information and make calls to Google PLay Developer API? I've searched and have n't found one. – Axxxon Apr 21 '16 at 09:44
  • I am not aware of any such backend service. As for order id for renewals, I just quoted official doc and implementation details which might be buggy. – random Apr 21 '16 at 10:18
  • I'm having the same issue, always the same orderId, did you manage to find a solution? – tehmaestro Aug 14 '16 at 09:24
  • How to clear the cache? My getPurchases() method still returns the purchase even after a cancel + wait. Thanks! – lorenzo May 07 '19 at 13:58
  • @random is `..0` the first payment of a new subscription? Or is the base ID the first payment of a new subscription and `..0` the second payment (the first recurrence) of the subscription? – Yu Chen Feb 19 '20 at 00:00
  • 2
    Can we please take a moment to notice how sloppy the idea of appending `..0` to the orderId is? I mean it's a json, why not add a key-value pair to the data? Instead they append a string to a important unique identifier... – krafter Nov 03 '20 at 13:09
7

The purchase data for subscriptions is returned only when the subscription is active. If the subscription expires then you won't get this purchase data when you query the inventory.

Excerpt from the link

If a recurring payment fails (for example, because the customer’s credit card has become invalid), the subscription does not renew. The getPurchases() method does not return failed or expired subscriptions.

Anirudha Agashe
  • 3,510
  • 2
  • 32
  • 47
2

You can serve in your DB the expiration date, and every time, when you are getting the data, you can check the expiration date with your db's value, and if it is later, then the subscription was renewed))

Gag Baghdasaryan
  • 716
  • 1
  • 11
  • 22
-1

I struggled to find a solution for the exact implementation of @random's suggestion. It seems to indeed be the only way to have a solid implementation for renewal tracking on Android, but I couldn't find a good approach online on how to do it. For those who want to save some time (cost me 6 hours today), please find my answer below:

1. First step is to add the dependencies:

implementation "com.google.apis:google-api-services-androidpublisher:v3-rev142-1.25.0" // Update based on latest release
implementation "com.google.auth:google-auth-library-oauth2-http:1.12.1" // Update based on latest release

2. Follow these steps to link the Google Play Console with Google Play Developer API (choose the "Use a service account", not "Use OAuth clients" and follow until "Additional information").

3. Download the services JSON file from your Google Cloud service account (click on the account that you set up in the previous step). You can find/create this file under the "Manage Keys" action or the "Keys" tab. Add the exported JSON file in your assets folder in Android

4. Then you can call the Google Play Developer API to query subscriptions like this (important to call from a Thread, didn't work from the UI thread, not sure why):

new Thread(() -> {
    InputStream inputStream = context.getAssets().open("service_account_google_play.json"); // JSON file from step 3
    GoogleCredentials credentials = GoogleCredentials.fromStream(inputStream)
                    .createScoped(AndroidPublisherScopes.ANDROIDPUBLISHER);
    AndroidPublisher androidPublisher = new AndroidPublisher(
        new NetHttpTransport(),
        JacksonFactory.getDefaultInstance(),
        new HttpCredentialsAdapter(credentials)
    );
    SubscriptionPurchase purchase = androidPublisher.purchases().subscriptions().get(
        context.getPackageName(), subscriptionId, purchaseToken
    ).execute();
    // Check the orderId or check the expiryTimeMillis for renewal check, e.g. purchase.getOrderId();
}).start();

At the risk of being overly descriptive, the subscriptionId is the ID of your subscription in the Play Console (e.g. subscription_monthly or whatever you called it), and the purchaseToken is the token you get from the Purchase token after querying the BillingClient (querying subscriptions is explained in detail here).

Jorn Rigter
  • 745
  • 1
  • 6
  • 25