Exploring the Google Play In-App Review API

E

When it comes to the Google Play store, app ratings and reviews are a pretty important marketing tool – they can have a huge influence on whether someone downloads our app, so ensuring that we do not miss out on good reviews is important. However, I’ve felt like there has always been a lot of friction in the review process – many apps seem to approach it differently, all of which require the user to leave the app to review it in the Google Play Store.

Last week we saw the launch of the Google Play In-App Review API – this new API allows users to be presented with a review sheet inside of the app, allowing them to review your app without switching context – this is something I am incredibly thankful for and have wanted for so long! In this post we’re going to dive into exactly what it is, how it works and how we can make use of it in our android applications.

As a side note, it turns out this is my 200th article – thanks for reading the stuff I put out and sharing with me the times that things have been a help for you 😊


Available on devices running Android 5.0 (lollipop) and above, as well as requiring the Google Play Store installed, the In-App Review API aims to ease the app review process for developers. Currently, when it comes to prompting users for reviews from applications there is a lot of fricton and inconsistency. Some applications will present an option for the user to go to the Google Play Store to leave a review, others will present an In-App Review and only take the user to the play store if the user selects a good rating inside of the app – this is something that I’ve seen a lot of. Regardless of how this is being done in an app currently, all these solutions end up looking very different, behaving very different and also add friction to the review process – likely resulting in no review being left at all.

With the In-App Review API, developers can present a review sheet to users which allows users to leave a review directly within the application without switching context. This will not only help to bring consistency to the review process within applications, but also hopefully increase the rate of reviews due to the reduced friction that is involved in the process.

To use the In-App Review API, we need to begin by adding the play-core dependency to our app – this review API has been added in version 1.8.0.

implementation 'com.google.android.play:core:1.8.0'

With the dependency added, we now have access tot he required classes for triggering the review flow. These are the:

  • ReviewManager – the class used to retrieve review information and launch the review flow. This has two functions, one for retrieving the review information and another for launching the review flow
  • ReviewInfo – the class that holds the required information used to launch the review flow

Using the ReviewManager, we can request the required ReviewInfo reference for our application and then use that reference to trigger the review flow for the user.

Before we can go ahead and request / launch the review flow, we need to obtain a reference to a ReviewManager. This is done using the ReviewManagerFactory, calling the create function and passing a reference to a context:

val manager = ReviewManagerFactory.create(context)

This create function will provide us with an instance of the ReviewManager class. With this manager in place, we can utilise the requestReviewFlow function. This is an asynchronous call which will retrieve the information required to display the review information for our application.

val request = manager.requestReviewFlow()

When we call this requestReviewFlow function, we’ll get back a reference to a Task of the type ReviewInfo. Because this is an asynchronous operation, we need to wait for it to complete before we can show the review. This means that the review information will not be available instantly when the review is requested – for example, the time this takes could vary greatly on the users network connection. For this reason, we need to add a listener for when the Task is completed – that way once the review info has been retrieved we can display it to the user.

request.addOnCompleteListener { request ->
    if (request.isSuccessful) {
        val reviewInfo = request.result
    }
}

In some cases the Task may fail, which in that case we won’t want to show anything to the user at all (as they won’t know that the review was being retrieved from the background in the first place). However, if the request is successful, we can retrieve the ReviewInfo instance from the result of the request. Using this ReviewInfo reference we can then trigger the review flow using the launchReviewFlow function from our ReviewManager reference:

val flow = manager.launchReviewFlow(activity, reviewInfo)

Again, this launchReviewFlow is an asynchronous task – when the function is called, the review flow will be prepared and potentially displayed to the user. I say potentially because it’s important to note that the launchReviewFlow function is not guaranteed to launch the review flow. Google play has quotas in place for how often a user can be displayed the review sheet, which if exceeded will mean that this flow will not result in the review sheet being displayed. Because of this, it’s important not to show any prompts to trigger reviews in your application as it could result in a confusing state for your users.

With this being an asynchronous operation, this Task reference does not return us any data, but it still has a completion state. The completion state means that the review flow is finished – it does not indicate as to whether the review flow was shown or whether the user actually left a review, it acts more as an indicator for us to continue any operations in our app.

flow.addOnCompleteListener { _ ->
    // continue app operations
}

With the above code we have a review flow in place without much code required from our side. However, with the asynchronous behaviour of the operations, none of these flows are guaranteed to be instant when triggered – for example, you could request to show the review and the user move to another part of your app, causing the review dialog to be disruptive to the user. Whilst we could cancel the request when the screen is moved away from, this could keep happening and result in the user never actually getting to leave a review for your app, all because the review info has not been ready when required.

To get around this, we’d want to take the above operations and keep a reference to the ReviewInfo reference so that when we want to display the review flow, the review information is already retrieved and available to launch without the need to wait for any operations to complete.

When it comes to this, we’re going to utilise the KTX library for play core to simplify our operations when it comes to pre-fetching the review.

implementation 'com.google.android.play:core-ktx:1.8.0'

With this in place, we can now trigger the same request to retrieve the review information except this time in the form of a suspending function:

val reviewInfo = reviewManager.requestReview()

Not only is this more likely to fit in with our current setup of coroutines, but it allows us to pre-fetch the review information with more ease. For example, when our app launches we could trigger this suspending function to pre-load the review and then access it at a later time, providing the retrieval has completed.

private var reviewInfo: Deferred<ReviewInfo>? = null

init {
    reviewInfo = viewModelScope.async {
        reviewManager.requestReview()
    }
}

override fun onCleared() {
    reviewInfo?.cancel()
    super.onCleared()
}

fun retrieveReview() {
    viewModelScope.launch(dispatchers.main) {
        if (reviewInfo?.isCompleted == true &&
            reviewInfo?.isCancelled == true
        ) {
            singleLiveEvent.value = reviewInfo?.getCompleted()
            reviewInfo = null
        }
    }
}

Whilst we could have achieved something similar using the Task callbacks from the previous example, the KTX library gives us a nice Kotlin API to work with – making these kind of operations much more concise in our code.

When it comes to launching the review flow, we can again use the KTX library to trigger the launchReview function. This is again a suspending function which takes a reference to the retrieved review info reference to construct the review sheet for the user. When this is called, the behaviour is exactly the same as the previous example – if the review flow is able to be launched then it will, otherwise the call will either silently fail or the review will just not be displayed to the user.

viewLifecycleOwner.lifecycleScope.launchWhenResumed {
    reviewManager.launchReview(requireActivity(), reviewInfo)
}

Manually testing the review flow

When it comes to testing the review flow, running a debug build from Android Studio will not result in the review sheet being displayed. Instead, you’ll need to utilise either Internal App Testing or the Internal Test Track within the Google Play Console. This is because the app needs to be installed through Google Play in-order for the review flow to work – the flow utilises the connected Google Play Account to depict the review information and quota, so this is required in-order to display the review sheet to the user. In most cases, the below should suffice for most cases when it comes to testing the In-App Review flow:

If you run into any issues when testing the flow, check out the troubleshooting guide in the developer documentation for In-App Reviews.

Unit Testing

Aside from manual testing, the API also provides some assistance when it comes to unit testing our review flows. For example, in the retrieveReview() from our previous example we may want to check that when the review is retrieved, our single live event is triggered with the review info reference – in this case we can utilise the FakeReviewManager class from the In-App Review API:

val manager = FakeReviewManager(context)

When the requestReview() function is called, the FakeReviewManager will return a fake ReviewInfo object within our tests. If the launchReview() function is triggered then a success status is returned to signify that the app can continue after the review flow. This means that we can fully unit test our review flows to ensure that the expected behaviours are triggered under their corresponding conditions.


In this post we’ve explored the new In-App Review API and how we can use it for a frictionless review process in our applications. We’ve seen that the API does not require us to add much code in-order to utilise this new review flow – with that in mind it feels like a worthy investment to potentially help improve the ratings and reviews in for our app in the Google Play Store.

I hope this guide helps to get your app configured for this new In-App Review flow. If you have any questions or thoughts, please feel free to reach out!

About the author

hitherejoe

Add Comment

By hitherejoe