diff --git a/app/build.gradle b/app/build.gradle index 87877c30b..631d91956 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -120,7 +120,7 @@ android { manifestPlaceholders.put("app_name", "@string/app_name") //applicationIdSuffix '.debug' - versionNameSuffix "_debug-${getGitCommitHash()}" + versionNameSuffix "_debug+${getGitCommitHash()}" minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro', 'cronet-proguard-rules.pro' } diff --git a/app/src/main/java/io/legato/kazusa/help/update/AppReleaseInfo.kt b/app/src/main/java/io/legato/kazusa/help/update/AppReleaseInfo.kt index b3991117a..187aa488f 100644 --- a/app/src/main/java/io/legato/kazusa/help/update/AppReleaseInfo.kt +++ b/app/src/main/java/io/legato/kazusa/help/update/AppReleaseInfo.kt @@ -11,13 +11,9 @@ data class AppReleaseInfo( val note: String, val name: String, val downloadUrl: String, - val assetUrl: String -) { - val versionName: String = Regex("""legado_app_([\d.]+)\.apk""") - .find(name) - ?.groupValues?.get(1) - ?: "" -} + val assetUrl: String, + val versionName: String +) enum class AppVariant { OFFICIAL, @@ -43,11 +39,14 @@ data class GithubRelease( val createdAt: String? ) { fun gitReleaseToAppReleaseInfo(): List { + val version = tagName // 直接用 release 的 tag_name 作为版本号 assets ?: throw NoStackTraceException("获取新版本出错") + return assets .filter { it.isValid } - .map { it.assetToAppReleaseInfo(isPreRelease, body) } + .map { it.assetToAppReleaseInfo(isPreRelease, body, version) } } + } @@ -69,17 +68,21 @@ data class Asset( val isValid: Boolean get() = (contentType == "application/vnd.android.package-archive") && (state == "uploaded") - fun assetToAppReleaseInfo(preRelease: Boolean, note: String): AppReleaseInfo { + fun assetToAppReleaseInfo(preRelease: Boolean, note: String, version: String): AppReleaseInfo { val instant = Instant.parse(createdAt) val timestamp: Long = instant.toEpochMilli() - val appVariant = if (preRelease) { - AppVariant.BETA_RELEASE - } else { - AppVariant.OFFICIAL - } + val appVariant = if (preRelease) AppVariant.BETA_RELEASE else AppVariant.OFFICIAL - return AppReleaseInfo(appVariant, timestamp, note, name, apkUrl, url) + return AppReleaseInfo( + appVariant = appVariant, + createdAt = timestamp, + note = note, + name = name, + downloadUrl = apkUrl, + assetUrl = url, + versionName = version // 直接传入 tagName + ) } } diff --git a/app/src/main/java/io/legato/kazusa/help/update/AppUpdateGitHub.kt b/app/src/main/java/io/legato/kazusa/help/update/AppUpdateGitHub.kt index bea1f17aa..e174a00ea 100644 --- a/app/src/main/java/io/legato/kazusa/help/update/AppUpdateGitHub.kt +++ b/app/src/main/java/io/legato/kazusa/help/update/AppUpdateGitHub.kt @@ -29,16 +29,10 @@ object AppUpdateGitHub : AppUpdate.AppUpdateInterface { "https://api.github.com/repos/HapeLee/legado-with-MD3/releases/latest" } - val res = okHttpClient.newCallResponse { - url(lastReleaseUrl) - } - if (!res.isSuccessful) { - throw NoStackTraceException("获取新版本出错(${res.code})") - } + val res = okHttpClient.newCallResponse { url(lastReleaseUrl) } + if (!res.isSuccessful) throw NoStackTraceException("获取新版本出错(${res.code})") val body = res.body.text() - if (body.isBlank()) { - throw NoStackTraceException("获取新版本出错") - } + if (body.isBlank()) throw NoStackTraceException("获取新版本出错") return if (checkVariant.isBeta()) { val releases = GSON.fromJsonArray(body) @@ -60,11 +54,16 @@ object AppUpdateGitHub : AppUpdate.AppUpdateInterface { override fun check(scope: CoroutineScope): Coroutine { return Coroutine.async(scope) { val currentVersion = AppConst.appInfo.versionName - val releases = getLatestRelease() .filter { it.appVariant == checkVariant } - val latest = releases.firstOrNull { it.versionName.versionCompare(currentVersion) > 0 } + val latest = releases.firstOrNull { r -> + try { + r.versionName.versionCompare(currentVersion) > 0 + } catch (e: Exception) { + false + } + } if (latest != null) { return@async AppUpdate.UpdateInfo( @@ -79,35 +78,57 @@ object AppUpdateGitHub : AppUpdate.AppUpdateInterface { }.timeout(10000) } - fun String.versionCompare(other: String): Int { - val regex = Regex("""(\d+)|(\D+)""") - val thisParts = regex.findAll(this).map { it.value }.toList() - val otherParts = regex.findAll(other).map { it.value }.toList() - val maxLength = maxOf(thisParts.size, otherParts.size) + private data class SemVer( + val major: Int, + val minor: Int, + val patch: Int, + val preRelease: String? = null + ) : Comparable { + override fun compareTo(other: SemVer): Int { + if (major != other.major) return major - other.major + if (minor != other.minor) return minor - other.minor + if (patch != other.patch) return patch - other.patch - for (i in 0 until maxLength) { - val a = thisParts.getOrNull(i) - val b = otherParts.getOrNull(i) + if (preRelease == null && other.preRelease != null) return 1 + if (preRelease != null && other.preRelease == null) return -1 + if (preRelease == null && other.preRelease == null) return 0 - if (a == null) return -1 - if (b == null) return 1 + val aParts = preRelease!!.split(".") + val bParts = other.preRelease!!.split(".") + val maxLen = maxOf(aParts.size, bParts.size) - val isANum = a.all { it.isDigit() } - val isBNum = b.all { it.isDigit() } + for (i in 0 until maxLen) { + val a = aParts.getOrNull(i) + val b = bParts.getOrNull(i) + if (a == null) return -1 + if (b == null) return 1 - if (isANum && a.length > 1 && a.startsWith("0")) return -1 - if (isBNum && b.length > 1 && b.startsWith("0")) return 1 - - val cmp = if (isANum && isBNum) { - a.toInt() - b.toInt() - } else { - a.compareTo(b) + val isANum = a.all { it.isDigit() } + val isBNum = b.all { it.isDigit() } + if (isANum && isBNum) { + val cmp = a.toInt().compareTo(b.toInt()) + if (cmp != 0) return cmp + } else { + val cmp = a.compareTo(b) + if (cmp != 0) return cmp + } } - - if (cmp != 0) return cmp + return 0 } - return 0 + companion object { + fun parse(version: String): SemVer { + val regex = Regex("""(\d+)\.(\d+)\.(\d+)(?:-([\w.]+))?""") + val match = regex.matchEntire(version) + ?: throw IllegalArgumentException("Invalid version: $version") + val (maj, min, pat, pre) = match.destructured + return SemVer(maj.toInt(), min.toInt(), pat.toInt(), pre.ifBlank { null }) + } + } } + fun String.versionCompare(other: String): Int { + return SemVer.parse(this).compareTo(SemVer.parse(other)) + } } + diff --git a/app/src/main/res/xml/pref_config_other.xml b/app/src/main/res/xml/pref_config_other.xml index 25f20a3ac..4bf8beb2c 100644 --- a/app/src/main/res/xml/pref_config_other.xml +++ b/app/src/main/res/xml/pref_config_other.xml @@ -9,6 +9,16 @@ app:entries="@array/language" app:entryValues="@array/language_value" /> + + - -