Fix in-app update checking
parent
ff0706dae5
commit
0248f84ca0
@ -1,110 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.settings
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import androidx.activity.ComponentActivity
|
|
||||||
import androidx.annotation.MainThread
|
|
||||||
import androidx.core.net.toUri
|
|
||||||
import com.google.android.material.R as materialR
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.InputStream
|
|
||||||
import java.security.MessageDigest
|
|
||||||
import java.security.cert.CertificateFactory
|
|
||||||
import java.security.cert.X509Certificate
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import org.koitharu.kotatsu.BuildConfig
|
|
||||||
import org.koitharu.kotatsu.R
|
|
||||||
import org.koitharu.kotatsu.core.github.AppUpdateRepository
|
|
||||||
import org.koitharu.kotatsu.core.github.AppVersion
|
|
||||||
import org.koitharu.kotatsu.core.github.VersionId
|
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
|
||||||
import org.koitharu.kotatsu.parsers.util.byte2HexFormatted
|
|
||||||
import org.koitharu.kotatsu.utils.FileSize
|
|
||||||
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
|
|
||||||
|
|
||||||
@Deprecated("")
|
|
||||||
class AppUpdateChecker(private val activity: ComponentActivity) {
|
|
||||||
|
|
||||||
private val settings: AppSettings = TODO()
|
|
||||||
private val repo: AppUpdateRepository = TODO()
|
|
||||||
|
|
||||||
suspend fun checkIfNeeded(): Boolean? = if (
|
|
||||||
settings.isUpdateCheckingEnabled &&
|
|
||||||
settings.lastUpdateCheckTimestamp + PERIOD < System.currentTimeMillis()
|
|
||||||
) {
|
|
||||||
checkNow()
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun checkNow() = runCatching {
|
|
||||||
val version = repo.fetchUpdate() ?: return@runCatching false
|
|
||||||
val newVersionId = VersionId(version.name)
|
|
||||||
val currentVersionId = VersionId(BuildConfig.VERSION_NAME)
|
|
||||||
val result = newVersionId > currentVersionId
|
|
||||||
if (result) {
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
showUpdateDialog(version)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
settings.lastUpdateCheckTimestamp = System.currentTimeMillis()
|
|
||||||
result
|
|
||||||
}.onFailure {
|
|
||||||
it.printStackTraceDebug()
|
|
||||||
}.getOrNull()
|
|
||||||
|
|
||||||
@MainThread
|
|
||||||
private fun showUpdateDialog(version: AppVersion) {
|
|
||||||
val message = buildString {
|
|
||||||
append(activity.getString(R.string.new_version_s, version.name))
|
|
||||||
appendLine()
|
|
||||||
append(activity.getString(R.string.size_s, FileSize.BYTES.format(activity, version.apkSize)))
|
|
||||||
appendLine()
|
|
||||||
appendLine()
|
|
||||||
append(version.description)
|
|
||||||
}
|
|
||||||
MaterialAlertDialogBuilder(activity, materialR.style.ThemeOverlay_Material3_MaterialAlertDialog_Centered)
|
|
||||||
.setTitle(R.string.app_update_available)
|
|
||||||
.setMessage(message)
|
|
||||||
.setIcon(R.drawable.ic_app_update)
|
|
||||||
.setPositiveButton(R.string.download) { _, _ ->
|
|
||||||
val intent = Intent(Intent.ACTION_VIEW, version.apkUrl.toUri())
|
|
||||||
activity.startActivity(Intent.createChooser(intent, activity.getString(R.string.open_in_browser)))
|
|
||||||
}
|
|
||||||
.setNegativeButton(R.string.close, null)
|
|
||||||
.setCancelable(false)
|
|
||||||
.create()
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
private const val CERT_SHA1 = "2C:19:C7:E8:07:61:2B:8E:94:51:1B:FD:72:67:07:64:5D:C2:58:AE"
|
|
||||||
private val PERIOD = TimeUnit.HOURS.toMillis(6)
|
|
||||||
|
|
||||||
fun isUpdateSupported(context: Context): Boolean {
|
|
||||||
return BuildConfig.DEBUG || getCertificateSHA1Fingerprint(context) == CERT_SHA1
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
@SuppressLint("PackageManagerGetSignatures")
|
|
||||||
private fun getCertificateSHA1Fingerprint(context: Context): String? = runCatching {
|
|
||||||
val packageInfo = context.packageManager.getPackageInfo(context.packageName, PackageManager.GET_SIGNATURES)
|
|
||||||
val signatures = requireNotNull(packageInfo?.signatures)
|
|
||||||
val cert: ByteArray = signatures.first().toByteArray()
|
|
||||||
val input: InputStream = ByteArrayInputStream(cert)
|
|
||||||
val cf = CertificateFactory.getInstance("X509")
|
|
||||||
val c = cf.generateCertificate(input) as X509Certificate
|
|
||||||
val md: MessageDigest = MessageDigest.getInstance("SHA1")
|
|
||||||
val publicKey: ByteArray = md.digest(c.encoded)
|
|
||||||
return publicKey.byte2HexFormatted()
|
|
||||||
}.onFailure { error ->
|
|
||||||
error.printStackTraceDebug()
|
|
||||||
}.getOrNull()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package org.koitharu.kotatsu.settings.about
|
||||||
|
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import javax.inject.Inject
|
||||||
|
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||||
|
import org.koitharu.kotatsu.core.github.AppUpdateRepository
|
||||||
|
import org.koitharu.kotatsu.core.github.AppVersion
|
||||||
|
import org.koitharu.kotatsu.utils.SingleLiveEvent
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
class AboutSettingsViewModel @Inject constructor(
|
||||||
|
private val appUpdateRepository: AppUpdateRepository,
|
||||||
|
) : BaseViewModel() {
|
||||||
|
|
||||||
|
val isUpdateSupported = appUpdateRepository.isUpdateSupported()
|
||||||
|
val onUpdateAvailable = SingleLiveEvent<AppVersion?>()
|
||||||
|
|
||||||
|
fun checkForUpdates() {
|
||||||
|
launchLoadingJob {
|
||||||
|
val update = appUpdateRepository.fetchUpdate()
|
||||||
|
onUpdateAvailable.call(update)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package org.koitharu.kotatsu.settings.about
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
import com.google.android.material.R as materialR
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.core.github.AppVersion
|
||||||
|
import org.koitharu.kotatsu.utils.FileSize
|
||||||
|
|
||||||
|
class AppUpdateDialog(private val context: Context) {
|
||||||
|
|
||||||
|
fun show(version: AppVersion) {
|
||||||
|
val message = buildString {
|
||||||
|
append(context.getString(R.string.new_version_s, version.name))
|
||||||
|
appendLine()
|
||||||
|
append(context.getString(R.string.size_s, FileSize.BYTES.format(context, version.apkSize)))
|
||||||
|
appendLine()
|
||||||
|
appendLine()
|
||||||
|
append(version.description)
|
||||||
|
}
|
||||||
|
MaterialAlertDialogBuilder(
|
||||||
|
context,
|
||||||
|
materialR.style.ThemeOverlay_Material3_MaterialAlertDialog_Centered,
|
||||||
|
)
|
||||||
|
.setTitle(R.string.app_update_available)
|
||||||
|
.setMessage(message)
|
||||||
|
.setIcon(R.drawable.ic_app_update)
|
||||||
|
.setPositiveButton(R.string.download) { _, _ ->
|
||||||
|
val intent = Intent(Intent.ACTION_VIEW, version.apkUrl.toUri())
|
||||||
|
context.startActivity(Intent.createChooser(intent, context.getString(R.string.open_in_browser)))
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.close, null)
|
||||||
|
.setCancelable(false)
|
||||||
|
.create()
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue