feat(Settings): allow directly exporting patched apk
This commit is contained in:
parent
172b53c5f6
commit
e83374253c
8 changed files with 62 additions and 44 deletions
17
INFO.md
17
INFO.md
|
|
@ -1,20 +1,3 @@
|
|||
## Obtaining Patched APKs
|
||||
|
||||
Unfortunately, starting with Android 10, file managers cannot access external data of other apps without root.
|
||||
You will have to manually download the patched APK via `adb`.
|
||||
|
||||
ADB command (assuming the first user profile):
|
||||
|
||||
```shell
|
||||
$ adb pull /storage/emulated/0/Android/data/com.aliucord.manager/cache/patched/patched.apk
|
||||
```
|
||||
|
||||
This file should only be used after the patching process has successfully completed.
|
||||
If the process failed at any step before "Installing", then the APK will be unusable.
|
||||
|
||||
The patched APK **should not be reused on another device**. Refer to the section [below](#backing-up-aliucord)
|
||||
for more information.
|
||||
|
||||
## Backing up Aliucord
|
||||
|
||||
Note: This section is about the app installation itself, not the installed plugins, themes, and settings.
|
||||
|
|
|
|||
|
|
@ -101,6 +101,11 @@ class PathManager(
|
|||
fun patchingWorkingDir() = patchingDir
|
||||
.resolve("patched")
|
||||
|
||||
/**
|
||||
* The APK that is worked on during the patching process.
|
||||
*/
|
||||
fun patchedApk() = patchingWorkingDir().resolve("patched.apk")
|
||||
|
||||
private companion object {
|
||||
/**
|
||||
* List all the files that follow the ```[SemVer].custom.*``` naming scheme.
|
||||
|
|
|
|||
|
|
@ -38,6 +38,5 @@ class AliucordGithubService(
|
|||
const val MANAGER_REPO = "Manager"
|
||||
|
||||
const val DATA_JSON_URL = "https://raw.githubusercontent.com/$ORG/$MAIN_REPO/builds/data.json"
|
||||
const val PATCHED_APKS_INFO_URL = "https://github.com/$ORG/$MANAGER_REPO/blob/main/INFO.md#obtaining-patched-apks"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,7 @@ class CopyDependenciesStep : Step(), KoinComponent {
|
|||
/**
|
||||
* The target APK file which can be modified during patching
|
||||
*/
|
||||
val patchedApk: File = paths.patchingWorkingDir()
|
||||
.resolve("patched.apk")
|
||||
val patchedApk: File = paths.patchedApk()
|
||||
|
||||
override val group = StepGroup.Download
|
||||
override val localizedName = R.string.patch_step_copy_deps
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
package com.aliucord.manager.ui.screens.settings
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.core.content.FileProvider
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import com.aliucord.manager.BuildConfig
|
||||
|
|
@ -18,6 +21,9 @@ class SettingsModel(
|
|||
) : ScreenModel {
|
||||
val installInfo = InstallInfo
|
||||
|
||||
var patchedApkExists by mutableStateOf(paths.patchedApk().exists())
|
||||
private set
|
||||
|
||||
var showThemeDialog by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
|
|
@ -39,6 +45,7 @@ class SettingsModel(
|
|||
|
||||
fun clearCache() = screenModelScope.launchBlock {
|
||||
paths.clearCache()
|
||||
patchedApkExists = false
|
||||
application.showToast(R.string.action_cleared_cache)
|
||||
}
|
||||
|
||||
|
|
@ -47,6 +54,35 @@ class SettingsModel(
|
|||
application.showToast(R.string.action_copied)
|
||||
}
|
||||
|
||||
fun shareApk() = screenModelScope.launchBlock {
|
||||
val file = paths.patchingWorkingDir().resolve("patched.apk")
|
||||
val fileUri = FileProvider.getUriForFile(
|
||||
/* context = */ application,
|
||||
/* authority = */ "${BuildConfig.APPLICATION_ID}.provider",
|
||||
/* file = */ file,
|
||||
/* displayName = */ "Aliucord.apk",
|
||||
)
|
||||
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
.setType("application/vnd.android.package-archive")
|
||||
.putExtra(Intent.EXTRA_STREAM, fileUri)
|
||||
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
.let {
|
||||
Intent.createChooser(
|
||||
/* target = */ it,
|
||||
/* title = */ application.getString(R.string.log_action_export_apk),
|
||||
)
|
||||
}
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
|
||||
try {
|
||||
application.startActivity(intent)
|
||||
} catch (t: Throwable) {
|
||||
Log.w(BuildConfig.TAG, "Failed to share APK", t)
|
||||
application.showToast(R.string.status_failed)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@Suppress("KotlinConstantConditions")
|
||||
private val InstallInfo: String = """
|
||||
|
|
|
|||
|
|
@ -15,14 +15,12 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import cafe.adriel.voyager.koin.koinScreenModel
|
||||
import com.aliucord.manager.R
|
||||
import com.aliucord.manager.network.services.AliucordGithubService
|
||||
import com.aliucord.manager.ui.components.BackButton
|
||||
import com.aliucord.manager.ui.components.MainActionButton
|
||||
import com.aliucord.manager.ui.components.settings.*
|
||||
|
|
@ -94,10 +92,7 @@ class SettingsScreen : Screen, Parcelable {
|
|||
secondaryLabel = stringResource(R.string.setting_developer_options_desc),
|
||||
pref = preferences.devMode,
|
||||
icon = { Icon(painterResource(R.drawable.ic_code), null) },
|
||||
onPrefChange = {
|
||||
preferences.devMode = it
|
||||
clearedCache = false // Cache dir changes with this setting
|
||||
},
|
||||
onPrefChange = { preferences.devMode = it },
|
||||
)
|
||||
|
||||
SettingsSwitch(
|
||||
|
|
@ -105,13 +100,22 @@ class SettingsScreen : Screen, Parcelable {
|
|||
secondaryLabel = stringResource(R.string.setting_keep_patched_apks_desc),
|
||||
icon = { Icon(painterResource(R.drawable.ic_delete_forever), null) },
|
||||
pref = preferences.keepPatchedApks,
|
||||
onPrefChange = {
|
||||
model.setKeepPatchedApks(it)
|
||||
clearedCache = false // Cache dir changes with this setting
|
||||
},
|
||||
onPrefChange = { model.setKeepPatchedApks(it) },
|
||||
modifier = Modifier.padding(bottom = 18.dp),
|
||||
)
|
||||
|
||||
if (preferences.keepPatchedApks) {
|
||||
MainActionButton(
|
||||
text = stringResource(R.string.log_action_export_apk),
|
||||
icon = painterResource(R.drawable.ic_save),
|
||||
enabled = model.patchedApkExists,
|
||||
onClick = model::shareApk,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 18.dp, vertical = 9.dp)
|
||||
.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
|
||||
MainActionButton(
|
||||
text = stringResource(R.string.settings_clear_cache),
|
||||
icon = painterResource(R.drawable.ic_delete_forever),
|
||||
|
|
@ -128,18 +132,6 @@ class SettingsScreen : Screen, Parcelable {
|
|||
.fillMaxWidth()
|
||||
)
|
||||
|
||||
if (preferences.keepPatchedApks) {
|
||||
val handler = LocalUriHandler.current
|
||||
MainActionButton(
|
||||
text = stringResource(R.string.settings_see_patched_apks),
|
||||
icon = painterResource(R.drawable.ic_launch),
|
||||
onClick = { handler.openUri(AliucordGithubService.PATCHED_APKS_INFO_URL) },
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 18.dp, vertical = 9.dp)
|
||||
.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
|
||||
SettingsHeader(stringResource(R.string.settings_header_info))
|
||||
|
||||
Row(
|
||||
|
|
|
|||
|
|
@ -53,9 +53,9 @@
|
|||
<string name="setting_developer_options">Developer options</string>
|
||||
<string name="setting_developer_options_desc">Don\'t enable this unless you know what it does! (yes, really)</string>
|
||||
<string name="setting_keep_patched_apks">Keep patched APKs</string>
|
||||
<string name="setting_keep_patched_apks_desc">Keep all patched files and APKs after installing for debugging. This setting may drastically slow down (20x) patching on certain devices!</string>
|
||||
<string name="setting_keep_patched_apks_desc">Keep all patched files and APKs after installation for debugging purposes. Note that exporting the APK is only useful after a successful patching session.</string>
|
||||
<string name="settings_clear_cache">Clear cache</string>
|
||||
<string name="settings_see_patched_apks">See patched APKs</string>
|
||||
<string name="settings_export_apk">Export APK</string>
|
||||
|
||||
<string name="theme_system">System</string>
|
||||
<string name="theme_dark">Dark</string>
|
||||
|
|
@ -205,6 +205,7 @@
|
|||
<string name="log_section_error">Error Stacktrace</string>
|
||||
<string name="log_section_log">Installation Log</string>
|
||||
<string name="log_action_export">Export log</string>
|
||||
<string name="log_action_export_apk">Export APK</string>
|
||||
<string name="log_action_share">Share log</string>
|
||||
|
||||
<string name="logs_title">Logs</string>
|
||||
|
|
|
|||
|
|
@ -3,4 +3,7 @@
|
|||
<cache-path
|
||||
name="cache"
|
||||
path="." />
|
||||
<files-path
|
||||
name="files"
|
||||
path="." />
|
||||
</paths>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue