Deprecate canary channel

This commit is contained in:
topjohnwu 2025-06-20 00:22:17 -07:00
parent 39f2940bd1
commit 04008949b8
7 changed files with 53 additions and 63 deletions

View File

@ -14,9 +14,8 @@ import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseViewModel import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.core.AppContext import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.BuildConfig import com.topjohnwu.magisk.core.BuildConfig.APP_VERSION_CODE
import com.topjohnwu.magisk.core.Config import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Info import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.base.ContentResultCallback import com.topjohnwu.magisk.core.base.ContentResultCallback
import com.topjohnwu.magisk.core.ktx.toast import com.topjohnwu.magisk.core.ktx.toast
@ -70,17 +69,16 @@ class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel()
init { init {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
val file = File(AppContext.cacheDir, "${BuildConfig.APP_VERSION_CODE}.md") val noteFile = File(AppContext.cacheDir, "${APP_VERSION_CODE}.md")
val text = when { val noteText = when {
file.exists() -> file.readText() noteFile.exists() -> noteFile.readText()
else -> { else -> {
val str = if (Const.APP_IS_CANARY) Info.update.note val note = svc.fetchUpdate(APP_VERSION_CODE).note
else svc.fetchString(Const.Url.CHANGELOG_URL) noteFile.writeText(note)
file.writeText(str) note
str
} }
} }
val spanned = markwon.toMarkdown(text) val spanned = markwon.toMarkdown(noteText)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
notes = spanned notes = spanned
} }

View File

@ -151,15 +151,7 @@ object UpdateChannel : BaseSettingsItem.Selector() {
} }
override val title = CoreR.string.settings_update_channel_title.asText() override val title = CoreR.string.settings_update_channel_title.asText()
override val entryRes = CoreR.array.update_channel override val entryRes = CoreR.array.update_channel
override fun entries(res: Resources): Array<String> {
return super.entries(res).let {
if (!Const.APP_IS_CANARY && !BuildConfig.DEBUG)
it.copyOfRange(0, Config.Value.CANARY_CHANNEL)
else it
}
}
} }
object UpdateChannelUrl : BaseSettingsItem.Input() { object UpdateChannelUrl : BaseSettingsItem.Input() {

View File

@ -33,7 +33,7 @@ object Config : PreferenceConfig, DBConfig {
const val SU_REAUTH = "su_reauth" const val SU_REAUTH = "su_reauth"
const val SU_TAPJACK = "su_tapjack" const val SU_TAPJACK = "su_tapjack"
const val CHECK_UPDATES = "check_update" const val CHECK_UPDATES = "check_update"
const val UPDATE_CHANNEL = "update_channel" const val RELEASE_CHANNEL = "release_channel"
const val CUSTOM_CHANNEL = "custom_channel" const val CUSTOM_CHANNEL = "custom_channel"
const val LOCALE = "locale" const val LOCALE = "locale"
const val DARK_THEME = "dark_theme_extended" const val DARK_THEME = "dark_theme_extended"
@ -48,7 +48,7 @@ object Config : PreferenceConfig, DBConfig {
SU_AUTO_RESPONSE, SU_REAUTH, SU_TAPJACK) SU_AUTO_RESPONSE, SU_REAUTH, SU_TAPJACK)
} }
object Value { object OldValue {
// Update channels // Update channels
const val DEFAULT_CHANNEL = -1 const val DEFAULT_CHANNEL = -1
const val STABLE_CHANNEL = 0 const val STABLE_CHANNEL = 0
@ -56,6 +56,15 @@ object Config : PreferenceConfig, DBConfig {
const val CUSTOM_CHANNEL = 2 const val CUSTOM_CHANNEL = 2
const val CANARY_CHANNEL = 3 const val CANARY_CHANNEL = 3
const val DEBUG_CHANNEL = 4 const val DEBUG_CHANNEL = 4
}
object Value {
// Update channels
const val DEFAULT_CHANNEL = -1
const val STABLE_CHANNEL = 0
const val BETA_CHANNEL = 1
const val DEBUG_CHANNEL = 2
const val CUSTOM_CHANNEL = 3
// root access mode // root access mode
const val ROOT_ACCESS_DISABLED = 0 const val ROOT_ACCESS_DISABLED = 0
@ -86,14 +95,6 @@ object Config : PreferenceConfig, DBConfig {
val TIMEOUT_LIST = longArrayOf(0, -1, 10, 20, 30, 60) val TIMEOUT_LIST = longArrayOf(0, -1, 10, 20, 30, 60)
} }
private val defaultChannel =
if (BuildConfig.DEBUG)
Value.DEBUG_CHANNEL
else if (Const.APP_IS_CANARY)
Value.CANARY_CHANNEL
else
Value.DEFAULT_CHANNEL
@JvmField var keepVerity = false @JvmField var keepVerity = false
@JvmField var keepEnc = false @JvmField var keepEnc = false
@JvmField var recovery = false @JvmField var recovery = false
@ -109,7 +110,7 @@ object Config : PreferenceConfig, DBConfig {
private var checkUpdatePrefs by preference(Key.CHECK_UPDATES, true) private var checkUpdatePrefs by preference(Key.CHECK_UPDATES, true)
private var localePrefs by preference(Key.LOCALE, "") private var localePrefs by preference(Key.LOCALE, "")
var doh by preference(Key.DOH, false) var doh by preference(Key.DOH, false)
var updateChannel by preferenceStrInt(Key.UPDATE_CHANNEL, defaultChannel) var updateChannel by preference(Key.RELEASE_CHANNEL, Value.DEFAULT_CHANNEL)
var customChannelUrl by preference(Key.CUSTOM_CHANNEL, "") var customChannelUrl by preference(Key.CUSTOM_CHANNEL, "")
var downloadDir by preference(Key.DOWNLOAD_DIR, "") var downloadDir by preference(Key.DOWNLOAD_DIR, "")
var randName by preference(Key.RAND_NAME, true) var randName by preference(Key.RAND_NAME, true)
@ -148,6 +149,7 @@ object Config : PreferenceConfig, DBConfig {
var suTapjack by preference(Key.SU_TAPJACK, true) var suTapjack by preference(Key.SU_TAPJACK, true)
private const val SU_FINGERPRINT = "su_fingerprint" private const val SU_FINGERPRINT = "su_fingerprint"
private const val UPDATE_CHANNEL = "update_channel"
fun toBundle(): Bundle { fun toBundle(): Bundle {
val map = prefs.all - Key.NO_MIGRATION val map = prefs.all - Key.NO_MIGRATION
@ -183,17 +185,23 @@ object Config : PreferenceConfig, DBConfig {
} }
prefs.edit { prefs.edit {
// Settings migration // Migrate su_fingerprint
if (prefs.getBoolean(SU_FINGERPRINT, false)) if (prefs.getBoolean(SU_FINGERPRINT, false))
suBiometric = true suBiometric = true
remove(SU_FINGERPRINT) remove(SU_FINGERPRINT)
prefs.getString(Key.UPDATE_CHANNEL, null).also {
if (it == null || // Migrate update_channel
it.toInt() > Value.DEBUG_CHANNEL || prefs.getString(UPDATE_CHANNEL, null)?.let {
it.toInt() < Value.DEFAULT_CHANNEL) { val channel = when (it.toInt()) {
putString(Key.UPDATE_CHANNEL, defaultChannel.toString()) OldValue.STABLE_CHANNEL -> Value.STABLE_CHANNEL
} OldValue.CANARY_CHANNEL, OldValue.BETA_CHANNEL -> Value.BETA_CHANNEL
} OldValue.DEBUG_CHANNEL -> Value.DEBUG_CHANNEL
OldValue.CUSTOM_CHANNEL -> Value.CUSTOM_CHANNEL
else -> Value.DEFAULT_CHANNEL
}
putInt(Key.RELEASE_CHANNEL, channel)
}
remove(UPDATE_CHANNEL)
} }
} }
} }

View File

@ -21,18 +21,14 @@ object Const {
// Misc // Misc
val USER_ID = Process.myUid() / 100000 val USER_ID = Process.myUid() / 100000
val APP_IS_CANARY get() = Version.isCanary(APP_VERSION_CODE)
object Version { object Version {
const val MIN_VERSION = "v22.0" const val MIN_VERSION = "v22.0"
const val MIN_VERCODE = 22000 const val MIN_VERCODE = 22000
fun atLeast_24_0() = Info.env.versionCode >= 24000 || isCanary() fun atLeast_24_0() = Info.env.versionCode >= 24000
fun atLeast_25_0() = Info.env.versionCode >= 25000 || isCanary() fun atLeast_25_0() = Info.env.versionCode >= 25000
fun atLeast_28_0() = Info.env.versionCode >= 28000 || isCanary() fun atLeast_28_0() = Info.env.versionCode >= 28000
fun isCanary() = isCanary(Info.env.versionCode)
fun isCanary(ver: Int) = ver > 0 && ver % 100 != 0
} }
object ID { object ID {
@ -44,8 +40,6 @@ object Const {
const val PATREON_URL = "https://www.patreon.com/topjohnwu" const val PATREON_URL = "https://www.patreon.com/topjohnwu"
const val SOURCE_CODE_URL = "https://github.com/topjohnwu/Magisk" const val SOURCE_CODE_URL = "https://github.com/topjohnwu/Magisk"
const val CHANGELOG_URL = "https://topjohnwu.github.io/Magisk/releases/${APP_VERSION_CODE}.md"
const val GITHUB_API_URL = "https://api.github.com/" const val GITHUB_API_URL = "https://api.github.com/"
const val GITHUB_PAGE_URL = "https://topjohnwu.github.io/magisk-files/" const val GITHUB_PAGE_URL = "https://topjohnwu.github.io/magisk-files/"
const val INVALID_URL = "https://example.com/" const val INVALID_URL = "https://example.com/"

View File

@ -1,8 +1,8 @@
package com.topjohnwu.magisk.core.repository package com.topjohnwu.magisk.core.repository
import com.topjohnwu.magisk.core.BuildConfig
import com.topjohnwu.magisk.core.Config import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Config.Value.BETA_CHANNEL import com.topjohnwu.magisk.core.Config.Value.BETA_CHANNEL
import com.topjohnwu.magisk.core.Config.Value.CANARY_CHANNEL
import com.topjohnwu.magisk.core.Config.Value.CUSTOM_CHANNEL import com.topjohnwu.magisk.core.Config.Value.CUSTOM_CHANNEL
import com.topjohnwu.magisk.core.Config.Value.DEBUG_CHANNEL import com.topjohnwu.magisk.core.Config.Value.DEBUG_CHANNEL
import com.topjohnwu.magisk.core.Config.Value.DEFAULT_CHANNEL import com.topjohnwu.magisk.core.Config.Value.DEFAULT_CHANNEL
@ -24,21 +24,25 @@ class NetworkService(
) { ) {
suspend fun fetchUpdate() = safe { suspend fun fetchUpdate() = safe {
var info = when (Config.updateChannel) { var info = when (Config.updateChannel) {
DEFAULT_CHANNEL, STABLE_CHANNEL -> fetchStableUpdate() DEFAULT_CHANNEL -> if (BuildConfig.DEBUG) fetchDebugUpdate() else fetchStableUpdate()
STABLE_CHANNEL -> fetchStableUpdate()
BETA_CHANNEL -> fetchBetaUpdate() BETA_CHANNEL -> fetchBetaUpdate()
CANARY_CHANNEL -> fetchCanaryUpdate()
DEBUG_CHANNEL -> fetchDebugUpdate() DEBUG_CHANNEL -> fetchDebugUpdate()
CUSTOM_CHANNEL -> fetchCustomUpdate(Config.customChannelUrl) CUSTOM_CHANNEL -> fetchCustomUpdate(Config.customChannelUrl)
else -> throw IllegalArgumentException() else -> throw IllegalArgumentException()
} }
if (info.versionCode < Info.env.versionCode && if (info.versionCode < Info.env.versionCode &&
Config.updateChannel == DEFAULT_CHANNEL) { Config.updateChannel == DEFAULT_CHANNEL &&
!BuildConfig.DEBUG
) {
Config.updateChannel = BETA_CHANNEL Config.updateChannel = BETA_CHANNEL
info = fetchBetaUpdate() info = fetchBetaUpdate()
} }
info info
} }
suspend fun fetchUpdate(version: Int) = findRelease { it.versionCode == version }.asInfo()
// Keep going through all release pages until we find a match // Keep going through all release pages until we find a match
private suspend inline fun findRelease(predicate: (Release) -> Boolean): Release? { private suspend inline fun findRelease(predicate: (Release) -> Boolean): Release? {
var page = 1 var page = 1
@ -58,14 +62,13 @@ class NetworkService(
} }
} }
suspend fun fetchUpdate(version: Int) = findRelease { it.versionCode == version }?.asInfo() private inline fun Release?.asInfo(
private inline fun Release.asInfo(
selector: (ReleaseAssets) -> Boolean = { selector: (ReleaseAssets) -> Boolean = {
// Default selector picks the non-debug APK // Default selector picks the non-debug APK
it.name.run { endsWith(".apk") && !contains("debug") } it.name.run { endsWith(".apk") && !contains("debug") }
}): UpdateInfo { }): UpdateInfo {
return if (tag[0] == 'v') asPublicInfo(selector) return if (this == null) UpdateInfo()
else if (tag[0] == 'v') asPublicInfo(selector)
else asCanaryInfo(selector) else asCanaryInfo(selector)
} }
@ -89,20 +92,16 @@ class NetworkService(
) )
} }
// Version number: canary == debug >= beta >= stable // Version number: debug == beta >= stable
// Find the latest non-prerelease // Find the latest non-prerelease
private suspend fun fetchStableUpdate() = api.fetchLatestRelease().asInfo() private suspend fun fetchStableUpdate() = api.fetchLatestRelease().asInfo()
// Find the latest non-canary release
private suspend fun fetchBetaUpdate() = findRelease { it.tag[0] == 'v' }!!.asInfo()
// Find the latest release, regardless whether it's prerelease // Find the latest release, regardless whether it's prerelease
private suspend fun fetchCanary() = findRelease { true }!! private suspend fun fetchBetaUpdate() = findRelease { true }.asInfo()
private suspend fun fetchCanaryUpdate() = fetchCanary().asInfo() private suspend fun fetchDebugUpdate() =
findRelease { true }.asInfo { it.name == "app-debug.apk" }
private suspend fun fetchDebugUpdate() = fetchCanary().asInfo { it.name == "app-debug.apk" }
private suspend fun fetchCustomUpdate(url: String): UpdateInfo { private suspend fun fetchCustomUpdate(url: String): UpdateInfo {
val info = raw.fetchUpdateJson(url).magisk val info = raw.fetchUpdateJson(url).magisk

View File

@ -63,9 +63,7 @@
<string-array name="update_channel"> <string-array name="update_channel">
<item>@string/settings_update_stable</item> <item>@string/settings_update_stable</item>
<item>@string/settings_update_beta</item> <item>@string/settings_update_beta</item>
<item>@string/settings_update_debug</item>
<item>@string/settings_update_custom</item> <item>@string/settings_update_custom</item>
<item>Canary</item>
<item>Debug</item>
</string-array> </string-array>
</resources> </resources>

View File

@ -139,6 +139,7 @@
<string name="settings_update_channel_title">Update Channel</string> <string name="settings_update_channel_title">Update Channel</string>
<string name="settings_update_stable">Stable</string> <string name="settings_update_stable">Stable</string>
<string name="settings_update_beta">Beta</string> <string name="settings_update_beta">Beta</string>
<string name="settings_update_debug">Debug</string>
<string name="settings_update_custom">Custom</string> <string name="settings_update_custom">Custom</string>
<string name="settings_update_custom_msg">Insert a custom channel URL</string> <string name="settings_update_custom_msg">Insert a custom channel URL</string>
<string name="settings_zygisk_summary">Run parts of Magisk in the zygote daemon</string> <string name="settings_zygisk_summary">Run parts of Magisk in the zygote daemon</string>