mirror of
https://github.com/pepaskopec-blip/Graduately.git
synced 2026-10-27 15:14:35 +00:00
Make the Android updater read GitHub atom feeds the same way desktop does.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
9b9693fe4f
commit
d34a87c1f1
2 changed files with 53 additions and 26 deletions
|
|
@ -13,8 +13,8 @@ android {
|
|||
applicationId = "org.maturita.maturita"
|
||||
minSdk = 26
|
||||
targetSdk = 35
|
||||
versionCode = 4
|
||||
versionName = "android-4"
|
||||
versionCode = 5
|
||||
versionName = "android-5"
|
||||
buildConfigField("String", "COMMIT", "\"$commit\"")
|
||||
buildConfigField("String", "UPDATE_REPO", "\"pepaskopec-blip/maturita.c\"")
|
||||
buildConfigField("String", "UPDATE_BRANCH", "\"builds\"")
|
||||
|
|
|
|||
|
|
@ -2,8 +2,11 @@ package org.maturita.maturita.update
|
|||
|
||||
import android.app.Application
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.provider.Settings
|
||||
import androidx.core.content.FileProvider
|
||||
import org.maturita.maturita.BuildConfig
|
||||
import java.io.File
|
||||
|
|
@ -22,6 +25,8 @@ data class UpdateState(
|
|||
class Updater(private val app: Application) {
|
||||
private val io = Executors.newSingleThreadExecutor()
|
||||
private val main = Handler(Looper.getMainLooper())
|
||||
private val repo = BuildConfig.UPDATE_REPO
|
||||
private val branch = BuildConfig.UPDATE_BRANCH
|
||||
|
||||
private fun emit(cb: (UpdateState) -> Unit, state: UpdateState) {
|
||||
main.post { cb(state) }
|
||||
|
|
@ -35,18 +40,17 @@ class Updater(private val app: Application) {
|
|||
emit(cb, UpdateState(status = "checking", messageKey = "update_checking", messageArg = null))
|
||||
io.execute {
|
||||
try {
|
||||
val atom = get("https://github.com/${BuildConfig.UPDATE_REPO}/commits/${BuildConfig.UPDATE_BRANCH}.atom")
|
||||
val sha = Regex("""<id>.*?/commit/([0-9a-f]{7,40})</id>""", RegexOption.IGNORE_CASE)
|
||||
.find(atom)?.groupValues?.get(1)
|
||||
?: throw IllegalStateException("sha")
|
||||
val version = get(
|
||||
"https://raw.githubusercontent.com/${BuildConfig.UPDATE_REPO}/$sha/VERSION",
|
||||
).trim()
|
||||
val atom = get("https://github.com/$repo/commits/$branch.atom")
|
||||
val remote = atomMainSha(atom)
|
||||
?: run {
|
||||
val tip = atomTip(atom) ?: error("sha")
|
||||
get("https://raw.githubusercontent.com/$repo/$tip/VERSION").trim()
|
||||
}
|
||||
val local = BuildConfig.COMMIT
|
||||
if (version.startsWith(local) || local.startsWith(version)) {
|
||||
emit(cb, UpdateState("ok", version, "update_uptodate", version.take(7)))
|
||||
if (sameCommit(remote, local)) {
|
||||
emit(cb, UpdateState("ok", remote, "update_uptodate", remote.take(7)))
|
||||
} else {
|
||||
emit(cb, UpdateState("available", version, "update_available", version.take(7), true))
|
||||
emit(cb, UpdateState("available", remote, "update_available", remote.take(7), true))
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
emit(cb, UpdateState("error", messageKey = "update_err_network", messageArg = null))
|
||||
|
|
@ -58,11 +62,20 @@ class Updater(private val app: Application) {
|
|||
emit(cb, UpdateState(status = "downloading", messageKey = "update_downloading", messageArg = null))
|
||||
io.execute {
|
||||
try {
|
||||
val atom = get("https://github.com/${BuildConfig.UPDATE_REPO}/commits/${BuildConfig.UPDATE_BRANCH}.atom")
|
||||
val sha = Regex("""<id>.*?/commit/([0-9a-f]{7,40})</id>""", RegexOption.IGNORE_CASE)
|
||||
.find(atom)?.groupValues?.get(1)
|
||||
?: throw IllegalStateException("sha")
|
||||
val url = "https://raw.githubusercontent.com/${BuildConfig.UPDATE_REPO}/$sha/maturita-android.apk"
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
|
||||
!app.packageManager.canRequestPackageInstalls()
|
||||
) {
|
||||
val settings = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).apply {
|
||||
data = Uri.parse("package:${app.packageName}")
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
}
|
||||
main.post { app.startActivity(settings) }
|
||||
emit(cb, UpdateState("error", messageKey = "update_err_download", messageArg = null))
|
||||
return@execute
|
||||
}
|
||||
val atom = get("https://github.com/$repo/commits/$branch.atom")
|
||||
val tip = atomTip(atom) ?: error("sha")
|
||||
val url = "https://raw.githubusercontent.com/$repo/$tip/maturita-android.apk"
|
||||
val dir = File(app.cacheDir, "updates").apply { mkdirs() }
|
||||
val apk = File(dir, "maturita.apk")
|
||||
download(url, apk)
|
||||
|
|
@ -77,13 +90,25 @@ class Updater(private val app: Application) {
|
|||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
}
|
||||
main.post { app.startActivity(intent) }
|
||||
emit(cb, UpdateState("staged", sha, "update_staged", sha.take(7)))
|
||||
emit(cb, UpdateState("staged", tip, "update_staged", tip.take(7)))
|
||||
} catch (_: Exception) {
|
||||
emit(cb, UpdateState("error", messageKey = "update_err_download", messageArg = null))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun atomTip(atom: String): String? =
|
||||
Regex("""Commit/([0-9a-f]{40})""", RegexOption.IGNORE_CASE).find(atom)?.groupValues?.get(1)
|
||||
?: Regex("""/commit/([0-9a-f]{7,40})""", RegexOption.IGNORE_CASE).find(atom)?.groupValues?.get(1)
|
||||
|
||||
private fun atomMainSha(atom: String): String? =
|
||||
Regex("""Build from ([0-9a-f]{7,40})""", RegexOption.IGNORE_CASE).find(atom)?.groupValues?.get(1)
|
||||
|
||||
private fun sameCommit(a: String, b: String): Boolean {
|
||||
val n = minOf(a.length, b.length)
|
||||
return n >= 7 && a.take(n).equals(b.take(n), ignoreCase = true)
|
||||
}
|
||||
|
||||
private fun isApk(file: File): Boolean {
|
||||
if (file.length() < 1_000_000L) return false
|
||||
file.inputStream().use { input ->
|
||||
|
|
@ -93,12 +118,18 @@ class Updater(private val app: Application) {
|
|||
}
|
||||
}
|
||||
|
||||
private fun get(url: String): String {
|
||||
val c = (URL(url).openConnection() as HttpURLConnection).apply {
|
||||
private fun open(url: String, readMs: Int): HttpURLConnection {
|
||||
return (URL(url).openConnection() as HttpURLConnection).apply {
|
||||
connectTimeout = 15000
|
||||
readTimeout = 15000
|
||||
readTimeout = readMs
|
||||
instanceFollowRedirects = true
|
||||
setRequestProperty("User-Agent", "maturita.c-android")
|
||||
setRequestProperty("Accept", "*/*")
|
||||
}
|
||||
}
|
||||
|
||||
private fun get(url: String): String {
|
||||
val c = open(url, 15000)
|
||||
return try {
|
||||
if (c.responseCode !in 200..299) error("http ${c.responseCode}")
|
||||
c.inputStream.bufferedReader().use { it.readText() }
|
||||
|
|
@ -108,11 +139,7 @@ class Updater(private val app: Application) {
|
|||
}
|
||||
|
||||
private fun download(url: String, dest: File) {
|
||||
val c = (URL(url).openConnection() as HttpURLConnection).apply {
|
||||
connectTimeout = 20000
|
||||
readTimeout = 60000
|
||||
instanceFollowRedirects = true
|
||||
}
|
||||
val c = open(url, 60000)
|
||||
try {
|
||||
if (c.responseCode !in 200..299) error("http ${c.responseCode}")
|
||||
c.inputStream.use { input -> dest.outputStream().use { input.copyTo(it) } }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue