添加共存版的检查更新
This commit is contained in:
@@ -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
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user