mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-07-29 08:33:43 +00:00
app: use github api to check updates
This commit is contained in:
parent
a4b8c5e46b
commit
76962f965e
@ -14,7 +14,8 @@ class ManagerInstallDialog : MarkDownDialog() {
|
|||||||
private val svc get() = ServiceLocator.networkService
|
private val svc get() = ServiceLocator.networkService
|
||||||
|
|
||||||
override suspend fun getMarkdownText(): String {
|
override suspend fun getMarkdownText(): String {
|
||||||
val text = svc.fetchString(Info.remote.magisk.note)
|
val str = Info.remote.magisk.note
|
||||||
|
val text = if (str.startsWith("http", true)) svc.fetchString(str) else str
|
||||||
// Cache the changelog
|
// Cache the changelog
|
||||||
AppContext.cacheDir.listFiles { _, name -> name.endsWith(".md") }.orEmpty().forEach {
|
AppContext.cacheDir.listFiles { _, name -> name.endsWith(".md") }.orEmpty().forEach {
|
||||||
it.delete()
|
it.delete()
|
||||||
|
@ -71,11 +71,14 @@ class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel()
|
|||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
val file = File(AppContext.cacheDir, "${BuildConfig.APP_VERSION_CODE}.md")
|
val file = File(AppContext.cacheDir, "${BuildConfig.APP_VERSION_CODE}.md")
|
||||||
|
val note = Info.remote.magisk.note
|
||||||
val text = when {
|
val text = when {
|
||||||
file.exists() -> file.readText()
|
file.exists() -> file.readText()
|
||||||
Const.Url.CHANGELOG_URL.isEmpty() -> ""
|
Const.APP_IS_CANARY && note.isEmpty() -> ""
|
||||||
|
Const.APP_IS_CANARY && !note.startsWith("http", true) -> note
|
||||||
else -> {
|
else -> {
|
||||||
val str = svc.fetchString(Const.Url.CHANGELOG_URL)
|
val url = if (Const.APP_IS_CANARY) note else Const.Url.CHANGELOG_URL
|
||||||
|
val str = svc.fetchString(url)
|
||||||
file.writeText(str)
|
file.writeText(str)
|
||||||
str
|
str
|
||||||
}
|
}
|
||||||
|
@ -43,8 +43,7 @@ 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"
|
||||||
|
|
||||||
val CHANGELOG_URL = if (APP_IS_CANARY) Info.remote.magisk.note
|
const val CHANGELOG_URL = "https://topjohnwu.github.io/Magisk/releases/${BuildConfig.APP_VERSION_CODE}.md"
|
||||||
else "https://topjohnwu.github.io/Magisk/releases/${BuildConfig.APP_VERSION_CODE}.md"
|
|
||||||
|
|
||||||
const val GITHUB_RAW_URL = "https://raw.githubusercontent.com/"
|
const val GITHUB_RAW_URL = "https://raw.githubusercontent.com/"
|
||||||
const val GITHUB_API_URL = "https://api.github.com/"
|
const val GITHUB_API_URL = "https://api.github.com/"
|
||||||
|
@ -1,25 +1,16 @@
|
|||||||
package com.topjohnwu.magisk.core.data
|
package com.topjohnwu.magisk.core.data
|
||||||
|
|
||||||
import com.topjohnwu.magisk.core.model.BranchInfo
|
|
||||||
import com.topjohnwu.magisk.core.model.ModuleJson
|
import com.topjohnwu.magisk.core.model.ModuleJson
|
||||||
|
import com.topjohnwu.magisk.core.model.Release
|
||||||
import com.topjohnwu.magisk.core.model.UpdateInfo
|
import com.topjohnwu.magisk.core.model.UpdateInfo
|
||||||
import okhttp3.ResponseBody
|
import okhttp3.ResponseBody
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Headers
|
import retrofit2.http.Headers
|
||||||
import retrofit2.http.Path
|
import retrofit2.http.Path
|
||||||
|
import retrofit2.http.Query
|
||||||
import retrofit2.http.Streaming
|
import retrofit2.http.Streaming
|
||||||
import retrofit2.http.Url
|
import retrofit2.http.Url
|
||||||
|
|
||||||
private const val BRANCH = "branch"
|
|
||||||
private const val REPO = "repo"
|
|
||||||
private const val FILE = "file"
|
|
||||||
|
|
||||||
interface GithubPageServices {
|
|
||||||
|
|
||||||
@GET
|
|
||||||
suspend fun fetchUpdateJSON(@Url file: String): UpdateInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
interface RawServices {
|
interface RawServices {
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@ -32,14 +23,26 @@ interface RawServices {
|
|||||||
@GET
|
@GET
|
||||||
suspend fun fetchModuleJson(@Url url: String): ModuleJson
|
suspend fun fetchModuleJson(@Url url: String): ModuleJson
|
||||||
|
|
||||||
|
@GET
|
||||||
|
suspend fun fetchUpdateJSON(@Url url: String): UpdateInfo
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GithubApiServices {
|
interface GithubApiServices {
|
||||||
|
|
||||||
@GET("repos/{$REPO}/branches/{$BRANCH}")
|
@GET("/repos/{owner}/{repo}/releases")
|
||||||
@Headers("Accept: application/vnd.github.v3+json")
|
@Headers("Accept: application/vnd.github+json")
|
||||||
suspend fun fetchBranch(
|
suspend fun fetchRelease(
|
||||||
@Path(REPO, encoded = true) repo: String,
|
@Path("owner") owner: String = "topjohnwu",
|
||||||
@Path(BRANCH) branch: String
|
@Path("repo") repo: String = "Magisk",
|
||||||
): BranchInfo
|
@Query("per_page") per: Int = 10,
|
||||||
|
@Query("page") page: Int = 1,
|
||||||
|
): List<Release>
|
||||||
|
|
||||||
|
@GET("/repos/{owner}/{repo}/releases/latest")
|
||||||
|
@Headers("Accept: application/vnd.github+json")
|
||||||
|
suspend fun fetchLatestRelease(
|
||||||
|
@Path("owner") owner: String = "topjohnwu",
|
||||||
|
@Path("repo") repo: String = "Magisk",
|
||||||
|
): Release
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,8 @@ object ServiceLocator {
|
|||||||
val markwon by lazy { createMarkwon(AppContext) }
|
val markwon by lazy { createMarkwon(AppContext) }
|
||||||
val networkService by lazy {
|
val networkService by lazy {
|
||||||
NetworkService(
|
NetworkService(
|
||||||
createApiService(retrofit, Const.Url.GITHUB_PAGE_URL),
|
|
||||||
createApiService(retrofit, Const.Url.GITHUB_RAW_URL),
|
createApiService(retrofit, Const.Url.GITHUB_RAW_URL),
|
||||||
|
createApiService(retrofit, Const.Url.GITHUB_API_URL),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,11 +27,16 @@ data class ModuleJson(
|
|||||||
)
|
)
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class CommitInfo(
|
data class ReleaseAssets(
|
||||||
val sha: String
|
val name: String,
|
||||||
|
val browser_download_url: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class BranchInfo(
|
data class Release(
|
||||||
val commit: CommitInfo
|
val tag_name: String,
|
||||||
|
val name: String,
|
||||||
|
val prerelease: Boolean,
|
||||||
|
val assets: List<ReleaseAssets>,
|
||||||
|
val body: String,
|
||||||
)
|
)
|
||||||
|
@ -8,15 +8,18 @@ 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
|
||||||
import com.topjohnwu.magisk.core.Config.Value.STABLE_CHANNEL
|
import com.topjohnwu.magisk.core.Config.Value.STABLE_CHANNEL
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.data.GithubPageServices
|
import com.topjohnwu.magisk.core.data.GithubApiServices
|
||||||
import com.topjohnwu.magisk.core.data.RawServices
|
import com.topjohnwu.magisk.core.data.RawServices
|
||||||
|
import com.topjohnwu.magisk.core.model.MagiskJson
|
||||||
|
import com.topjohnwu.magisk.core.model.Release
|
||||||
|
import com.topjohnwu.magisk.core.model.UpdateInfo
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
class NetworkService(
|
class NetworkService(
|
||||||
private val pages: GithubPageServices,
|
private val raw: RawServices,
|
||||||
private val raw: RawServices
|
private val api: GithubApiServices,
|
||||||
) {
|
) {
|
||||||
suspend fun fetchUpdate() = safe {
|
suspend fun fetchUpdate() = safe {
|
||||||
var info = when (Config.updateChannel) {
|
var info = when (Config.updateChannel) {
|
||||||
@ -36,11 +39,39 @@ class NetworkService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateInfo
|
// UpdateInfo
|
||||||
private suspend fun fetchStableUpdate() = pages.fetchUpdateJSON("stable.json")
|
private suspend fun fetchStableUpdate(rel: Release? = null): UpdateInfo {
|
||||||
private suspend fun fetchBetaUpdate() = pages.fetchUpdateJSON("beta.json")
|
val release = rel ?: api.fetchLatestRelease()
|
||||||
private suspend fun fetchCanaryUpdate() = pages.fetchUpdateJSON("canary.json")
|
val name = release.tag_name.drop(1)
|
||||||
private suspend fun fetchDebugUpdate() = pages.fetchUpdateJSON("debug.json")
|
val info = MagiskJson(
|
||||||
private suspend fun fetchCustomUpdate(url: String) = pages.fetchUpdateJSON(url)
|
name, (name.toFloat() * 1000).toInt(),
|
||||||
|
release.assets[0].browser_download_url, release.body
|
||||||
|
)
|
||||||
|
return UpdateInfo(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun fetchBetaUpdate(): UpdateInfo {
|
||||||
|
val release = api.fetchRelease().find { it.tag_name[0] == 'v' && it.prerelease }
|
||||||
|
return fetchStableUpdate(release)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun fetchCanaryUpdate(): UpdateInfo {
|
||||||
|
val release = api.fetchRelease().find { it.tag_name.startsWith("canary-") }
|
||||||
|
val info = MagiskJson(
|
||||||
|
release!!.name.substring(8, 16),
|
||||||
|
release.tag_name.drop(7).toInt(),
|
||||||
|
release.assets.find { it.name == "app-release.apk" }!!.browser_download_url,
|
||||||
|
release.body
|
||||||
|
)
|
||||||
|
return UpdateInfo(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun fetchDebugUpdate(): UpdateInfo {
|
||||||
|
val release = fetchCanaryUpdate()
|
||||||
|
val link = release.magisk.link.replace("app-release.apk", "app-debug.apk")
|
||||||
|
return UpdateInfo(release.magisk.copy(link = link))
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun fetchCustomUpdate(url: String) = raw.fetchUpdateJSON(url)
|
||||||
|
|
||||||
private inline fun <T> safe(factory: () -> T): T? {
|
private inline fun <T> safe(factory: () -> T): T? {
|
||||||
return try {
|
return try {
|
||||||
|
@ -13,24 +13,28 @@ android {
|
|||||||
namespace = "com.topjohnwu.magisk"
|
namespace = "com.topjohnwu.magisk"
|
||||||
|
|
||||||
val canary = !Config.version.contains(".")
|
val canary = !Config.version.contains(".")
|
||||||
|
val base = "https://github.com/topjohnwu/Magisk/releases/download/"
|
||||||
val url = if (canary) null
|
val url = base + "v${Config.version}/Magisk-v${Config.version}.apk"
|
||||||
else "https://github.com/topjohnwu/Magisk/releases/download/v${Config.version}/Magisk-v${Config.version}.apk"
|
val canaryUrl = base + "canary-${Config.versionCode}/"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "com.topjohnwu.magisk"
|
applicationId = "com.topjohnwu.magisk"
|
||||||
versionCode = 1
|
versionCode = 1
|
||||||
versionName = "1.0"
|
versionName = "1.0"
|
||||||
buildConfigField("String", "APK_URL", url?.let { "\"$it\"" } ?: "null" )
|
buildConfigField("String", "APK_URL", "\"$url\"")
|
||||||
buildConfigField("int", "STUB_VERSION", Config.stubVersion)
|
buildConfigField("int", "STUB_VERSION", Config.stubVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
|
if (canary) buildConfigField("String", "APK_URL", "\"${canaryUrl}app-release.apk\"")
|
||||||
proguardFiles("proguard-rules.pro")
|
proguardFiles("proguard-rules.pro")
|
||||||
isMinifyEnabled = true
|
isMinifyEnabled = true
|
||||||
isShrinkResources = false
|
isShrinkResources = false
|
||||||
}
|
}
|
||||||
|
debug {
|
||||||
|
if (canary) buildConfigField("String", "APK_URL", "\"${canaryUrl}app-debug.apk\"")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
|
@ -27,8 +27,6 @@ import com.topjohnwu.magisk.net.Networking;
|
|||||||
import com.topjohnwu.magisk.net.Request;
|
import com.topjohnwu.magisk.net.Request;
|
||||||
import com.topjohnwu.magisk.utils.APKInstall;
|
import com.topjohnwu.magisk.utils.APKInstall;
|
||||||
|
|
||||||
import org.json.JSONException;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
@ -48,13 +46,8 @@ import javax.crypto.spec.SecretKeySpec;
|
|||||||
public class DownloadActivity extends Activity {
|
public class DownloadActivity extends Activity {
|
||||||
|
|
||||||
private static final String APP_NAME = "Magisk";
|
private static final String APP_NAME = "Magisk";
|
||||||
private static final String JSON_URL = BuildConfig.DEBUG ?
|
|
||||||
"https://topjohnwu.github.io/magisk-files/debug.json" :
|
|
||||||
"https://topjohnwu.github.io/magisk-files/canary.json";
|
|
||||||
|
|
||||||
private String apkLink = BuildConfig.APK_URL;
|
|
||||||
private Context themed;
|
private Context themed;
|
||||||
private ProgressDialog dialog;
|
|
||||||
private boolean dynLoad;
|
private boolean dynLoad;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -75,11 +68,7 @@ public class DownloadActivity extends Activity {
|
|||||||
ProviderInstaller.install(this);
|
ProviderInstaller.install(this);
|
||||||
|
|
||||||
if (Networking.checkNetworkStatus(this)) {
|
if (Networking.checkNetworkStatus(this)) {
|
||||||
if (BuildConfig.APK_URL == null) {
|
|
||||||
fetchCanary();
|
|
||||||
} else {
|
|
||||||
showDialog();
|
showDialog();
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
new AlertDialog.Builder(themed)
|
new AlertDialog.Builder(themed)
|
||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
@ -115,23 +104,10 @@ public class DownloadActivity extends Activity {
|
|||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchCanary() {
|
|
||||||
dialog = ProgressDialog.show(themed, "", "", true);
|
|
||||||
request(JSON_URL).getAsJSONObject(json -> {
|
|
||||||
dialog.dismiss();
|
|
||||||
try {
|
|
||||||
apkLink = json.getJSONObject("magisk").getString("link");
|
|
||||||
showDialog();
|
|
||||||
} catch (JSONException e) {
|
|
||||||
error(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void dlAPK() {
|
private void dlAPK() {
|
||||||
dialog = ProgressDialog.show(themed, getString(dling), getString(dling) + " " + APP_NAME, true);
|
ProgressDialog.show(themed, getString(dling), getString(dling) + " " + APP_NAME, true);
|
||||||
// Download and upgrade the app
|
// Download and upgrade the app
|
||||||
var request = request(apkLink).setExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
var request = request(BuildConfig.APK_URL).setExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
if (dynLoad) {
|
if (dynLoad) {
|
||||||
request.getAsFile(StubApk.current(this), file -> StubApk.restartProcess(this));
|
request.getAsFile(StubApk.current(this), file -> StubApk.restartProcess(this));
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user