diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ea28ce2..2417518 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -39,7 +39,7 @@ android { minSdk = 28 targetSdk = 35 versionCode = 31 - versionName = "3.2.0" + versionName = "3.2.0-test" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { @@ -83,10 +83,6 @@ android { isCoreLibraryDesugaringEnabled = true } - kotlinOptions { - jvmTarget = "21" - } - buildFeatures { buildConfig = true compose = true @@ -111,6 +107,10 @@ android { } } +kotlin { + jvmToolchain(21) +} + androidComponents { onVariants(selector().withBuildType("release")) { it.packaging.resources.excludes.addAll( @@ -199,7 +199,4 @@ dependencies { implementation(libs.accompanist.pager) // 依赖注入 coreLibraryDesugaring(libs.desugar) - } - - diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index bc1b3f8..96631a4 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -20,7 +20,6 @@ -dontwarn androidx.window.sidecar.Sidecar* -keep class net.sf.sevenzipjbinding.** { *; } --keep class top.laoxin.modmanager.** { *; } -keep class okhttp3.** { *; } -keep class com.squareup.okhttp.** { *; } diff --git a/app/src/main/kotlin/top/laoxin/modmanager/bean/GithubBean.kt b/app/src/main/kotlin/top/laoxin/modmanager/bean/GithubBean.kt index d5541c4..742eabe 100644 --- a/app/src/main/kotlin/top/laoxin/modmanager/bean/GithubBean.kt +++ b/app/src/main/kotlin/top/laoxin/modmanager/bean/GithubBean.kt @@ -1,18 +1,17 @@ package top.laoxin.modmanager.bean -import kotlinx.serialization.Serializable +import com.google.gson.annotations.SerializedName +import top.lings.updater.util.AppConfig -@Serializable data class GithubBean( - val tag_name: String, - val name: String, - val body: String, - val published_at: String, - val assets: List -) + @SerializedName("tag_name") val version: String, + @SerializedName("body") val info: String, + @SerializedName("assets") val assets: List +) { + fun getDownloadLink(): String { + val asset = assets.find { AppConfig.matchVariant(it.downloadLink) } ?: assets[0] + return asset.downloadLink + } +} -@Serializable -data class Asset( - val name: String, - val browser_download_url: String -) +data class GitHubAssets(@SerializedName("browser_download_url") val downloadLink: String) diff --git a/app/src/main/kotlin/top/laoxin/modmanager/network/ModManagerGithubApiService.kt b/app/src/main/kotlin/top/laoxin/modmanager/network/ModManagerGithubApiService.kt deleted file mode 100644 index 9487ccb..0000000 --- a/app/src/main/kotlin/top/laoxin/modmanager/network/ModManagerGithubApiService.kt +++ /dev/null @@ -1,41 +0,0 @@ -package top.laoxin.modmanager.network - -import com.google.gson.GsonBuilder -import retrofit2.Retrofit -import retrofit2.converter.gson.GsonConverterFactory -import retrofit2.http.GET -import top.laoxin.modmanager.bean.GithubBean - -private const val BASE_URL_GITHUB = - "https://api.github.com" - -/** - * Use the Retrofit builder to build a retrofit object using a kotlinx.serialization converter - */ -val gsonForGithub = GsonBuilder() - //.disableHtmlEscaping() - .create() -private val retrofit = Retrofit.Builder() - //.addConverterFactory(json.asConverterFactory("application/json".toMediaType())) - .addConverterFactory(GsonConverterFactory.create(gsonForGithub)) - .baseUrl(BASE_URL_GITHUB) - .build() - -/** - * Retrofit service object for creating api calls - */ -interface ModManagerGithubApiService { - @GET("repos/laoxinH/crosscore-mod-manager/releases/latest") - suspend fun getLatestRelease(): GithubBean - -} - -/** - * A public Api object that exposes the lazy-initialized Retrofit service - */ -object ModManagerGithubApi { - val retrofitService: ModManagerGithubApiService by lazy { - retrofit.create(ModManagerGithubApiService::class.java) - } -} - diff --git a/app/src/main/kotlin/top/laoxin/modmanager/ui/view/Console.kt b/app/src/main/kotlin/top/laoxin/modmanager/ui/view/Console.kt index 5045283..d8095a8 100644 --- a/app/src/main/kotlin/top/laoxin/modmanager/ui/view/Console.kt +++ b/app/src/main/kotlin/top/laoxin/modmanager/ui/view/Console.kt @@ -107,18 +107,16 @@ fun ConsoleContent(viewModel: ConsoleViewModel) { // 请求通知权限 RequestNotificationPermission() // 升级提示 - DialogCommonForUpdate( - title = stringResource(id = R.string.console_upgrade_title), - content = viewModel.updateContent, - onConfirm = { -// viewModel.setShowUpgradeDialog(false) - viewModel.openUrl(context, viewModel.downloadUrl) - }, -// onCancel = { -// viewModel.setShowUpgradeDialog(false) -// }, - showDialog = uiState.showUpgradeDialog - ) + viewModel.updateContent?.let { + DialogCommonForUpdate( + title = stringResource(id = R.string.console_upgrade_title), + content = it, + onConfirm = { + viewModel.downloadUrl?.let { url -> viewModel.openUrl(context, url) } + }, + showDialog = uiState.showUpgradeDialog + ) + } // 信息提示 DialogCommon( diff --git a/app/src/main/kotlin/top/laoxin/modmanager/ui/view/Setting.kt b/app/src/main/kotlin/top/laoxin/modmanager/ui/view/Setting.kt index e3dd3b7..60032c3 100644 --- a/app/src/main/kotlin/top/laoxin/modmanager/ui/view/Setting.kt +++ b/app/src/main/kotlin/top/laoxin/modmanager/ui/view/Setting.kt @@ -91,18 +91,18 @@ fun SettingPage() { } } - DialogCommonForUpdate( - title = stringResource(id = R.string.console_upgrade_title), - content = viewModel.updateDescription, - onConfirm = { -// viewModel.setShowUpgradeDialog(false) - viewModel.openUrl(context, viewModel.downloadUrl) - }, -// onCancel = { -// viewModel.setShowUpgradeDialog(false) -// }, - showDialog = uiState.showUpdateDialog - ) + viewModel.updateContent?.let { + DialogCommonForUpdate( + title = stringResource(id = R.string.console_upgrade_title), + content = it, + onConfirm = { + viewModel.downloadUrl?.let { url -> viewModel.openUrl(context, url) } + }, + + showDialog = uiState.showUpdateDialog + ) + } + DialogCommon( title = stringResource(id = R.string.console_game_tips_title), content = viewModel.gameInfo.tips, diff --git a/app/src/main/kotlin/top/laoxin/modmanager/ui/viewmodel/ConsoleViewModel.kt b/app/src/main/kotlin/top/laoxin/modmanager/ui/viewmodel/ConsoleViewModel.kt index 2392b9f..3bd29ec 100644 --- a/app/src/main/kotlin/top/laoxin/modmanager/ui/viewmodel/ConsoleViewModel.kt +++ b/app/src/main/kotlin/top/laoxin/modmanager/ui/viewmodel/ConsoleViewModel.kt @@ -45,7 +45,6 @@ import top.laoxin.modmanager.database.UserPreferencesRepository import top.laoxin.modmanager.database.antiHarmony.AntiHarmonyRepository import top.laoxin.modmanager.database.mods.ModRepository import top.laoxin.modmanager.network.ModManagerApi -import top.laoxin.modmanager.network.ModManagerGithubApi import top.laoxin.modmanager.observer.FlashModsObserver import top.laoxin.modmanager.tools.LogTools import top.laoxin.modmanager.tools.ModTools @@ -54,6 +53,7 @@ import top.laoxin.modmanager.tools.ToastUtils import top.laoxin.modmanager.ui.state.ConsoleUiState import top.laoxin.modmanager.ui.state.UserPreferencesState import top.laoxin.modmanager.userservice.gamestart.ProjectSnowStartService +import top.lings.updater.Updater import java.io.File @@ -67,18 +67,20 @@ class ConsoleViewModel( private var _requestPermissionPath by mutableStateOf("") // 下载地址 - private var _downloadUrl by mutableStateOf("") - val downloadUrl: String + private var _downloadUrl: String? by mutableStateOf("") + val downloadUrl: String? get() = _downloadUrl - val requestPermissionPath: String - get() = _requestPermissionPath - // 更新类容 - private var _updateContent by mutableStateOf("") - val updateContent: String + // 更新内容 + private var _updateContent: String? by mutableStateOf("") + val updateContent: String? get() = _updateContent + val requestPermissionPath: String + get() = _requestPermissionPath + + private val _uiState = MutableStateFlow(ConsoleUiState()) companion object { @@ -177,6 +179,15 @@ class ConsoleViewModel( } } + private fun checkUpdate() { + viewModelScope.launch { + val update = Updater.checkUpdate() + _downloadUrl = update?.first + _updateContent = update?.second + setShowUpgradeDialog(true) + } + } + private fun getNewInfo() { viewModelScope.launch { kotlin.runCatching { @@ -535,41 +546,6 @@ class ConsoleViewModel( // } // } // } - private fun checkUpdate() { - viewModelScope.launch { - kotlin.runCatching { - ModManagerGithubApi.retrofitService.getLatestRelease() - }.onFailure { exception -> - Log.e("ConsoleViewModel", "checkUpdate failed: ${exception.message}", exception) - }.onSuccess { release -> - Log.d("ConsoleViewModel", "Update available: $release") - // 当前版本号 - val currentVersion = ModTools.getVersionName() - // tag_name 是版本号,这里进行比较 - val releaseVersion = release.tag_name - - if (releaseVersion != currentVersion) { - Log.d("ConsoleViewModel", "Update available: $release") - - // 获取v8a资产 - val v8aAsset = release.assets.firstOrNull { - it.name.contains( - "arm64-v8a", - ignoreCase = true - ) || - it.browser_download_url.contains( - "arm64-v8a", - ignoreCase = true - ) - } - _downloadUrl = v8aAsset?.browser_download_url ?: "" - _updateContent = release.body + "\n\n无法安装请前往github下载universal版本apk" - setShowUpgradeDialog(true) - } - } - } - } - fun startGameService() { val intent = Intent(App.get(), ProjectSnowStartService::class.java) diff --git a/app/src/main/kotlin/top/laoxin/modmanager/ui/viewmodel/SettingViewModel.kt b/app/src/main/kotlin/top/laoxin/modmanager/ui/viewmodel/SettingViewModel.kt index 973e611..99a8dcc 100644 --- a/app/src/main/kotlin/top/laoxin/modmanager/ui/viewmodel/SettingViewModel.kt +++ b/app/src/main/kotlin/top/laoxin/modmanager/ui/viewmodel/SettingViewModel.kt @@ -32,11 +32,11 @@ import top.laoxin.modmanager.database.UserPreferencesRepository import top.laoxin.modmanager.database.backups.BackupRepository import top.laoxin.modmanager.database.mods.ModRepository import top.laoxin.modmanager.network.ModManagerApi -import top.laoxin.modmanager.network.ModManagerGithubApi import top.laoxin.modmanager.tools.ModTools import top.laoxin.modmanager.tools.PermissionTools import top.laoxin.modmanager.tools.ToastUtils import top.laoxin.modmanager.ui.state.SettingUiState +import top.lings.updater.Updater class SettingViewModel( @@ -66,14 +66,15 @@ class SettingViewModel( private var _gameInfo = mutableStateOf(GameInfoConstant.gameInfoList[0]) val gameInfo get() = _gameInfo.value - // 更新描述 - private var _updateDescription by mutableStateOf("") - val updateDescription get() = _updateDescription - // 下载地址 - private var _downloadUrl by mutableStateOf("") + private var _downloadUrl: String? by mutableStateOf("") + val downloadUrl: String? + get() = _downloadUrl - val downloadUrl get() = _downloadUrl + // 更新内容 + private var _updateContent: String? by mutableStateOf("") + val updateContent: String? + get() = _updateContent init { @@ -304,39 +305,10 @@ class SettingViewModel( // } fun checkUpdate() { viewModelScope.launch { - kotlin.runCatching { - ModManagerGithubApi.retrofitService.getLatestRelease() - }.onFailure { exception -> - Log.e("ConsoleViewModel", "checkUpdate failed: ${exception.message}", exception) - }.onSuccess { release -> - Log.d("ConsoleViewModel", "Update available: $release") - // 当前版本号 - val currentVersion = ModTools.getVersionName() - // tag_name 是版本号,这里进行比较 - val releaseVersion = release.tag_name - - if (releaseVersion != currentVersion) { - Log.d("ConsoleViewModel", "Update available: $release") - - // 获取v8a资产 - val v8aAsset = release.assets.firstOrNull { - it.name.contains( - "arm64-v8a", - ignoreCase = true - ) || - it.browser_download_url.contains( - "arm64-v8a", - ignoreCase = true - ) - } - _downloadUrl = v8aAsset?.browser_download_url ?: "" - _updateDescription = - release.body + "\n\n无法安装请前往github下载universal版本apk" - setShowUpgradeDialog(true) - } else { - ToastUtils.longCall(R.string.toast_no_update) - } - } + val update = Updater.checkUpdate() + _downloadUrl = update?.first + _updateContent = update?.second + setShowUpgradeDialog(true) } } diff --git a/app/src/main/kotlin/top/lings/updater/GithubApiService.kt b/app/src/main/kotlin/top/lings/updater/GithubApiService.kt new file mode 100644 index 0000000..5eaf875 --- /dev/null +++ b/app/src/main/kotlin/top/lings/updater/GithubApiService.kt @@ -0,0 +1,30 @@ +package top.lings.updater + +import com.google.gson.GsonBuilder +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import retrofit2.http.GET +import top.laoxin.modmanager.bean.GithubBean + +private const val BASE_URL_GITHUB = + "https://api.github.com" + +val gsonForGithub = GsonBuilder().create() + +private val retrofit = Retrofit.Builder() + .addConverterFactory(GsonConverterFactory.create(gsonForGithub)) + .baseUrl(BASE_URL_GITHUB) + .build() + +interface GithubApiService { + @GET("repos/laoxinH/crosscore-mod-manager/releases/latest") + suspend fun getLatestRelease(): GithubBean + +} + +object GithubApi { + val retrofitService: GithubApiService by lazy { + retrofit.create(GithubApiService::class.java) + } +} + diff --git a/app/src/main/kotlin/top/lings/updater/Updater.kt b/app/src/main/kotlin/top/lings/updater/Updater.kt new file mode 100644 index 0000000..b9a8424 --- /dev/null +++ b/app/src/main/kotlin/top/lings/updater/Updater.kt @@ -0,0 +1,26 @@ +package top.lings.updater + +import android.util.Log +import top.laoxin.modmanager.BuildConfig + +object Updater { + suspend fun checkUpdate(): Pair? { + kotlin.runCatching { + GithubApi.retrofitService.getLatestRelease() + }.onFailure { exception -> + Log.e("ConsoleViewModel", "checkUpdate failed: ${exception.message}", exception) + }.onSuccess { release -> + Log.d("ConsoleViewModel", "Update available: $release") + // 当前版本号 + val currentVersion = BuildConfig.VERSION_NAME + // version 是版本号,这里进行比较 + val releaseVersion = release.version + + if (releaseVersion != currentVersion) { + Log.d("ConsoleViewModel", "Update available: $release") + return Pair(release.getDownloadLink(), release.info) + } + } + return null + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/top/lings/updater/util/AppConfig.kt b/app/src/main/kotlin/top/lings/updater/util/AppConfig.kt new file mode 100644 index 0000000..dda4dbd --- /dev/null +++ b/app/src/main/kotlin/top/lings/updater/util/AppConfig.kt @@ -0,0 +1,12 @@ +package top.lings.updater.util + +import android.os.Build + +object AppConfig { + + private val abi = Build.SUPPORTED_ABIS[0].takeIf { + it in setOf("arm64-v8a", "x86_64", "armeabi-v7a", "x86") + } ?: "universal" + + fun matchVariant(name: String) = name.contains(abi) +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5a9f47c..8d24907 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,6 +29,7 @@ xz = "1.10" xZipJbindingXandroid = "Release-16.02-2.02" zip4j = "2.11.5" roomVersion = "2.6.1" +desugar = "2.1.3" [libraries] accompanist-pager = { module = "com.google.accompanist:accompanist-pager", version.ref = "accompanistPager" } @@ -72,7 +73,7 @@ x-zip-jbinding-xandroid = { module = "com.github.omicronapps:7-Zip-JBinding-4And xz = { module = "org.tukaani:xz", version.ref = "xz" } zip4j = { module = "net.lingala.zip4j:zip4j", version.ref = "zip4j" } androidx-roomcompiler = { group = "androidx.room", name = "room-compiler", version.ref = "roomVersion" } -desugar = "com.android.tools:desugar_jdk_libs_nio:2.1.3" +desugar = { group = "com.android.tools", name = "desugar_jdk_libs_nio", version.ref = "desugar" } [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" }