Finding out if an update is available

Before we implement the actual updater we first need to know if an update is available. I used Firebase Remote Config to define a property latestVersionCode which would always point to the version code of the latest version. As it is an incremental integer it’s perfectly suited for this kind of comparison. At app start I compare the property against the value from BuildConfig.VERSION_CODE and, if it’s higher, I assume an update is available. I encapsulated the Remote Config code within a RxSingle to better fit my code:

remoteConfiguration.fetchLatestVersionCode()

.onErrorReturnItem(BuildConfig.VERSION_CODE)

.subscribe(versionCode -> {

if (versionCode > BuildConfig.VERSION_CODE) downloadUpdate()

})

In reality I actually show a dialog here informing the user about the update and let him choose if he wants to download it, but for now we directly download it.

Downloading the new APK

We’re using OkHttp to do the download and, as we want to show a progress bar to the user, a special ResponseBody to get informed about the progress. Luckily, there’s an official sample available how to do that here. I migrated that to Kotlin:

Now we simply need to add this ResponseBody as a network interceptor when building the OkHttp client:

val progressListener = object : ProgressListener { ... } val okHttpClient = OkHttpClient.Builder().addNetworkInterceptor {

val originalResponse = it.proceed(it.request())

val responseBody = originalResponse.body() ?: return@addNetworkInterceptor originalResponse



return@addNetworkInterceptor originalResponse.newBuilder()

.body(DownloadProgressBody(responseBody, progressListener))

.build()

}.build()

And that’s it. The progressListener will now get informed about the progress. My update() function looks more or less like this:

override fun update(bytesRead: Long, contentLength: Long, done: Boolean) {

val progress = ((bytesRead.toFloat() / contentLength) * 100).roundToInt()

runOnUiThread { progressBar.progress = progress }



if (done) installApk()

}