diff --git a/app/src/main/kotlin/com/aliucord/manager/manager/InstallLogManager.kt b/app/src/main/kotlin/com/aliucord/manager/manager/InstallLogManager.kt index 59125b7..dcf12ee 100644 --- a/app/src/main/kotlin/com/aliucord/manager/manager/InstallLogManager.kt +++ b/app/src/main/kotlin/com/aliucord/manager/manager/InstallLogManager.kt @@ -12,8 +12,7 @@ import com.aliucord.manager.BuildConfig import com.aliucord.manager.ui.screens.patchopts.PatchOptions import com.aliucord.manager.util.IS_PROBABLY_EMULATOR import com.aliucord.manager.util.isPlayProtectEnabled -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.Serializable +import kotlinx.serialization.* import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromStream import java.io.IOException @@ -149,7 +148,7 @@ class InstallLogManager( @Serializable data class InstallLogData( val id: String, - val installDate: Instant, + @Contextual val installDate: Instant, val installDuration: Duration, val installOptions: PatchOptions, val environmentInfo: String, diff --git a/app/src/main/kotlin/com/aliucord/manager/manager/PathManager.kt b/app/src/main/kotlin/com/aliucord/manager/manager/PathManager.kt index dd590c5..34d18f5 100644 --- a/app/src/main/kotlin/com/aliucord/manager/manager/PathManager.kt +++ b/app/src/main/kotlin/com/aliucord/manager/manager/PathManager.kt @@ -125,7 +125,7 @@ class PathManager( /** * The APK that is worked on during the patching process. */ - fun patchedApk() = patchingWorkingDir().resolve("patched.apk") + fun patchedApk(part: String = "") = patchingWorkingDir().resolve("patched-${part}.apk") private companion object { /** diff --git a/app/src/main/kotlin/com/aliucord/manager/patcher/InstallMetadata.kt b/app/src/main/kotlin/com/aliucord/manager/patcher/InstallMetadata.kt index 46df4cc..4ca3d71 100644 --- a/app/src/main/kotlin/com/aliucord/manager/patcher/InstallMetadata.kt +++ b/app/src/main/kotlin/com/aliucord/manager/patcher/InstallMetadata.kt @@ -27,15 +27,15 @@ data class InstallMetadata( /** * Version (commit hash) of the Aliuhook build that was injected into the APK. */ - val aliuhookVersion: SemVer, + val aliuhookVersion: SemVer?, /** * Version of the injector build that was injected into the APK. */ - val injectorVersion: SemVer, + val injectorVersion: SemVer?, /** * Version of the smali patches that were applied onto the APK. */ - val patchesVersion: SemVer, + val patchesVersion: SemVer?, ) diff --git a/app/src/main/kotlin/com/aliucord/manager/patcher/StepRunner.kt b/app/src/main/kotlin/com/aliucord/manager/patcher/StepRunner.kt index 014627b..808d380 100644 --- a/app/src/main/kotlin/com/aliucord/manager/patcher/StepRunner.kt +++ b/app/src/main/kotlin/com/aliucord/manager/patcher/StepRunner.kt @@ -42,10 +42,7 @@ abstract class StepRunner : KoinComponent { * @param completed Only match steps that have finished executing. */ inline fun getStep(completed: Boolean = true): T { - val step = steps.asSequence() - .filterIsInstance() - .filter { !completed || it.state.isFinished } - .firstOrNull() + val step = getStepOrNull(completed) if (step == null) { throw IllegalArgumentException("No completed step ${T::class.simpleName} exists in container") @@ -54,6 +51,13 @@ abstract class StepRunner : KoinComponent { return step } + inline fun getStepOrNull(completed: Boolean = true): T? { + return steps.asSequence() + .filterIsInstance() + .filter { !completed || it.state.isFinished } + .firstOrNull() + } + /** * Adds a log entry without any associated log level. */ diff --git a/app/src/main/kotlin/com/aliucord/manager/patcher/WintryPatchRunner.kt b/app/src/main/kotlin/com/aliucord/manager/patcher/WintryPatchRunner.kt new file mode 100644 index 0000000..09ac717 --- /dev/null +++ b/app/src/main/kotlin/com/aliucord/manager/patcher/WintryPatchRunner.kt @@ -0,0 +1,28 @@ +package com.aliucord.manager.patcher + +import com.aliucord.manager.patcher.steps.base.Step +import com.aliucord.manager.patcher.steps.download.* +import com.aliucord.manager.patcher.steps.install.* +import com.aliucord.manager.patcher.steps.patch.* +import com.aliucord.manager.ui.screens.patchopts.PatchOptions +import kotlinx.collections.immutable.persistentListOf + +class WintryPatchRunner(options: PatchOptions) : StepRunner() { + override val steps = persistentListOf( + DownloadDiscordRNABaseStep(), + DownloadDiscordRNALangStep(), + DownloadDiscordRNAResourcesStep(), + DownloadDiscordRNALibStep(), + CopyDependenciesStep(), + + PatchIconsStep(options), + PatchManifestStep(options), + // ReorganizeDexStep(), + SaveMetadataStep(options), + + AlignmentStep(), + SigningStep(), + InstallStep(options), + // CleanupStep(), + ) +} diff --git a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/base/DownloadStep.kt b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/base/DownloadStep.kt index c861d05..9ba25cd 100644 --- a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/base/DownloadStep.kt +++ b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/base/DownloadStep.kt @@ -22,6 +22,9 @@ abstract class DownloadStep : Step(), KoinComponent { private val context: Context by inject() private val downloader: KtorDownloadManager by inject() + // Temporary + protected val version: Int = 289210 + /** * The remote url to download */ diff --git a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/CopyDependenciesStep.kt b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/CopyDependenciesStep.kt index ebd88bf..0e504ec 100644 --- a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/CopyDependenciesStep.kt +++ b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/CopyDependenciesStep.kt @@ -23,15 +23,30 @@ class CopyDependenciesStep : Step(), KoinComponent { private val application: Application by inject() /** - * The target APK file which can be modified during patching + * The target APK files which can be modified during patching */ val patchedApk: File = paths.patchedApk() + var patchedLangApk: File? = null + var patchedLibApk: File? = null + var patchedResApk: File? = null + + val patchedApks + get() = listOfNotNull( + patchedApk, + patchedLangApk.takeIf { it?.exists() == true }, + patchedLibApk.takeIf { it?.exists() == true }, + patchedResApk.takeIf { it?.exists() == true } + ) override val group = StepGroup.Download override val localizedName = R.string.patch_step_copy_deps override suspend fun execute(container: StepRunner) { val srcApk = container.getStep().targetFile + val langApk = container.getStepOrNull()?.targetFile + val libApk = container.getStepOrNull()?.targetFile + val resApk = container.getStepOrNull()?.targetFile + val dir = paths.patchingWorkingDir() container.log("Clearing patched directory") @@ -42,7 +57,7 @@ class CopyDependenciesStep : Step(), KoinComponent { if (Build.VERSION.SDK_INT >= 26) { val storageManager = application.getSystemService()!! val targetFileStorageId = storageManager.getUuidForPath(patchedApk) - val fileSize = srcApk.length() + val fileSize = srcApk.length() + (langApk?.length() ?: 0) + (libApk?.length() ?: 0) + (resApk?.length() ?: 0) // We request 3.5x the size of the APK, to give space for the following: // 1) A copy of the APK @@ -57,7 +72,21 @@ class CopyDependenciesStep : Step(), KoinComponent { } } - container.log("Copying patched apk from ${srcApk.absolutePath} to ${patchedApk.absolutePath}") + fun copyApkSafely(src: File?, destFile: File, onCopied: (File) -> Unit) { + src?.let { + container.log("Copying patched apk from ${it.absolutePath} to ${destFile.absolutePath}") + it.copyTo(destFile) + onCopied(destFile) + } + } + + // Base APK + container.log("Copying patched base apk from ${srcApk.absolutePath} to ${patchedApk.absolutePath}") srcApk.copyTo(patchedApk) + + // Optional APKs + copyApkSafely(langApk, File(dir, "lang")) { patchedLangApk = it } + copyApkSafely(libApk, File(dir, "lib")) { patchedLibApk = it } + copyApkSafely(resApk, File(dir, "res")) { patchedResApk = it } } } diff --git a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/DownloadDiscordRNABaseStep.kt b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/DownloadDiscordRNABaseStep.kt new file mode 100644 index 0000000..54ddf39 --- /dev/null +++ b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/DownloadDiscordRNABaseStep.kt @@ -0,0 +1,9 @@ +package com.aliucord.manager.patcher.steps.download + +import com.aliucord.manager.R + +class DownloadDiscordRNABaseStep : DownloadDiscordStep() { + override val targetUrl = "https://tracker.vendetta.rocks/tracker/download/$version/base" + override val targetFile = paths.discordApkVersionCache(version).resolve("base.apk") + override val localizedName = R.string.downloading_base_apk +} diff --git a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/DownloadDiscordRNALangStep.kt b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/DownloadDiscordRNALangStep.kt new file mode 100644 index 0000000..bc093b0 --- /dev/null +++ b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/DownloadDiscordRNALangStep.kt @@ -0,0 +1,15 @@ +package com.aliucord.manager.patcher.steps.download + +import com.aliucord.manager.R +import com.aliucord.manager.manager.PathManager +import com.aliucord.manager.patcher.steps.base.DownloadStep +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject + +class DownloadDiscordRNALangStep : DownloadStep(), KoinComponent { + private val paths: PathManager by inject() + + override val targetUrl = "https://tracker.vendetta.rocks/tracker/download/$version/config.en" + override val targetFile = paths.discordApkVersionCache(version).resolve("config.en.apk") + override val localizedName = R.string.download_libs_apk +} diff --git a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/DownloadDiscordRNALibStep.kt b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/DownloadDiscordRNALibStep.kt new file mode 100644 index 0000000..480f8a3 --- /dev/null +++ b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/DownloadDiscordRNALibStep.kt @@ -0,0 +1,17 @@ +package com.aliucord.manager.patcher.steps.download + +import android.os.Build +import com.aliucord.manager.R +import com.aliucord.manager.manager.PathManager +import com.aliucord.manager.patcher.steps.base.DownloadStep +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject + +class DownloadDiscordRNALibStep : DownloadStep(), KoinComponent { + private val paths: PathManager by inject() + private val arch = Build.SUPPORTED_ABIS.first().replace("-v", "_v") + + override val targetUrl = "https://tracker.vendetta.rocks/tracker/download/$version/config.$arch" + override val targetFile = paths.discordApkVersionCache(version).resolve("config.$arch.apk") + override val localizedName = R.string.downloading_libs_apk +} diff --git a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/DownloadDiscordRNAResourcesStep.kt b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/DownloadDiscordRNAResourcesStep.kt new file mode 100644 index 0000000..cb29bcb --- /dev/null +++ b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/DownloadDiscordRNAResourcesStep.kt @@ -0,0 +1,15 @@ +package com.aliucord.manager.patcher.steps.download + +import com.aliucord.manager.R +import com.aliucord.manager.manager.PathManager +import com.aliucord.manager.patcher.steps.base.DownloadStep +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject + +class DownloadDiscordRNAResourcesStep : DownloadStep(), KoinComponent { + private val paths: PathManager by inject() + + override val targetUrl = "https://tracker.vendetta.rocks/tracker/download/$version/config.xxhdpi" + override val targetFile = paths.discordApkVersionCache(version).resolve("config.xxhdpi.apk") + override val localizedName = R.string.downloading_resources_apk +} diff --git a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/DownloadDiscordStep.kt b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/DownloadDiscordStep.kt index 3b81ddb..c135558 100644 --- a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/DownloadDiscordStep.kt +++ b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/download/DownloadDiscordStep.kt @@ -13,8 +13,8 @@ import org.koin.core.component.inject * from a redirect to an APK mirror site provided by the Aliucord backend. */ @Stable -class DownloadDiscordStep : DownloadStep(), KoinComponent { - private val paths: PathManager by inject() +open class DownloadDiscordStep : DownloadStep(), KoinComponent { + protected val paths: PathManager by inject() override val localizedName = R.string.patch_step_dl_kt_apk override val targetUrl = getDiscordApkUrl(DISCORD_KT_VERSION) diff --git a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/install/AlignmentStep.kt b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/install/AlignmentStep.kt index ad4eed5..6f80fcb 100644 --- a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/install/AlignmentStep.kt +++ b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/install/AlignmentStep.kt @@ -22,98 +22,100 @@ class AlignmentStep : Step(), KoinComponent { override suspend fun execute(container: StepRunner) { val currentDeviceArch = Build.SUPPORTED_ABIS.first() - val apk = container.getStep().patchedApk + val apks = container.getStep().patchedApks - var resourcesArscBytes: ByteArray? = null - var dexCount: Int = -1 + for (apk in apks) { + var resourcesArscBytes: ByteArray? = null + var dexCount: Int = -1 - // Align resources.arsc due to targeting API 30 for silent install - if (Build.VERSION.SDK_INT >= 30) { - container.log("Extracting resources.arsc to be aligned later") - resourcesArscBytes = ZipReader(apk) - .use { it.openEntry("resources.arsc")?.read() } - ?: throw IllegalArgumentException("APK is missing resources.arsc") - } + // Align resources.arsc due to targeting API 30 for silent install + if (Build.VERSION.SDK_INT >= 30) { + container.log("Extracting resources.arsc to be aligned later") + resourcesArscBytes = ZipReader(apk) + .use { it.openEntry("resources.arsc")?.read() } + ?: continue // Alignment is not needed + } - // Align dex files due to using useEmbeddedDex (ref. ManifestPatcher) - if (Build.VERSION.SDK_INT >= 29) { - container.log("Extracting all dex files to be aligned later") - ZipReader(apk).use { zip -> - // Count the amount of dex files currently in the apk - dexCount = zip.entryNames.count { it.endsWith(".dex") } + // Align dex files due to using useEmbeddedDex (ref. ManifestPatcher) + if (Build.VERSION.SDK_INT >= 29) { + container.log("Extracting all dex files to be aligned later") + ZipReader(apk).use { zip -> + // Count the amount of dex files currently in the apk + dexCount = zip.entryNames.count { it.endsWith(".dex") } - // Copy all the dex files that need to be moved out of the apk - for (idx in 0.. + val libPaths = zip.entryNames.filter { it.endsWith(".so") } + + // Extract to disk temporarily + for ((idx, path) in libPaths.withIndex()) { + // Ignore lib architectures that don't match this device + if (!path.startsWith("lib/$currentDeviceArch")) { + container.log("Skipping native lib $path due to incompatible architecture") + continue + } + + // Index is just used as a placeholder id to cache on disk + val bytes = zip.openEntry(path)!!.read() + val file = paths.patchingWorkingDir().resolve("$idx.so") file.writeBytes(bytes) - } - } - container.log("Extracted $dexCount dex files") - } - - // Align native libs due to using extractNativeLibs - container.log("Extracting native libraries to be aligned later") - val nativeLibPaths = ZipReader(apk).use { zip -> - val libPaths = zip.entryNames.filter { it.endsWith(".so") } - - // Extract to disk temporarily - for ((idx, path) in libPaths.withIndex()) { - // Ignore lib architectures that don't match this device - if (!path.startsWith("lib/$currentDeviceArch")) { - container.log("Skipping native lib $path due to incompatible architecture") - continue + container.log("Extracted native lib $file") } - // Index is just used as a placeholder id to cache on disk - val bytes = zip.openEntry(path)!!.read() - val file = paths.patchingWorkingDir().resolve("$idx.so") - file.writeBytes(bytes) - container.log("Extracted native lib $file") + libPaths } - libPaths - } + container.log("Writing entries back aligned") + ZipWriter(apk, /* append = */ true).use { zip -> + // Delete all the unaligned files from APK + container.log("Deleting resources.arsc") + if (resourcesArscBytes != null) + zip.deleteEntry("resources.arsc") - container.log("Writing entries back aligned") - ZipWriter(apk, /* append = */ true).use { zip -> - // Delete all the unaligned files from APK - container.log("Deleting resources.arsc") - if (resourcesArscBytes != null) - zip.deleteEntry("resources.arsc") + container.log("Deleting $dexCount dex files") + for (i in 0..().patchedApk + val apks = container.getStep().patchedApks // If app backgrounded, show notification if (ProcessLifecycleOwner.get().lifecycle.currentState == Lifecycle.State.CREATED) { @@ -66,9 +66,9 @@ class InstallStep(private val options: PatchOptions) : Step(), KoinComponent { prefs.showPlayProtectWarning = !neverShowAgain } - container.log("Installing ${apk.absolutePath}, silent: ${!prefs.devMode}") + container.log("Installing ${apks.joinToString(", ") { it.name }}, silent: ${!prefs.devMode}") val result = installers.getActiveInstaller().waitInstall( - apks = listOf(apk), + apks = apks, silent = !prefs.devMode, ) diff --git a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/install/SigningStep.kt b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/install/SigningStep.kt index 493dbe8..23ed813 100644 --- a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/install/SigningStep.kt +++ b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/install/SigningStep.kt @@ -16,9 +16,9 @@ class SigningStep : Step(), KoinComponent { override val localizedName = R.string.patch_step_signing override suspend fun execute(container: StepRunner) { - val apk = container.getStep().patchedApk - - container.log("Signing apk at ${apk.absolutePath}") - Signer.signApk(apk) + for (apk in container.getStep().patchedApks) { + container.log("Signing apk at ${apk.absolutePath}") + Signer.signApk(apk) + } } } diff --git a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/patch/PatchManifestStep.kt b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/patch/PatchManifestStep.kt index af45e17..9314304 100644 --- a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/patch/PatchManifestStep.kt +++ b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/patch/PatchManifestStep.kt @@ -18,25 +18,33 @@ class PatchManifestStep(private val options: PatchOptions) : Step() { override val localizedName = R.string.patch_step_patch_manifests override suspend fun execute(container: StepRunner) { - val apk = container.getStep().patchedApk + val deps = container.getStep() + for (apk in deps.patchedApks) { + container.log("Reading manifest from apk") + val manifest = ZipReader(apk) + .use { zip -> zip.openEntry("AndroidManifest.xml")?.read() } + ?: throw IllegalArgumentException("No manifest found in APK") - container.log("Reading manifest from apk") - val manifest = ZipReader(apk) - .use { zip -> zip.openEntry("AndroidManifest.xml")?.read() } - ?: throw IllegalArgumentException("No manifest found in APK") + container.log("Patching manifest") + val patchedManifest = if (apk == deps.patchedApk) + ManifestPatcher.patchManifest( + manifestBytes = manifest, + packageName = options.packageName, + appName = options.appName, + debuggable = options.debuggable, + ) + else { + ManifestPatcher.patchManifestPackageName( + manifestBytes = manifest, + packageName = options.packageName, + ) + } - container.log("Patching manifest") - val patchedManifest = ManifestPatcher.patchManifest( - manifestBytes = manifest, - packageName = options.packageName, - appName = options.appName, - debuggable = options.debuggable, - ) - - container.log("Writing patched manifest to apk unaligned compressed") - ZipWriter(apk, /* append = */ true).use { - it.deleteEntry("AndroidManifest.xml") - it.writeEntry("AndroidManifest.xml", patchedManifest) + container.log("Writing patched manifest to apk unaligned compressed") + ZipWriter(apk, /* append = */ true).use { + it.deleteEntry("AndroidManifest.xml", apk == deps.patchedLibApk || apk == deps.patchedApk) + it.writeEntry("AndroidManifest.xml", patchedManifest) + } } } } diff --git a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/patch/SaveMetadataStep.kt b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/patch/SaveMetadataStep.kt index ca5b54d..6abbc28 100644 --- a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/patch/SaveMetadataStep.kt +++ b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/patch/SaveMetadataStep.kt @@ -27,17 +27,17 @@ class SaveMetadataStep(private val options: PatchOptions) : Step(), KoinComponen override suspend fun execute(container: StepRunner) { val apk = container.getStep().patchedApk - val aliuhook = container.getStep() - val injector = container.getStep() - val patches = container.getStep() + val aliuhook = container.getStepOrNull() + val injector = container.getStepOrNull() + val patches = container.getStepOrNull() val metadata = InstallMetadata( options = options, customManager = !BuildConfig.RELEASE, managerVersion = SemVer.parse(BuildConfig.VERSION_NAME), - aliuhookVersion = aliuhook.targetVersion, - injectorVersion = injector.targetVersion, - patchesVersion = patches.targetVersion, + aliuhookVersion = aliuhook?.targetVersion, + injectorVersion = injector?.targetVersion, + patchesVersion = patches?.targetVersion, ) container.log("Writing serialized install metadata to APK") diff --git a/app/src/main/kotlin/com/aliucord/manager/patcher/util/ManifestPatcher.kt b/app/src/main/kotlin/com/aliucord/manager/patcher/util/ManifestPatcher.kt index 8614132..c7b87aa 100644 --- a/app/src/main/kotlin/com/aliucord/manager/patcher/util/ManifestPatcher.kt +++ b/app/src/main/kotlin/com/aliucord/manager/patcher/util/ManifestPatcher.kt @@ -191,6 +191,72 @@ object ManifestPatcher { return writer.toByteArray() } + fun patchManifestPackageName( + manifestBytes: ByteArray, + packageName: String, + ): ByteArray { + val reader = AxmlReader(manifestBytes) + val writer = AxmlWriter() + + reader.accept(object : AxmlVisitor(writer) { + override fun ns(prefix: String?, uri: String?, ln: Int) { + val realUri = uri ?: ANDROID_NAMESPACE + super.ns(prefix, realUri, ln) + } + + override fun child(ns: String?, name: String?) = + object : ReplaceAttrsVisitor( + super.child(ns, name), + mapOf(PACKAGE to packageName) + ) { + override fun child(ns: String?, name: String): NodeVisitor { + val nv = super.child(ns, name) + + return when (name) { + "permission" -> object : NodeVisitor(nv) { + override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) { + super.attr( + ns, name, resourceId, type, + if (name == "name") { + (value as String).replace("com.discord", packageName) + } else { + value + } + ) + } + } + + "application" -> object : NodeVisitor(nv) { + override fun child(ns: String?, name: String): NodeVisitor { + val visitor = super.child(ns, name) + return when (name) { + "provider" -> object : NodeVisitor(visitor) { + override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) { + super.attr( + ns, name, resourceId, type, + if (name == "authorities") { + (value as String).replace("com.discord", packageName) + } else { + value + } + ) + } + } + + else -> visitor + } + } + } + + else -> nv + } + } + } + }) + + return writer.toByteArray() + } + private open class ReplaceAttrsVisitor( nv: NodeVisitor, private val attrs: Map, diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeModel.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeModel.kt index 3fd4493..8487ca4 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeModel.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/HomeModel.kt @@ -250,9 +250,11 @@ class HomeModel( return false } - // Check that all the installation components are up-to-date - return remoteBuildData.injectorVersion == installMetadata.injectorVersion - && remoteBuildData.patchesVersion == installMetadata.patchesVersion - && latestAliuhookVersion == installMetadata.aliuhookVersion + // Check that all the installation components are up-to-date (skip not installed) + val injectorUpToDate = installMetadata.injectorVersion == null || remoteBuildData.injectorVersion == installMetadata.injectorVersion + val patchesUpToDate = installMetadata.patchesVersion == null || remoteBuildData.patchesVersion == installMetadata.patchesVersion + val aliuhookUpToDate = installMetadata.aliuhookVersion == null || latestAliuhookVersion == installMetadata.aliuhookVersion + + return injectorUpToDate && patchesUpToDate && aliuhookUpToDate } } diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/patching/PatchingScreenModel.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/patching/PatchingScreenModel.kt index f5837c5..e242942 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/patching/PatchingScreenModel.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/patching/PatchingScreenModel.kt @@ -10,8 +10,8 @@ import cafe.adriel.voyager.core.model.screenModelScope import com.aliucord.manager.BuildConfig import com.aliucord.manager.R import com.aliucord.manager.manager.* -import com.aliucord.manager.patcher.KotlinPatchRunner import com.aliucord.manager.patcher.StepRunner +import com.aliucord.manager.patcher.WintryPatchRunner import com.aliucord.manager.patcher.steps.StepGroup import com.aliucord.manager.patcher.steps.base.* import com.aliucord.manager.patcher.steps.install.InstallStep @@ -125,7 +125,7 @@ class PatchingScreenModel( } private suspend fun startPatchRunner() { - val runner = KotlinPatchRunner(options) + val runner = WintryPatchRunner(options) .also { stepRunner = it } val newSteps = runner.steps.groupBy { it.group } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6f73ab3..08f97b7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -245,4 +245,9 @@ Aliucord uses the *real* old UI, from mid-2022! There was an attempt to make Aliucord run on iOS… veeeee 😭 + + Download libs apk + Downloading base APK + Downloading libs apk + Downloading resources apk