5

I'm using Google Billing and trying to understand if subscription is expired or not with two solutions:

  1. billingClient.queryPurchaseHistoryAsync(BillingClient.SkuType.SUBS) { billingResult, purchasesList -> }

  2. val purchasesList = billingClient.queryPurchases(BillingClient.SkuType.SUBS).purchasesList

And they returns something like that:

{
  "productId": "weekly_with_trial",
  "purchaseToken": "someToken",
  "purchaseTime": 1563305764597,
  "developerPayload": null
}
{
  "orderId": "GPA.3380-7704-5235-01361",
  "packageName": "com.myapp",
  "productId": "weekly_trial_trial",
  "purchaseTime": 1563305764597,
  "purchaseState": 0,
  "purchaseToken": "someToken",
  "autoRenewing": false,
  "acknowledged": false
}

Both of them return me a list of purchases without any info about if it expired or not. How to check it ?

VLeonovs
  • 2,193
  • 5
  • 24
  • 44

2 Answers2

13

As the documentation of Google play billing clearly suggest's that there are two function to get Purchases List

val purchasesResult: PurchasesResult =
        billingClient.queryPurchases(SkuType.INAPP)

When you do a query purchase only active subscriptions appear on this list. As long as the in-app product is on this list, the user should have access to it.

This means that if the purchase is expired then you will not get that purchase item in the response for queryPurchase. However you have to keep in mind that it returns the local cached result of google play store.

So in order to get the purchase request from network call you need to use an asynchronous method, which is queryPurchaseHistoryAsync()

billingClient.queryPurchaseHistoryAsync(SkuType.INAPP, { billingResult, purchasesList ->
   if (billingResult.responseCode == BillingResponse.OK && purchasesList != null) {
       for (purchase in purchasesList) {
           // Process the result.
       }
   }
})

However there is a catch in object that contains info about the most recent purchase made by the user for each product ID, even if that purchase is expired, cancelled, or consumed.

So you can use queryPurchase() to get all active purchases.

Rajat Beck
  • 1,523
  • 1
  • 14
  • 29
  • 1
    How much time takes when subscriptions will be removed from list after I cancel it ? I have purchased a weekly subscription and removed it after, waiting for 1.5 hours and it is still in response – VLeonovs Jul 18 '19 at 06:26
  • Try clearing your play store cache and check again. – Rajat Beck Jul 18 '19 at 10:59
  • 5
    Buuuut, how can I use it in production? – VLeonovs Jul 18 '19 at 11:14
  • The issue you are facing is regarding this is actually right now open at google's end, you can read this thread for more details [link](https://github.com/googlesamples/android-play-billing/issues/122), and to the latest solution provided in this thread is [link](https://stackoverflow.com/questions/56594713/refund-customer-in-app-purchase-but-billingclient-still-indicate-user-has-purcha/56726021#56726021) – Rajat Beck Jul 18 '19 at 11:54
  • Hi Rajat, thank for the answer! Just a quick question. If a user subscribes to my app in 2018, cancelled it in 2019 and then subscribe again in 2020, can I get details about 2018 subscription as well when the user clicks restore? – Abhi Apr 14 '20 at 03:05
  • **queryPurchaseHistoryAsync()** will give you the details of 2018 subscription but I am not sure about the restore click. Abhi – Rajat Beck Apr 14 '20 at 15:10
  • @RajatBeck so at the end of your comment you state " So you can use queryPurchase() to get all active purchases." Do you do this on the objects returned in the Async query? My queryPurchases used to work while testing, however, my monthly subscription is still showing up when I call queryPurchases even after an hour later and it should have expired. – justdan0227 May 22 '20 at 15:12
  • try clearing your cache google play cache and then try again..@justdan0227 – Rajat Beck May 22 '20 at 16:46
  • **queryPurchase** is **deprecated** please use **queryPurchaseAsync** documented at [here](https://developer.android.com/reference/com/android/billingclient/api/BillingClient#queryPurchasesAsync(java.lang.String,%20com.android.billingclient.api.PurchasesResponseListener)) – AndroidEngineX Aug 29 '21 at 09:13
4

Here is the code that I use to check for active subscription :

private void isUserHasSubscription(Context context) {
        billingClient = BillingClient.newBuilder(context).enablePendingPurchases().setListener(this).build();
        billingClient.startConnection(new BillingClientStateListener() {
            @Override
            public void onBillingSetupFinished(BillingResult billingResult) {
                Purchase.PurchasesResult purchasesResult=billingClient.queryPurchases(BillingClient.SkuType.SUBS);

                billingClient.queryPurchaseHistoryAsync(BillingClient.SkuType.SUBS,(billingResult1, list) -> {
                    
                    Log.d("billingprocess","purchasesResult.getPurchasesList():"+purchasesResult.getPurchasesList());
                    
                    if (billingResult1.getResponseCode() == BillingClient.BillingResponseCode.OK &&
                            !Objects.requireNonNull(purchasesResult.getPurchasesList()).isEmpty()) {

                            //here you can pass the user to use the app because he has an active subscription  
                            Intent myIntent=new Intent(context,MainActivity.class);
                            startActivity(myIntent);
                    }
                });
            }
            @Override
            public void onBillingServiceDisconnected() {
                // Try to restart the connection on the next request to
                // Google Play by calling the startConnection() method.
                Log.d("billingprocess","onBillingServiceDisconnected");
            }
        });
    }
Mohamed Ben Romdhane
  • 1,005
  • 3
  • 11
  • 22
  • Thanks. It is the only solid working example. No other docs on how to use it anywhere else ... it's ridiculous. – ekashking Jul 12 '21 at 05:17