Преглед изворни кода

添加共存版的检查更新

Jason Yao пре 2 година
родитељ
комит
f896183309

+ 15 - 32
app/src/androidTest/java/io/legado/app/UpdateTest.kt

@@ -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.utils.jsonPath
+import io.legado.app.model.GithubRelease
+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
-    fun updateLollipop() {
-        val body = okHttpClient.newCall(Request.Builder().url(lastReleaseUrl).build()).execute()
-            .body!!.string()
-        val rootDoc = jsonPath.parse(body)
-        val downloadUrl =
-            rootDoc.read<List<String>>("\$.assets[?(@.name =~ /legado_lollipop_.*?apk\$/)].browser_download_url")
-        print(downloadUrl)
-    }
+        val releaseList = Gson().fromJsonArray<GithubRelease>(body)
+            .getOrElse {
+                throw NoStackTraceException("获取新版本出错 " + it.localizedMessage)
+            }
+            .flatMap { it.gitReleaseToAppReleaseInfo() }
+            .sortedByDescending { it.createdAt }
 
 
-    @Test
-    fun updateChannel() {
-        val body = okHttpClient.newCall(Request.Builder().url(lastReleaseUrl).build()).execute()
-            .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)
+        assertTrue(releaseList.isNotEmpty())
+        assertTrue(releaseList.all { it.downloadUrl.isNotBlank() })
+        assertTrue(releaseList.all { it.versionName.isNotBlank() })
     }
     }
 
 
 }
 }

+ 8 - 1
app/src/main/java/io/legado/app/constant/AppConst.kt

@@ -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
     )
     )
 
 
     /**
     /**

+ 34 - 28
app/src/main/java/io/legado/app/help/AppUpdateGitHub.kt

@@ -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.utils.jsonPath
-import io.legado.app.utils.readString
+import io.legado.app.model.AppReleaseInfo
+import io.legado.app.model.GithubRelease
+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 body = okHttpClient.newCallStrResponse {
-                url(lastReleaseUrl)
-            }.body
-            if (body.isNullOrBlank()) {
-                throw NoStackTraceException("获取新版本出错")
-            }
-            val rootDoc = jsonPath.parse(body)
-            val tagName = rootDoc.readString("$.tag_name")
-                ?: throw NoStackTraceException("获取新版本出错")
-            if (tagName > AppConst.appInfo.versionName) {
-                val updateBody = rootDoc.readString("$.body")
-                    ?: 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("已是最新版本")
-            }
+            val recentReleases = getRecentReleases()
+            recentReleases
+                .filter { it.appVariant == AppConst.appInfo.appVariant }
+                .firstOrNull { it.versionName > AppConst.appInfo.versionName }
+                ?.let {
+                    return@async AppUpdate.UpdateInfo(
+                        it.versionName,
+                        it.note,
+                        it.downloadUrl,
+                        it.name
+                    )
+                } ?: throw NoStackTraceException("已是最新版本")
         }.timeout(10000)
         }.timeout(10000)
     }
     }
 
 

+ 101 - 0
app/src/main/java/io/legado/app/model/AppReleaseInfo.kt

@@ -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
+                )
+
+        }
+    }
+}