添加共存版的检查更新

This commit is contained in:
Jason Yao
2024-07-24 20:45:49 -07:00
parent ed4311eae9
commit 039151ecc1
4 changed files with 158 additions and 61 deletions
@@ -1,51 +1,34 @@
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.fromJsonArray
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?page=1?per_page=1"
@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().fromJsonArray<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) .flatMap { it.gitReleaseToAppReleaseInfo() }
val downloadUrl = .sortedByDescending { it.createdAt }
rootDoc.read<List<String>>("\$.assets[?(@.name =~ /legado_lollipop_.*?apk\$/)].browser_download_url")
print(downloadUrl)
}
@Test assertTrue(releaseList.isNotEmpty())
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.COMPATIBLE
}
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
) )
/** /**
@@ -1,49 +1,55 @@
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.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.GithubRelease
import io.legado.app.utils.readString import io.legado.app.utils.fromJsonArray
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 {
// TODO:在关于->其他,添加其他版本选项,使用该函数
private suspend fun getRecentReleases(): List<AppReleaseInfo> {
val lastReleaseUrl =
"https://api.github.com/repos/gedoor/legado/releases?page=1?per_page=1"
val body = okHttpClient.newCallStrResponse {
url(lastReleaseUrl)
}.body
if (body.isNullOrBlank()) {
throw NoStackTraceException("获取新版本出错")
}
return Gson().fromJsonArray<GithubRelease>(body)
.getOrElse {
throw NoStackTraceException("获取新版本出错 " + it.localizedMessage)
}
.flatMap { it.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" val recentReleases = getRecentReleases()
val body = okHttpClient.newCallStrResponse { recentReleases
url(lastReleaseUrl) .filter { it.appVariant == AppConst.appInfo.appVariant }
}.body .firstOrNull { it.versionName > AppConst.appInfo.versionName }
if (body.isNullOrBlank()) { ?.let {
throw NoStackTraceException("获取新版本出错") return@async AppUpdate.UpdateInfo(
} it.versionName,
val rootDoc = jsonPath.parse(body) it.note,
val tagName = rootDoc.readString("$.tag_name") it.downloadUrl,
?: throw NoStackTraceException("获取新版本出错") it.name
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)
} }
@@ -0,0 +1,101 @@
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,
COMPATIBLE,
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.COMPATIBLE,
timestamp,
note,
name,
apkUrl,
url
)
preRelease && name.contains("release") ->
AppReleaseInfo(
AppVariant.BETA_RELEASE,
timestamp,
note,
name,
apkUrl,
url
)
!preRelease && name.contains("release") ->
AppReleaseInfo(
AppVariant.OFFICIAL,
timestamp,
note,
name,
apkUrl,
url
)
else ->
AppReleaseInfo(
AppVariant.UNKNOWN,
timestamp,
note,
name,
apkUrl,
url
)
}
}
}