Now that you have nearly everything in place in terms of dependencies, project setup and data, it’s time to build the InAppReviewManager. To start doing that, create a new interface named InAppReviewManager:
interface InAppReviewManager {
fun startReview(activity: Activity)
fun isEligibleForReview(): Boolean
}
You’ll use this interface to abstract the actual manager. It has two functions - isEligibleForReview() to check if the app state is ready to show the user an In App Review dialog and startReview() to start the review in question. Now add the implementation class, with the same name and Impl at the end:
class InAppReviewManagerImpl @Inject constructor(
@ApplicationContext private val context: Context,
private val reviewManager: ReviewManager,
private val inAppReviewPreferences: InAppReviewPreferences
) : InAppReviewManager {
}
This class has a few things going on. It’s using @Inject, to let Hilt know how to build the object. It’ll use the constructor, to which it passes a context, reviewManager and inAppReviewPreferences.
You also implement the interface, but you’ll add the functions in a moment. Now open the InAppReviewBinds class and add the following function:
@Binds
@Singleton
abstract fun bindInAppReviewManager(
inAppReviewManagerImpl: InAppReviewManagerImpl
): InAppReviewManager
Just like before, you’ll just bind the implementation to the manager interface. Go back to the manager implementation and add the following code to start building the manager:
companion object {
private const val KEY_REVIEW = "reviewFlow"
}
private var reviewInfo: ReviewInfo? = null
init {
if (isEligibleForReview()) {
reviewManager.requestReviewFlow().addOnCompleteListener {
if (it.isComplete && it.isSuccessful) {
this.reviewInfo = it.result
}
}
}
}
This piece of code creates the base setup you need to use to start the review flow. You’ll use the String key to log if the review flow was started or not. The reviewInfo is the important part. Using the ReviewInfo, you get all the data your app needs to provide to the review manager, to show the In App Review feature.
You need to fetch the reviewInfo using the reviewManager. In the case of this class, you fetch the info in the init block and only if the app is eligible to show a review. You’ll implement the eligibility check in a moment, as well.
To fetch the info, you have to call requestReviewFlow() and attach a listener to the task. Once the task is complete and successful, you can fetch its result and store it in the class as a property. If the task doesn’t complete or fails, you won’t create the reviewInfo and you won’t be able to start any reviews.
Now add the following function, to check the eligibility:
override fun isEligibleForReview(): Boolean {
return (!inAppReviewPreferences.hasUserRatedApp()
&& !inAppReviewPreferences.hasUserChosenRateLater())
|| (inAppReviewPreferences.hasUserChosenRateLater() && enoughTimePassed())
}
private fun enoughTimePassed(): Boolean {
val rateLaterTimestamp = inAppReviewPreferences.getRateLaterTime()
return abs(rateLaterTimestamp - System.currentTimeMillis()) >= TimeUnit.DAYS.toMillis(14)
}
By checking if the user hasn’t given a rating yet and they haven’t chosen to rate later, or that they’ve chosen to rate later and enough time has passed, you can determine if the app is eligible to ask the user for a review. To calculate if enough time has passed, you check if the difference from the rateLaterTimestamp and the current day is at least two weeks. Pretty simple! :]
Now add the final pieces of code, to start the review flow:
override fun startReview(activity: Activity) {
if (reviewInfo != null) {
reviewManager.launchReviewFlow(activity, reviewInfo).addOnCompleteListener { reviewFlow ->
onReviewFlowLaunchCompleted(reviewFlow)
}
}
}
private fun onReviewFlowLaunchCompleted(reviewFlow: Task<Void>) {
if (reviewFlow.isSuccessful) {
logSuccess()
}
}
private fun logSuccess() {
if (BuildConfig.DEBUG) {
Log.d(KEY_REVIEW, "Review complete!")
}
}
Within startReview() you call the reviewManager to launchReviewFlow(). You pass in to which Activity you want the flow to be bound to and with which info you want to start the flow. Then you add a complete listener and pass the reviewFlow task to the onReviewFlowLaunchCompleted() function. If the flow was successful and you’re in a DEBUG build, you log the successful status.
Notice how you don’t have to do anything with the task or anything with the reviewInfo. The manager takes care of everything for you and will launch the flow and show the dialog.
You’re almost there! In the next episode, you’ll finally connect the manager to your UI and rest of the app. See you there!