Adding subscriptions to your Android app. Part 3. Checking if user is subscribed
Tags: mobile, android, kotlin, tristan
Published: 2023-03-24 00:11:47

### Table of contents
1. [Resources I used](#resource)
2. [Before we start](#start)
3. [Start coding](#code)
4. [What is the next tutorial about?](#next)

### My app on the Google Playstore
- [HERE](https://play.google.com/store/apps/details?id=com.elliottsoftware.calftracker)

### GitHub code <a name="github"></a>
- [HERE](https://github.com/thePlebDev/CalfTracker)

### Resources I used <a name="resource"></a>
- [Integrate the Google Play Billing Library](https://developer.android.com/google/play/billing/integrate)
- [Android Subscritions codelab](https://codelabs.developers.google.com/play-billing-codelab#0)



### Before we start <a name="start"></a>
- Before you can read any further, you must have done the following 2 things

**1) Properly setup your google developer accound :** The instructions can be found [HERE](https://developer.android.com/google/play/billing/getting-ready)

**2) Add the Google billing library :** The library can be found [HERE](https://developer.android.com/google/play/billing/getting-ready#dependency). You need to add this library to your gradle.build file, then publish your app to either production, internal testing or closed testing.

### Determine if the user is subscribed or not
- So assuming you have done all the previously mentioned things, we can now worry about how to determine if the user is subscribed or not.

- The first thing we are going to do is to create a class called [BillingClientWrapper](https://github.com/android/play-billing-samples/blob/9cf7a57a7dfab7b207356dcb8b7d229bc0867063/PlayBillingCodelab/finished/src/main/java/com/sample/subscriptionscodelab/billing/BillingClientWrapper.kt#L42) and this class is where we will have all the code the interacts directly with the Google Play Billing Library

### Creating state inside the BillingClientWrapper <a name="code"></a>
- Now we need to create a MutableState object that will hold our subscribed information. We then need to map it to a State object and expose it to the rest of our code:
```
class BillingClientWrapper(
    context: Context
): PurchasesUpdatedListener{

    // Current Purchases
    private val _purchases =
        MutableStateFlow<List<Purchase>>(listOf())
    val purchases = _purchases.asStateFlow()

}

```
- This mapping from MutableState to State and then exposing as a public variable called `purchases` is a good coding practice. It allows us to define clear boundaries between our code. 

for the moment we can ignore the `PurchasesUpdatedListener` interface. But don't worry we will talk about it shortly


### Initialize a BillingClient
- Everything starts with the [BillingClient](https://developer.android.com/google/play/billing/integrate#initialize). We initialize the BillingClient like so:
```
// Initialize the BillingClient.
    private val billingClient = BillingClient.newBuilder(context)
        .setListener(this)
        .enablePendingPurchases()
        .build()
```

- BillingClient is the main interface for communication between the Google Play Billing Library and the rest of your app. BillingClient provides convenience methods, both synchronous and asynchronous, for many common billing operations. It's strongly recommended that we have one active BillingClient connection open at one time to avoid multiple PurchasesUpdatedListener callbacks for a single event

In `.setListener(this)` the `this` is referring to the `PurchasesUpdatedListener` interface. Since it is an interface, we have to implement its method, which is the [onPurchasesUpdated](https://developer.android.com/reference/com/android/billingclient/api/PurchasesUpdatedListener#onPurchasesUpdated(com.android.billingclient.api.BillingResult,%20java.util.List%3Ccom.android.billingclient.api.Purchase%3E)) method:
```
 override fun onPurchasesUpdated(
        billingResult: BillingResult, //contains the response code from the In-App billing API
        purchases: List<Purchase>? // a list of objects representing in-app purchases
    ) {

        if (billingResult.responseCode == BillingClient.BillingResponseCode.OK
            && !purchases.isNullOrEmpty()
        ) {
            // Post new purchase List to _purchases
            _purchases.value = purchases

            // Then, handle the purchases
        for (purchase in purchases) {
         acknowledgePurchases(purchase)// dont need to worry about
            }
        } else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
            // Handle an error caused by a user cancelling the purchase flow.

            Timber.tag("BILLINGR").e("User has cancelled")
        } else {
            // Handle any other error codes.
        }
    }

```
- The code above is responsible for updating our `_purchases` variable from earlier and will run each time our user makes a purchase. I also want to point out the the section of the code I marked `acknowledgePurchases(purchase)// dont need to worry about`. At this moment we don't need to worry about this code. Because it is used for detecting the different states of the Purchase objects(I will talk about in a future tutorial). But if you still want to checkout the code yourself, [HERE](https://github.com/android/play-billing-samples/blob/9cf7a57a7dfab7b207356dcb8b7d229bc0867063/PlayBillingCodelab/finished/src/main/java/com/sample/subscriptionscodelab/billing/BillingClientWrapper.kt#L199) it is.


### Connect to Google play
- After we have created a BillingClient, you need to establish a connection to Google Play. To connect to Google Play, call startConnection(). The connection process is asynchronous, and we must implement a BillingClientStateListener to receive a callback once the setup of the client is complete and it’s ready to make further requests:
```
   /*******CALLED TO INITIALIZE EVERYTHING******/
    // Establish a connection to Google Play.
    fun startBillingConnection(billingConnectionState: MutableLiveData<Boolean>) {

        billingClient.startConnection(object : BillingClientStateListener {
            override fun onBillingSetupFinished(billingResult: BillingResult) {
                if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                    Timber.tag("BILLINGR").d("Billing response OK")
        // The BillingClient is ready. You can query purchases and product details here
       queryPurchases()// we talk about this in the next paragraph
                } else {


           Timber.tag("BILLINGR").e(billingResult.debugMessage)
                }
            }

            override fun onBillingServiceDisconnected() {

                Timber.tag("BILLINGR").d("Billing connection disconnected")
                startBillingConnection(billingConnectionState)
            }
        })
    }

```
- Inside the code block above you can see we create a anonymous class with `billingClient.startConnection(object : BillingClientStateListener`. Which means we are creating a instance of the [BillingClientStateListener](https://developer.android.com/reference/com/android/billingclient/api/BillingClientStateListener) interface. Meaning we have to override it's two methods.

**1) onBillingSetupFinished() :** called when the connection to Google play is done and we can query for the user's purchases.

**2) onBillingServiceDisconnected() :** called when the connection to Google play billing service is lost. when this happens we just try to reconnect with a recursive call to `startBillingConnection(billingConnectionState)`

### The queryPurchases() method
- Now we can talk about `queryPurchases()`:
```
fun queryPurchases() {
        if (!billingClient.isReady) {

            Timber.tag("BILLINGR").e("queryPurchases: BillingClient is not ready")
        }

        // QUERY FOR EXISTING SUBSCRIPTION PRODUCTS THAT HAVE BEEN PURCHASED
        billingClient.queryPurchasesAsync(
            QueryPurchasesParams.newBuilder().setProductType(BillingClient.ProductType.SUBS).build()
        ) { billingResult, purchaseList ->
            if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                if (!purchaseList.isNullOrEmpty()) {
                    _purchases.value = purchaseList
                } else {
                    _purchases.value = emptyList()
                }

            } else {
                Timber.tag("BILLINGR").e(billingResult.debugMessage)
            }
        }
    }

```
- If you think this code seems similar to the `BillingClientStateListener`  you're right. But as the [documentation states](https://developer.android.com/google/play/billing/integrate#process), there are cases(such as buying a subscription outside of your app) where your app will be made aware of purchases by calling BillingClient.queryPurchasesAsync().

- Next we are using `QueryPurchasesParams.newBuilder().setProductType(BillingClient.ProductType.SUBS).build()` to query the Google library for any subscriptions that the user has made.

### Repository Layer
- Now we can create a repository layer that will be used as a filter and only return the subscriptions needed by our app.
```
class SubscriptionDataRepository(billingClientWrapper: BillingClientWrapper) {

    // Set to true when a returned purchase is an auto-renewing basic subscription.
    //hasRenewablePremium IS HOW WE WILL DETERMINE IF THERE IS A SUBSCRIPTION OR NOT
    val hasRenewablePremium: Flow<Boolean> = billingClientWrapper.purchases.map { value: List<Purchase> ->
        value.any { purchase: Purchase ->  purchase.products.contains(PREMIUM_SUB) && purchase.isAutoRenewing}
    }
   companion object {
        // List of subscription product offerings
        private const val PREMIUM_SUB = "your_subscription_id"
    }
}
```
- The important things from the code above are the `isAutoRenewing` and `contains(PREMIUM_SUB)`. `isAutoRenewing` is a flag stored on a [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) object to determine if the subscription is active or not. `contains(PREMIUM_SUB)` is used as a filter and you need to put your own `subscription_id` for you subscription. A subscription id can be found inside of your google play console under `Monetization -> Subscriptions`.

### ViewModel layer
- Now we are in the ViewModel there are 6 things that we need to do:

**1) Initialize the BillingClientWrapper**

**2) Initialize the Repository**

**3) Create state to hold the repository data**

**4) Create a method to query the repository**

**5) Start the connection**

**6) Using DisposableEffect to call queryPurchasesAsync()**

#### 1) Initialize the BillingClientWrapper
- We know all of the code to talk to the Google play Billing library lives inside of the `BillingClientWrapper`. So the first thing inside of our ViewModel is to initialize it:
```
class BillingViewModel(application: Application): AndroidViewModel(application){

    var billingClient: BillingClientWrapper = BillingClientWrapper(application)

}

```
- Notice how we use the `AndroidViewModel(application)` instead of the traditional ViewModel(). We do this to allow our `BillingViewModel` access to the application context, which we use to initialize the `BillingClientWrapper`.

#### 2) Initialize the Repository
- The next step is to use the initialized billingClient and pass it to the repository:
```
private var repo: SubscriptionDataRepository =
        SubscriptionDataRepository(billingClientWrapper = billingClient)

```

#### 3) Create state to hold the repository data
- We now need a object to hold the state we get from our repository and expose it to our view:
```
data class BillingUiState(
    val subscribed:Boolean = false
)

class BillingViewModel(application: Application): AndroidViewModel(application){

    private val _uiState = mutableStateOf(BillingUiState())
    val state:State<BillingUiState> = _uiState


    private var billingClient: BillingClientWrapper = BillingClientWrapper(application)

    private var repo: SubscriptionDataRepository =
        SubscriptionDataRepository(billingClientWrapper = billingClient)

}

```

#### 4) Create a method to query our Repository
```
 fun refreshPurchases(){

        viewModelScope.launch {
            repo.hasRenewablePremium.collect { collectedSubscriptions ->
                _uiState.value = _uiState.value.copy(
                    subscribed = collectedSubscriptions
                )
            }
        }

    }

```
- As you can see from the code above, we are using the viewModelScope to `collect{}` from the Flow stored inside of our repository layer `repo.hasRenewablePremium`.

#### 5) Start the connection
- Now that we have all of our methods set up we need to initialize everything inside of the BillingViewModel's init{} blocks:
```
init {
        billingClient.startBillingConnection(billingConnectionState = _billingConnectionState)
    }
init{

  refreshPurchases()

}

```

- Technically when the our BillingViewModel is initialized, our code will be able to recognize if the user has bought any subscriptions or not. But there are many more situations we are not accounting for, such as the ones described in the documentation, [HERE](https://developer.android.com/google/play/billing/integrate#fetch). As the documentation states, to be able to handle those situations we need to call the BillingClient.queryPurchasesAsync() in our onResume() method.

#### 6) Using DisposableEffect to call queryPurchasesAsync()
- We can accomplish calling BillingClient.queryPurchasesAsync() in our onResume() by using [Side-effects](https://developer.android.com/jetpack/compose/side-effects). More specifically we are going to use [DisposableEffect](https://developer.android.com/jetpack/compose/side-effects#disposableeffect) which allows us to create, add and remove a lifecycle observe to the `onResume()` method. We can actually do so inside of a Compose fuctions:
```
@Composable 
fun AddObserver(viewModel:BillingViewModel){
val lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current
DisposableEffect(lifecycleOwner) {
        // Create an observer that triggers our remembered callbacks
        // for sending analytics events
        val observer = LifecycleEventObserver { _, event ->
            if (event == Lifecycle.Event.ON_RESUME) {

                Timber.tag("LIFEEVENTCYCLE").d("WE ARE RESUMING")
                viewModel.refreshPurchases()
            }
        }

        // Add the observer to the lifecycle
        lifecycleOwner.lifecycle.addObserver(observer)

        // When the effect leaves the Composition, remove the observer
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(observer)
        }
    }


}

```
- In order to make this code work we first need to update the `refreshPurchases()` method inside of the BillingViewModel:
```
     fun refreshPurchases(){

        viewModelScope.launch {
            billingClient.queryPurchases()
            repo.hasRenewablePremium.collect { collectedSubscriptions ->
                //val value = collectedSubscriptions.hasRenewablePremium
                _uiState.value = _uiState.value.copy(
                    subscribed = collectedSubscriptions
                )
            }
        }

    }

```
- Notice that the code above now calls the `billingClient.queryPurchases()`, which will update the `_purchases` variable inside of the BillingClientWrapper, which will update the `hasRenewablePremium` variable inside of the repository, which will then be collected in the BilingViewModel, which can then be shown to the use as the variable `state.subscribed `

### What is the next tutorial <a name="next"></a>
- In the next tutorial we will implement the code to allow the user to buy our subscriptions



### Conclusion
- Thank you for taking the time out of your day to read this blog post of mine. If you have any questions or concerns please comment below or reach out to me on [Twitter](https://twitter.com/AndroidTristan).