Skip to content

Instantly share code, notes, and snippets.

@JakeSteam
Last active January 9, 2025 11:28
Show Gist options
  • Save JakeSteam/c09c7bd980095a8a26649419d49d393e to your computer and use it in GitHub Desktop.
Save JakeSteam/c09c7bd980095a8a26649419d49d393e to your computer and use it in GitHub Desktop.
Remotely configurable in-app Play Store review prompt in Kotlin
class MyFragment {
val navToBookings: () -> Unit = {
findNavController().navigate(MyFragmentDirections.toBookings())
}
fun eventHandler(event: TicketConfirmationEvents) {
when (event) {
is TicketConfirmationEvents.OnLookAtMyTicket -> {
viewModel.onLookAtMyTicket(navToBookings)
}
}
}
}
class MyViewModel(
reviewPromptHandler: ReviewPromptHandler
) {
init {
reviewPromptHandler.prepareReviewPrompt(ReviewPromptTrigger.TICKET_PURCHASED)
}
fun onLookAtMyTicket(navigation: () -> Unit) {
reviewPromptHandler.showReviewPrompt(ReviewPromptTrigger.TICKET_PURCHASED, navigation)
}
}
@Singleton
class ReviewPromptHandler @Inject constructor(
application: Application,
private val remoteConfigManager: RemoteConfigManager
) {
private val reviewManager = ReviewManagerFactory.create(application)
private var activity: Activity? = null
internal var preparedReviewPrompt: ReviewInfo? = null
private val triggersThisSession = mutableListOf<ReviewPromptTrigger>()
fun setActivity(activity: Activity) {
this.activity = activity
}
fun prepareReviewPrompt(trigger: ReviewPromptTrigger) {
preparedReviewPrompt = null
if (!shouldShow(trigger)) {
return
}
reviewManager.requestReviewFlow().addOnCompleteListener { request ->
if (request.isSuccessful) {
preparedReviewPrompt = request.result
}
}
}
fun showReviewPrompt(trigger: ReviewPromptTrigger, callback: () -> Unit = {}) {
val activity = activity
if (!shouldShow(trigger) || activity == null) {
callback()
return
}
triggersThisSession.add(trigger)
preparedReviewPrompt?.let {
launchReviewPrompt(activity, it, callback)
} ?: prepareAndLaunchReviewPrompt(activity, callback)
}
private fun shouldShow(trigger: ReviewPromptTrigger): Boolean {
if (triggersThisSession.contains(trigger)) {
return false
}
return remoteConfigManager.getString(review_prompt_triggers)
.split(",")
.map { it.trim() }
.contains(trigger.remoteName)
}
private fun prepareAndLaunchReviewPrompt(activity: Activity, callback: () -> Unit) {
reviewManager.requestReviewFlow().addOnCompleteListener { request ->
if (request.isSuccessful) {
launchReviewPrompt(activity, request.result, callback)
} else {
Log.i("ReviewPromptHandler", "Failed to prepareAndLaunchReviewPrompt")
callback()
}
}
}
private fun launchReviewPrompt(activity: Activity, reviewInfo: ReviewInfo, callback: () -> Unit) {
reviewManager.launchReviewFlow(activity, reviewInfo).addOnCompleteListener {
if (!it.isSuccessful) {
Log.i("ReviewPromptHandler", "Failed to launchReviewPrompt")
}
callback()
}
}
}
// https://developer.android.com/guide/playcore/in-app-review#when-to-request
enum class ReviewPromptTrigger(val remoteName: String) {
BID_MADE("BID_MADE"),
BUN_PURCHASED("BUN_PURCHASED"),
TICKET_PURCHASED("TICKET_PURCHASED")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment