Merge pull request #4044 from h11128/update-version-1

添加共存版的检查更新
This commit is contained in:
Horis
2024-07-25 14:19:57 +08:00
committed by GitHub
18 changed files with 249 additions and 119 deletions
@@ -1,51 +1,54 @@
package io.legado.app package io.legado.app
import com.google.gson.Gson
import io.legado.app.exception.NoStackTraceException import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.http.okHttpClient import io.legado.app.help.http.okHttpClient
import io.legado.app.utils.channel import io.legado.app.model.GithubRelease
import io.legado.app.utils.jsonPath import io.legado.app.utils.fromJsonObject
import okhttp3.Request import okhttp3.Request
import org.junit.Assert.assertTrue
import org.junit.Test import org.junit.Test
import splitties.init.appCtx
class UpdateTest { class UpdateTest {
private val lastReleaseUrl = "https://api.github.com/repos/gedoor/legado/releases/latest" private val lastReleaseUrl =
"https://api.github.com/repos/gedoor/legado/releases/latest"
private val lastBetaReleaseUrl =
"https://api.github.com/repos/gedoor/legado/releases/tags/beta"
@Test
fun updateApp_beta() {
val body = okHttpClient.newCall(Request.Builder().url(lastBetaReleaseUrl).build()).execute()
.body!!.string()
val releaseList = Gson().fromJsonObject<GithubRelease>(body)
.getOrElse {
throw NoStackTraceException("获取新版本出错 " + it.localizedMessage)
}
.gitReleaseToAppReleaseInfo()
.sortedByDescending { it.createdAt }
assertTrue(releaseList.size == 2)
assertTrue(releaseList.all { it.downloadUrl.isNotBlank() })
assertTrue(releaseList.all { it.versionName.isNotBlank() })
}
@Test @Test
fun updateApp() { fun updateApp() {
val body = okHttpClient.newCall(Request.Builder().url(lastReleaseUrl).build()).execute() val body = okHttpClient.newCall(Request.Builder().url(lastReleaseUrl).build()).execute()
.body!!.string() .body!!.string()
val rootDoc = jsonPath.parse(body)
val downloadUrl =
rootDoc.read<List<String>>("\$.assets[?(@.name =~ /legado_app_.*?apk\$/)].browser_download_url")
print(downloadUrl)
}
@Test val releaseList = Gson().fromJsonObject<GithubRelease>(body)
fun updateLollipop() { .getOrElse {
val body = okHttpClient.newCall(Request.Builder().url(lastReleaseUrl).build()).execute() throw NoStackTraceException("获取新版本出错 " + it.localizedMessage)
.body!!.string() }
val rootDoc = jsonPath.parse(body) .gitReleaseToAppReleaseInfo()
val downloadUrl = .sortedByDescending { it.createdAt }
rootDoc.read<List<String>>("\$.assets[?(@.name =~ /legado_lollipop_.*?apk\$/)].browser_download_url")
print(downloadUrl)
}
@Test assertTrue(releaseList.size == 1)
fun updateChannel() { assertTrue(releaseList.all { it.downloadUrl.isNotBlank() })
val body = okHttpClient.newCall(Request.Builder().url(lastReleaseUrl).build()).execute() assertTrue(releaseList.all { it.versionName.isNotBlank() })
.body!!.string()
val rootDoc = jsonPath.parse(body)
val path = "\$.assets[?(@.name =~ /legado_${appCtx.channel}_.*?apk\$/)]"
val downloadUrl = rootDoc.read<List<String>>("${path}.browser_download_url")
.firstOrNull()
?: throw NoStackTraceException("获取新版本出错")
val fileName = rootDoc.read<List<String>>("${path}.name")
.firstOrNull()
?: throw NoStackTraceException("获取新版本出错")
print(downloadUrl)
print(fileName)
} }
} }
@@ -5,6 +5,7 @@ import android.content.pm.PackageManager
import android.provider.Settings import android.provider.Settings
import androidx.annotation.Keep import androidx.annotation.Keep
import io.legado.app.BuildConfig import io.legado.app.BuildConfig
import io.legado.app.model.AppVariant
import splitties.init.appCtx import splitties.init.appCtx
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
@@ -58,6 +59,11 @@ object AppConst {
appCtx.packageManager.getPackageInfo(appCtx.packageName, PackageManager.GET_ACTIVITIES) appCtx.packageManager.getPackageInfo(appCtx.packageName, PackageManager.GET_ACTIVITIES)
?.let { ?.let {
appInfo.versionName = it.versionName appInfo.versionName = it.versionName
// TODO: 增加测试版还是正式版的检查
if (it.packageName.contains("releaseA")) {
appInfo.appVariant = AppVariant.BETA_RELEASEA
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
appInfo.versionCode = it.longVersionCode appInfo.versionCode = it.longVersionCode
} else { } else {
@@ -74,7 +80,8 @@ object AppConst {
@Keep @Keep
data class AppInfo( data class AppInfo(
var versionCode: Long = 0L, var versionCode: Long = 0L,
var versionName: String = "" var versionName: String = "",
var appVariant: AppVariant = AppVariant.UNKNOWN
) )
/** /**
@@ -145,7 +145,7 @@ object PreferKey {
const val mouseWheelPage = "mouseWheelPage" const val mouseWheelPage = "mouseWheelPage"
const val recordHeapDump = "recordHeapDump" const val recordHeapDump = "recordHeapDump"
const val optimizeRender = "optimizeRender" const val optimizeRender = "optimizeRender"
const val updateToBeta = "updateToBeta" const val updateToVariant = "updateToVariant"
const val cPrimary = "colorPrimary" const val cPrimary = "colorPrimary"
const val cAccent = "colorAccent" const val cAccent = "colorAccent"
@@ -23,8 +23,6 @@ object AppUpdate {
fun check(scope: CoroutineScope): Coroutine<UpdateInfo> fun check(scope: CoroutineScope): Coroutine<UpdateInfo>
fun checkBeta(scope: CoroutineScope): Coroutine<UpdateInfo>
} }
} }
@@ -1,83 +1,67 @@
package io.legado.app.help package io.legado.app.help
import androidx.annotation.Keep import androidx.annotation.Keep
import com.google.gson.Gson
import io.legado.app.constant.AppConst import io.legado.app.constant.AppConst
import io.legado.app.exception.NoStackTraceException import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.config.AppConfig
import io.legado.app.help.coroutine.Coroutine import io.legado.app.help.coroutine.Coroutine
import io.legado.app.help.http.newCallStrResponse import io.legado.app.help.http.newCallStrResponse
import io.legado.app.help.http.okHttpClient import io.legado.app.help.http.okHttpClient
import io.legado.app.utils.channel import io.legado.app.model.AppReleaseInfo
import io.legado.app.utils.jsonPath import io.legado.app.model.AppVariant
import io.legado.app.utils.readString import io.legado.app.model.GithubRelease
import io.legado.app.utils.fromJsonObject
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import splitties.init.appCtx
@Keep @Keep
@Suppress("unused") @Suppress("unused")
object AppUpdateGitHub : AppUpdate.AppUpdateInterface { object AppUpdateGitHub : AppUpdate.AppUpdateInterface {
private val checkVariant: AppVariant
get() = when (AppConfig.updateToVariant) {
"official_version" -> AppVariant.OFFICIAL
"beta_release_version" -> AppVariant.BETA_RELEASE
"beta_releaseA_version" -> AppVariant.BETA_RELEASEA
else -> AppConst.appInfo.appVariant
}
private suspend fun getLatestRelease(): List<AppReleaseInfo> {
val lastReleaseUrl = if (checkVariant.name.lowercase().contains("beta")) {
"https://api.github.com/repos/gedoor/legado/releases/tags/beta"
} else {
"https://api.github.com/repos/gedoor/legado/releases/latest"
}
val body = okHttpClient.newCallStrResponse {
url(lastReleaseUrl)
}.body
if (body.isNullOrBlank()) {
throw NoStackTraceException("获取新版本出错")
}
return Gson().fromJsonObject<GithubRelease>(body)
.getOrElse {
throw NoStackTraceException("获取新版本出错 " + it.localizedMessage)
}
.gitReleaseToAppReleaseInfo()
.sortedByDescending { it.createdAt }
}
override fun check( override fun check(
scope: CoroutineScope, scope: CoroutineScope,
): Coroutine<AppUpdate.UpdateInfo> { ): Coroutine<AppUpdate.UpdateInfo> {
return Coroutine.async(scope) { return Coroutine.async(scope) {
val lastReleaseUrl = "https://api.github.com/repos/gedoor/legado/releases/latest" getLatestRelease()
val body = okHttpClient.newCallStrResponse { .filter { it.appVariant == checkVariant }
url(lastReleaseUrl) .firstOrNull { it.versionName > AppConst.appInfo.versionName }
}.body ?.let {
if (body.isNullOrBlank()) { return@async AppUpdate.UpdateInfo(
throw NoStackTraceException("获取新版本出错") it.versionName,
} it.note,
val rootDoc = jsonPath.parse(body) it.downloadUrl,
val tagName = rootDoc.readString("$.tag_name") it.name
?: throw NoStackTraceException("获取新版本出错") )
if (tagName > AppConst.appInfo.versionName) { }
val updateBody = rootDoc.readString("$.body") ?: throw NoStackTraceException("已是最新版本")
?: throw NoStackTraceException("获取新版本出错")
val path = "\$.assets[?(@.name =~ /legado_${appCtx.channel}_.*?apk\$/)]"
val downloadUrl = rootDoc.read<List<String>>("${path}.browser_download_url")
.firstOrNull()
?: throw NoStackTraceException("获取新版本出错")
val fileName = rootDoc.read<List<String>>("${path}.name")
.firstOrNull()
?: throw NoStackTraceException("获取新版本出错")
return@async AppUpdate.UpdateInfo(tagName, updateBody, downloadUrl, fileName)
} else {
throw NoStackTraceException("已是最新版本")
}
}.timeout(10000) }.timeout(10000)
} }
override fun checkBeta(scope: CoroutineScope): Coroutine<AppUpdate.UpdateInfo> {
return Coroutine.async(scope) {
val preReleaseUrl = "https://api.github.com/repos/gedoor/legado/releases/tags/beta"
val body = okHttpClient.newCallStrResponse {
url(preReleaseUrl)
}.body
if (body.isNullOrBlank()) {
throw NoStackTraceException("获取新版本出错")
}
val rootDoc = jsonPath.parse(body)
val path = "\$.assets[?(@.name =~ /legado_${appCtx.channel}_.*?apk\$/)]"
val name = rootDoc.readString("$.name")
?: throw NoStackTraceException("获取新版本出错")
val tagName = name.replace("legado_app_", "")
if (tagName > AppConst.appInfo.versionName) {
val assetsMap = rootDoc.read<List<Any>>(path)
.firstOrNull()
?: throw NoStackTraceException("获取新版本出错")
val assets = jsonPath.parse(assetsMap)
val updateBody = rootDoc.readString("$.body")
?: throw NoStackTraceException("获取新版本出错")
val downloadUrl = assets.readString("$.browser_download_url")
?: throw NoStackTraceException("获取新版本出错")
val fileName = assets.readString("$.name")
?: throw NoStackTraceException("获取新版本出错")
return@async AppUpdate.UpdateInfo(tagName, updateBody, downloadUrl, fileName)
} else {
throw NoStackTraceException("已是最新版本")
}
}.timeout(10000)
}
} }
@@ -471,7 +471,7 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
val defaultHomePage get() = appCtx.getPrefString(PreferKey.defaultHomePage, "bookshelf") val defaultHomePage get() = appCtx.getPrefString(PreferKey.defaultHomePage, "bookshelf")
val updateToBeta get() = appCtx.getPrefBoolean(PreferKey.updateToBeta, false) val updateToVariant get() = appCtx.getPrefString(PreferKey.updateToVariant, "default_version")
val doublePageHorizontal: String? val doublePageHorizontal: String?
get() = appCtx.getPrefString(PreferKey.doublePageHorizontal) get() = appCtx.getPrefString(PreferKey.doublePageHorizontal)
@@ -0,0 +1,91 @@
package io.legado.app.model
import com.google.gson.annotations.SerializedName
import java.time.Instant
data class AppReleaseInfo(
val appVariant: AppVariant,
val createdAt: Long,
val note: String,
val name: String,
val downloadUrl: String,
val assetUrl: String
) {
val versionName: String = name.split("_").getOrNull(2)?.removeSuffix(".apk") ?: ""
}
enum class AppVariant {
OFFICIAL,
BETA_RELEASEA,
BETA_RELEASE,
UNKNOWN
}
data class GithubRelease(
val assets: List<Asset>,
val body: String,
@SerializedName("prerelease")
val isPreLease: Boolean,
) {
fun gitReleaseToAppReleaseInfo(): List<AppReleaseInfo> {
return assets
.filter { it.isValid }
.map { it.assetToAppReleaseInfo(isPreLease, body) }
}
}
data class Asset(
@SerializedName("browser_download_url")
val apkUrl: String,
@SerializedName("content_type")
val contentType: String,
@SerializedName("created_at")
val createdAt: String,
@SerializedName("download_count")
val downloadCount: Int,
val id: Int,
val name: String,
val state: String,
val url: String
) {
val isValid: Boolean
get() = (contentType == "application/vnd.android.package-archive") && (state == "uploaded")
fun assetToAppReleaseInfo(preRelease: Boolean, note: String): AppReleaseInfo {
val instant = Instant.parse(createdAt)
val timestamp: Long = instant.toEpochMilli()
return when {
preRelease && name.contains("releaseA") ->
AppReleaseInfo(
AppVariant.BETA_RELEASEA,
timestamp,
note,
name,
apkUrl,
url
)
preRelease && name.contains("release") ->
AppReleaseInfo(
AppVariant.BETA_RELEASE,
timestamp,
note,
name,
apkUrl,
url
)
else ->
AppReleaseInfo(
AppVariant.OFFICIAL,
timestamp,
note,
name,
apkUrl,
url
)
}
}
}
@@ -88,20 +88,16 @@ class AboutFragment : PreferenceFragmentCompat() {
private fun checkUpdate() { private fun checkUpdate() {
waitDialog.show() waitDialog.show()
AppUpdate.gitHubUpdate?.run { AppUpdate.gitHubUpdate?.run {
val job = if (AppConfig.updateToBeta) { check(lifecycleScope)
checkBeta(lifecycleScope) .onSuccess {
} else { showDialogFragment(
check(lifecycleScope) UpdateDialog(it)
} )
job.onSuccess { }.onError {
showDialogFragment( appCtx.toastOnUi("${getString(R.string.check_update)}\n${it.localizedMessage}")
UpdateDialog(it) }.onFinally {
) waitDialog.dismiss()
}.onError { }
appCtx.toastOnUi("${getString(R.string.check_update)}\n${it.localizedMessage}")
}.onFinally {
waitDialog.dismiss()
}
} }
} }
@@ -1155,4 +1155,8 @@
<string name="start_chapter">Cap. inicio</string> <string name="start_chapter">Cap. inicio</string>
<string name="update_to_bata_title">更新至测试版</string> <string name="update_to_bata_title">更新至测试版</string>
<string name="update_to_bata_summary">检查更新时查找最新的测试版本</string> <string name="update_to_bata_summary">检查更新时查找最新的测试版本</string>
<string name="default_version">当前</string>
<string name="official_version">正式版</string>
<string name="beta_release_version">测试版</string>
<string name="beta_releaseA_version">共存版</string>
</resources> </resources>
@@ -1158,4 +1158,8 @@
<string name="start_chapter">開始の章</string> <string name="start_chapter">開始の章</string>
<string name="update_to_bata_title">更新至测试版</string> <string name="update_to_bata_title">更新至测试版</string>
<string name="update_to_bata_summary">检查更新时查找最新的测试版本</string> <string name="update_to_bata_summary">检查更新时查找最新的测试版本</string>
<string name="default_version">当前</string>
<string name="official_version">正式版</string>
<string name="beta_release_version">测试版</string>
<string name="beta_releaseA_version">共存版</string>
</resources> </resources>
@@ -1158,4 +1158,8 @@
<string name="start_chapter">Início</string> <string name="start_chapter">Início</string>
<string name="update_to_bata_title">更新至测试版</string> <string name="update_to_bata_title">更新至测试版</string>
<string name="update_to_bata_summary">检查更新时查找最新的测试版本</string> <string name="update_to_bata_summary">检查更新时查找最新的测试版本</string>
<string name="default_version">当前</string>
<string name="official_version">正式版</string>
<string name="beta_release_version">测试版</string>
<string name="beta_releaseA_version">共存版</string>
</resources> </resources>
+4
View File
@@ -1154,4 +1154,8 @@ Còn </string>
<string name="start_chapter">Chương đầu</string> <string name="start_chapter">Chương đầu</string>
<string name="update_to_bata_title">更新至测试版</string> <string name="update_to_bata_title">更新至测试版</string>
<string name="update_to_bata_summary">检查更新时查找最新的测试版本</string> <string name="update_to_bata_summary">检查更新时查找最新的测试版本</string>
<string name="default_version">当前</string>
<string name="official_version">正式版</string>
<string name="beta_release_version">测试版</string>
<string name="beta_releaseA_version">共存版</string>
</resources> </resources>
@@ -1155,4 +1155,8 @@
<string name="start_chapter">開始篇章</string> <string name="start_chapter">開始篇章</string>
<string name="update_to_bata_title">更新至测试版</string> <string name="update_to_bata_title">更新至测试版</string>
<string name="update_to_bata_summary">检查更新时查找最新的测试版本</string> <string name="update_to_bata_summary">检查更新时查找最新的测试版本</string>
<string name="default_version">当前</string>
<string name="official_version">正式版</string>
<string name="beta_release_version">测试版</string>
<string name="beta_releaseA_version">共存版</string>
</resources> </resources>
@@ -1157,4 +1157,8 @@
<string name="start_chapter">開始篇章</string> <string name="start_chapter">開始篇章</string>
<string name="update_to_bata_title">更新至测试版</string> <string name="update_to_bata_title">更新至测试版</string>
<string name="update_to_bata_summary">检查更新时查找最新的测试版本</string> <string name="update_to_bata_summary">检查更新时查找最新的测试版本</string>
<string name="default_version">当前</string>
<string name="official_version">正式版</string>
<string name="beta_release_version">测试版</string>
<string name="beta_releaseA_version">共存版</string>
</resources> </resources>
+6 -2
View File
@@ -1155,6 +1155,10 @@
<string name="start_from">开始日期</string> <string name="start_from">开始日期</string>
<string name="daily_chapters">日更章数</string> <string name="daily_chapters">日更章数</string>
<string name="start_chapter">起始章节</string> <string name="start_chapter">起始章节</string>
<string name="update_to_bata_title">更新至测试版</string> <string name="update_to_bata_title">检查更新查找版本</string>
<string name="update_to_bata_summary">检查更新查找最新的测试版本</string> <string name="update_to_bata_summary">检查更新查找其他签名版本</string>
<string name="default_version">当前</string>
<string name="official_version">正式版</string>
<string name="beta_release_version">测试版</string>
<string name="beta_releaseA_version">共存版</string>
</resources> </resources>
+15
View File
@@ -151,6 +151,14 @@
<item>@string/my</item> <item>@string/my</item>
</string-array> </string-array>
<string-array name="default_app_variant">
<item>@string/default_version</item>
<item>@string/official_version</item>
<item>@string/beta_release_version</item>
<item>@string/beta_releaseA_version</item>
</string-array>
<string-array name="default_home_page_value"> <string-array name="default_home_page_value">
<item>bookshelf</item> <item>bookshelf</item>
<item>explore</item> <item>explore</item>
@@ -158,6 +166,13 @@
<item>my</item> <item>my</item>
</string-array> </string-array>
<string-array name="default_app_variant_value">
<item>default_version</item>
<item>official_version</item>
<item>beta_release_version</item>
<item>beta_releaseA_version</item>
</string-array>
<string-array name="tip_color"> <string-array name="tip_color">
<item>Same color as content</item> <item>Same color as content</item>
<item>Customize</item> <item>Customize</item>
+4
View File
@@ -1158,4 +1158,8 @@
<string name="start_chapter">Start Chapter</string> <string name="start_chapter">Start Chapter</string>
<string name="update_to_bata_title">更新至测试版</string> <string name="update_to_bata_title">更新至测试版</string>
<string name="update_to_bata_summary">检查更新时查找最新的测试版本</string> <string name="update_to_bata_summary">检查更新时查找最新的测试版本</string>
<string name="default_version">当前</string>
<string name="official_version">正式版</string>
<string name="beta_release_version">测试版</string>
<string name="beta_releaseA_version">共存版</string>
</resources> </resources>
+8 -4
View File
@@ -146,11 +146,15 @@
android:summary="@string/show_add_to_shelf_alert_summary" android:summary="@string/show_add_to_shelf_alert_summary"
android:title="@string/show_add_to_shelf_alert_title" /> android:title="@string/show_add_to_shelf_alert_title" />
<io.legado.app.lib.prefs.SwitchPreference <io.legado.app.lib.prefs.NameListPreference
android:defaultValue="false" android:defaultValue="default_version"
android:key="updateToBeta" android:key="updateToVariant"
android:summary="@string/update_to_bata_summary" android:summary="@string/update_to_bata_summary"
android:title="@string/update_to_bata_title" /> android:title="@string/update_to_bata_title"
app:allowDividerAbove="false"
app:allowDividerBelow="false"
app:entries="@array/default_app_variant"
app:entryValues="@array/default_app_variant_value" />
<io.legado.app.lib.prefs.Preference <io.legado.app.lib.prefs.Preference
android:key="webPort" android:key="webPort"