From 4953947e1d3a8adeb50aac6a60baceb3dd38f1b9 Mon Sep 17 00:00:00 2001 From: rushiiMachine <33725716+rushiiMachine@users.noreply.github.com> Date: Fri, 12 Jan 2024 15:14:40 -0800 Subject: [PATCH] feat: remove RN install --- .../manager/domain/manager/DownloadManager.kt | 6 - .../domain/repository/GithubRepository.kt | 3 - .../network/service/AliucordGithubService.kt | 22 +- .../manager/ui/dialog/InstallerDialog.kt | 196 +++++------ .../manager/ui/screen/InstallScreen.kt | 11 +- .../manager/ui/viewmodel/InstallViewModel.kt | 325 +----------------- app/src/main/res/values/strings.xml | 2 +- gradle/libs.versions.toml | 4 +- 8 files changed, 108 insertions(+), 461 deletions(-) diff --git a/app/src/main/kotlin/com/aliucord/manager/domain/manager/DownloadManager.kt b/app/src/main/kotlin/com/aliucord/manager/domain/manager/DownloadManager.kt index 705f1d3..77a98d3 100644 --- a/app/src/main/kotlin/com/aliucord/manager/domain/manager/DownloadManager.kt +++ b/app/src/main/kotlin/com/aliucord/manager/domain/manager/DownloadManager.kt @@ -25,9 +25,6 @@ class DownloadManager( suspend fun downloadDiscordApk(version: String, out: File): File = download("$BACKEND_HOST/download/discord?v=$version", out) - suspend fun downloadSplit(version: String, split: String, out: File): File = - download("$BACKEND_HOST/download/discord?v=$version&split=$split", out) - // Aliucord Kotlin downloads suspend fun downloadKtInjector(out: File): File = download(AliucordGithubService.KT_INJECTOR_URL, out) @@ -38,9 +35,6 @@ class DownloadManager( suspend fun downloadKotlinDex(out: File): File = download(AliucordGithubService.KOTLIN_DEX_URL, out) - suspend fun downloadBootstrap(out: File): File = - download(AliucordGithubService.BOOTSTRAP_URL, out) - suspend fun download(url: String, out: File): File { out.parentFile?.mkdirs() diff --git a/app/src/main/kotlin/com/aliucord/manager/domain/repository/GithubRepository.kt b/app/src/main/kotlin/com/aliucord/manager/domain/repository/GithubRepository.kt index 7a1ad28..9947f2c 100644 --- a/app/src/main/kotlin/com/aliucord/manager/domain/repository/GithubRepository.kt +++ b/app/src/main/kotlin/com/aliucord/manager/domain/repository/GithubRepository.kt @@ -13,8 +13,5 @@ class GithubRepository( suspend fun getDataJson() = service.getDataJson() - suspend fun getHermesRelease() = service.getLatestHermesRelease() - suspend fun getAliucordNativeRelease() = service.getLatestAliucordNativeRelease() suspend fun getManagerReleases() = service.getManagerReleases() - suspend fun getLatestBootstrapCommit() = service.getLatestBootstrapCommit() } diff --git a/app/src/main/kotlin/com/aliucord/manager/network/service/AliucordGithubService.kt b/app/src/main/kotlin/com/aliucord/manager/network/service/AliucordGithubService.kt index 6932c72..4cd77d0 100644 --- a/app/src/main/kotlin/com/aliucord/manager/network/service/AliucordGithubService.kt +++ b/app/src/main/kotlin/com/aliucord/manager/network/service/AliucordGithubService.kt @@ -1,10 +1,8 @@ package com.aliucord.manager.network.service -import com.aliucord.manager.network.dto.Commit import com.aliucord.manager.network.dto.Version import com.aliucord.manager.network.utils.ApiResponse -import com.aliucord.manager.network.utils.transform -import io.ktor.client.request.* +import io.ktor.client.request.url import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -20,31 +18,15 @@ class AliucordGithubService( } } - suspend fun getLatestBootstrapCommit(): ApiResponse { - return withContext(Dispatchers.IO) { - http.request> { - url("https://api.github.com/repos/$ORG/$RN_REPO/commits?sha=builds&path=bootstrap.js&per_page=1") - }.transform { - it.single().sha - } - } - } - suspend fun getCommits(page: Int = 0) = github.getCommits(ORG, MAIN_REPO, page) - suspend fun getLatestHermesRelease() = github.getLatestRelease(ORG, HERMES_REPO) - suspend fun getLatestAliucordNativeRelease() = github.getLatestRelease(ORG, ALIUNATIVE_REPO) suspend fun getManagerReleases() = github.getReleases(ORG, MANAGER_REPO) suspend fun getContributors() = github.getContributors(ORG, MAIN_REPO) companion object { private const val ORG = "Aliucord" private const val MAIN_REPO = "Aliucord" - private const val RN_REPO = "AliucordRN" - private const val HERMES_REPO = "Hermes" - private const val ALIUNATIVE_REPO = "AliucordNative" - private const val MANAGER_REPO = "AliucordManager" + private const val MANAGER_REPO = "Manager" - const val BOOTSTRAP_URL = "https://raw.githubusercontent.com/$ORG/$RN_REPO/builds/bootstrap.js" const val KT_INJECTOR_URL = "https://raw.githubusercontent.com/$ORG/$MAIN_REPO/builds/Injector.dex" const val KOTLIN_DEX_URL = "https://raw.githubusercontent.com/$ORG/$MAIN_REPO/main/installer/android/app/src/main/assets/kotlin/classes.dex" } diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/dialog/InstallerDialog.kt b/app/src/main/kotlin/com/aliucord/manager/ui/dialog/InstallerDialog.kt index b73517c..9c1665c 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/dialog/InstallerDialog.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/dialog/InstallerDialog.kt @@ -5,25 +5,11 @@ package com.aliucord.manager.ui.dialog -import androidx.compose.foundation.layout.* -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Download -import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.Dialog -import com.aliucord.manager.BuildConfig -import com.aliucord.manager.R import com.aliucord.manager.ui.screen.InstallData enum class DownloadMethod { DOWNLOAD } -enum class DiscordType { KOTLIN, REACT_NATIVE } @Composable fun InstallerDialog( @@ -31,104 +17,104 @@ fun InstallerDialog( onConfirm: (InstallData) -> Unit ) { val downloadMethod by rememberSaveable { mutableStateOf(DownloadMethod.DOWNLOAD) } - var discordType by rememberSaveable { mutableStateOf(null) } fun triggerConfirm() { onDismiss() onConfirm( - InstallData( - downloadMethod, - discordType ?: return - ) + InstallData(downloadMethod) ) } - Dialog( - onDismissRequest = onDismiss, - ) { - Surface( - color = AlertDialogDefaults.containerColor, - tonalElevation = AlertDialogDefaults.TonalElevation, - shape = AlertDialogDefaults.shape, - ) { - Column( - modifier = Modifier - .sizeIn(minWidth = 380.dp) - .padding(24.dp) - ) { - // Icon - Box( - Modifier - .align(Alignment.CenterHorizontally) - .padding(bottom = 16.dp) - ) { - Icon( - imageVector = Icons.Default.Download, - tint = AlertDialogDefaults.iconContentColor, - contentDescription = null - ) - } + SideEffect(::triggerConfirm) - // Title - Box( - modifier = Modifier - .align(Alignment.CenterHorizontally) - .padding(bottom = 30.dp) - ) { - Text( - stringResource(R.string.selector_discord_type), - color = AlertDialogDefaults.titleContentColor, - style = MaterialTheme.typography.headlineSmall - ) - } + // TODO: local install option - // Body - Box( - modifier = Modifier - .padding(bottom = 30.dp) - ) { - Text( - stringResource(R.string.selector_discord_type_body), - textAlign = TextAlign.Center, - color = AlertDialogDefaults.textContentColor, - style = MaterialTheme.typography.bodyMedium - ) - } - - // Buttons - Column( - verticalArrangement = Arrangement.spacedBy(4.dp), - modifier = Modifier.clip(MaterialTheme.shapes.large) - ) { - ProvideTextStyle(MaterialTheme.typography.labelMedium) { - Button( - shape = MaterialTheme.shapes.extraSmall, - enabled = BuildConfig.RN_ENABLED, - onClick = { - discordType = DiscordType.REACT_NATIVE - triggerConfirm() - }, - modifier = Modifier - .fillMaxWidth() - .height(50.dp) - ) { - Text(stringResource(R.string.selector_discord_type_kotlin)) - } - Button( - shape = MaterialTheme.shapes.extraSmall, - onClick = { - discordType = DiscordType.KOTLIN - triggerConfirm() - }, - modifier = Modifier - .fillMaxWidth() - .height(50.dp) - ) { - Text(stringResource(R.string.selector_discord_type_old)) - } - } - } - } - } - } + // Dialog( + // onDismissRequest = onDismiss, + // ) { + // Surface( + // color = AlertDialogDefaults.containerColor, + // tonalElevation = AlertDialogDefaults.TonalElevation, + // shape = AlertDialogDefaults.shape, + // ) { + // Column( + // modifier = Modifier + // .sizeIn(minWidth = 380.dp) + // .padding(24.dp) + // ) { + // // Icon + // Box( + // Modifier + // .align(Alignment.CenterHorizontally) + // .padding(bottom = 16.dp) + // ) { + // Icon( + // imageVector = Icons.Default.Check, // TODO: move away from icon lib + // tint = AlertDialogDefaults.iconContentColor, + // contentDescription = null + // ) + // } + // + // // Title + // Box( + // modifier = Modifier + // .align(Alignment.CenterHorizontally) + // .padding(bottom = 30.dp) + // ) { + // Text( + // stringResource(R.string.selector_discord_type), + // color = AlertDialogDefaults.titleContentColor, + // style = MaterialTheme.typography.headlineSmall + // ) + // } + // + // // Body + // Box( + // modifier = Modifier + // .padding(bottom = 30.dp) + // ) { + // Text( + // stringResource(R.string.selector_discord_type_body), + // textAlign = TextAlign.Center, + // color = AlertDialogDefaults.textContentColor, + // style = MaterialTheme.typography.bodyMedium + // ) + // } + // + // Buttons + // Column( + // verticalArrangement = Arrangement.spacedBy(4.dp), + // modifier = Modifier.clip(MaterialTheme.shapes.large) + // ) { + // ProvideTextStyle(MaterialTheme.typography.labelMedium) { + // Button( + // shape = MaterialTheme.shapes.extraSmall, + // enabled = BuildConfig.RN_ENABLED, + // onClick = { + // discordType = DiscordType.REACT_NATIVE + // triggerConfirm() + // }, + // modifier = Modifier + // .fillMaxWidth() + // .height(50.dp) + // ) { + // Text(stringResource(R.string.selector_discord_type_kotlin)) + // } + // Button( + // shape = MaterialTheme.shapes.extraSmall, + // onClick = { + // discordType = DiscordType.KOTLIN + // triggerConfirm() + // }, + // modifier = Modifier + // .fillMaxWidth() + // .height(50.dp) + // ) { + // Text(stringResource(R.string.selector_discord_type_old)) + // } + // } + // } + // } + // } + // } } diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screen/InstallScreen.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screen/InstallScreen.kt index 23664a5..4115cd5 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screen/InstallScreen.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screen/InstallScreen.kt @@ -11,7 +11,7 @@ import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.NavigateBefore +import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment @@ -22,7 +22,6 @@ import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp import com.aliucord.manager.R import com.aliucord.manager.ui.component.installer.* -import com.aliucord.manager.ui.dialog.DiscordType import com.aliucord.manager.ui.dialog.DownloadMethod import com.aliucord.manager.ui.viewmodel.InstallViewModel import com.aliucord.manager.ui.viewmodel.InstallViewModel.InstallStepGroup @@ -30,13 +29,11 @@ import kotlinx.collections.immutable.toImmutableList import kotlinx.parcelize.Parcelize import org.koin.androidx.compose.getViewModel import org.koin.core.parameter.parametersOf -import java.util.* @Immutable // this isn't *really* stable, but this never gets modified after being passed to a composable, so... @Parcelize data class InstallData( val downloadMethod: DownloadMethod, - val discordType: DiscordType, var baseApk: String? = null, var splits: List? = null ) : Parcelable @@ -50,7 +47,7 @@ fun InstallerScreen( ) { if (viewModel.returnToHome) onBackClick() - var expandedGroup by mutableStateOf(null) + var expandedGroup by remember { mutableStateOf(null) } LaunchedEffect(viewModel.currentStep) { expandedGroup = viewModel.currentStep?.group @@ -63,7 +60,7 @@ fun InstallerScreen( navigationIcon = { IconButton(onClick = onBackClick) { Icon( - imageVector = Icons.Default.NavigateBefore, + imageVector = Icons.Default.ArrowBack, contentDescription = stringResource(R.string.navigation_back) ) } @@ -88,7 +85,7 @@ fun InstallerScreen( .fillMaxWidth() .padding(16.dp) ) { - for (group in InstallStepGroup.values()) { + for (group in InstallStepGroup.entries) { InstallGroup( name = stringResource(group.nameResId), isCurrent = expandedGroup == group, diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/viewmodel/InstallViewModel.kt b/app/src/main/kotlin/com/aliucord/manager/ui/viewmodel/InstallViewModel.kt index 2b0821c..596f84c 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/viewmodel/InstallViewModel.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/viewmodel/InstallViewModel.kt @@ -1,5 +1,6 @@ package com.aliucord.manager.ui.viewmodel +import android.annotation.SuppressLint import android.app.Application import android.os.Build import android.util.Log @@ -17,15 +18,13 @@ import com.aliucord.manager.installer.util.* import com.aliucord.manager.network.utils.getOrThrow import com.aliucord.manager.ui.component.installer.InstallStatus import com.aliucord.manager.ui.component.installer.InstallStepData -import com.aliucord.manager.ui.dialog.DiscordType import com.aliucord.manager.ui.screen.InstallData import com.aliucord.manager.util.* import com.github.diamondminer88.zip.* import kotlinx.coroutines.* import java.text.SimpleDateFormat -import java.util.* +import java.util.Date import java.util.concurrent.atomic.AtomicBoolean -import kotlin.time.ExperimentalTime import kotlin.time.measureTimedValue class InstallViewModel( @@ -55,7 +54,7 @@ class InstallViewModel( Running Android ${Build.VERSION.RELEASE}, API level ${Build.VERSION.SDK_INT} Supported ABIs: ${Build.SUPPORTED_ABIS.joinToString()} - Installing ${installData.discordType} with the ${installData.downloadMethod} apk method + Installing Aliucord kt with the ${installData.downloadMethod} apk method Failed on: ${currentStep?.name} """.trimIndent() @@ -69,11 +68,13 @@ class InstallViewModel( } private var debugLogPath by mutableStateOf(null) + + @SuppressLint("SimpleDateFormat") fun saveDebugToFile() { val name = if (debugLogPath != null) { debugLogPath!! } else { - "Aliucord Manager ${SimpleDateFormat("YYYY-MM-dd hh-mm-s a").format(Date())}.log" + "Aliucord Manager ${SimpleDateFormat("yyyy-MM-dd hh-mm-s a").format(Date())}.log" .also { debugLogPath = it } } @@ -92,10 +93,7 @@ class InstallViewModel( withContext(Dispatchers.IO) { try { - when (installData.discordType) { - DiscordType.REACT_NATIVE -> installReactNative() - DiscordType.KOTLIN -> installKotlin() - } + installKotlin() isFinished = true delay(20000) @@ -145,304 +143,6 @@ class InstallViewModel( } } - private suspend fun installReactNative() { - steps += listOfNotNull( - InstallStep.DL_BASE_APK, - InstallStep.DL_LIBS_APK, - InstallStep.DL_LANG_APK, - InstallStep.DL_RESC_APK, - InstallStep.DL_HERMES, - InstallStep.DL_ALIUNATIVE, - InstallStep.DL_BOOTSTRAP, - if (preferences.replaceIcon) InstallStep.PATCH_APP_ICON else null, - InstallStep.PATCH_MANIFEST, - InstallStep.PATCH_DEX, - InstallStep.PATCH_LIBS, - InstallStep.SIGN_APK, - InstallStep.INSTALL_APK, - ).map { - it to InstallStepData(it.nameResId, InstallStatus.QUEUED) - } - - val supportedVersion = preferences.version - val arch = Build.SUPPORTED_ABIS.first() - val cacheDir = externalCacheDir - val discordCacheDir = externalCacheDir.resolve(supportedVersion) - val patchedDir = discordCacheDir.resolve("patched").also { it.deleteRecursively() } - - clearOldCache(supportedVersion.toInt()) - uninstallNewAliucord(supportedVersion.toInt()) - - // Download base.apk - val baseApkFile = step(InstallStep.DL_BASE_APK) { - discordCacheDir.resolve("base-${supportedVersion}.apk").let { file -> - if (file.exists()) { - cached = true - } else { - downloadManager.downloadDiscordApk(supportedVersion, file) - } - - file.copyTo( - patchedDir.resolve(file.name), - true - ) - } - } - - // Download the native libraries split - val libsApkFile = step(InstallStep.DL_LIBS_APK) { - val libArch = arch.replace("-v", "_v") - discordCacheDir.resolve("config.$libArch-${supportedVersion}.apk").let { file -> - if (file.exists()) { - cached = true - } else downloadManager.downloadSplit( - version = supportedVersion, - split = "config.$libArch", - out = file - ) - - file.copyTo( - patchedDir.resolve(file.name), - true - ) - } - } - - // Download the locale split - val localeApkFile = step(InstallStep.DL_LANG_APK) { - discordCacheDir.resolve("config.en-${supportedVersion}.apk").let { file -> - if (file.exists()) { - cached = true - } else downloadManager.downloadSplit( - version = supportedVersion, - split = "config.en", - out = file - ) - - file.copyTo( - patchedDir.resolve(file.name), - true - ) - } - } - - // Download the drawables split - val resApkFile = step(InstallStep.DL_RESC_APK) { - // TODO: download the appropriate dpi res apk - discordCacheDir.resolve("config.xxhdpi-${supportedVersion}.apk").let { file -> - if (file.exists()) { - cached = true - } else downloadManager.downloadSplit( - version = supportedVersion, - split = "config.xxhdpi", - out = file - ) - - file.copyTo( - patchedDir.resolve(file.name), - true - ) - } - } - - // Download hermes & c++ runtime lib - val (hermesLibrary, cppRuntimeLibrary) = step(InstallStep.DL_HERMES) { - // Fetch gh releases for Aliucord/Hermes - val latestHermesRelease = githubRepository.getHermesRelease().getOrThrow() - - // Download the hermes-release.aar file to replace in the apk - val hermes = cacheDir.resolve("hermes-release-${latestHermesRelease.tagName}.aar").also { file -> - if (file.exists()) { - cached = true - return@also - } - - latestHermesRelease.assets - .find { it.name == "hermes-release.aar" }!!.browserDownloadUrl - .also { downloadManager.download(it, file) } - } - - // Download the hermes-cppruntime-release.aar file to replace in the apk - val cppRuntime = if (!preferences.hermesReplaceLibCpp) null else { - cacheDir.resolve("hermes-cppruntime-release-${latestHermesRelease.tagName}.aar").also { file -> - if (file.exists()) return@also - cached = false - - latestHermesRelease.assets - .find { it.name == "hermes-cppruntime-release.aar" }!!.browserDownloadUrl - .also { downloadManager.download(it, file) } - } - } - - hermes to cppRuntime - } - - // Download Aliucord Native lib - val aliucordDexFile = step(InstallStep.DL_ALIUNATIVE) { - // Fetch the gh releases for Aliucord/AliucordNative - val latestAliucordNativeRelease = githubRepository.getAliucordNativeRelease().getOrThrow() - - // Download the Aliucord classes.dex file to add to the apk - cacheDir.resolve("aliucord-${latestAliucordNativeRelease.tagName}.dex").also { file -> - if (file.exists()) { - cached = true - return@also - } - - latestAliucordNativeRelease.assets - .find { it.name == "classes.dex" }!!.browserDownloadUrl - .also { downloadManager.download(it, file) } - } - } - - // Download AliucordRN bootstrap - val aliucordBootstrap = step(InstallStep.DL_BOOTSTRAP) { - // Fetch latest commit for bootstrap.js - val commit = githubRepository.getLatestBootstrapCommit().getOrThrow() - cacheDir.resolve("bootstrap-$commit.js").also { - if (it.exists()) { - cached = true - return@also - } - - downloadManager.downloadBootstrap(it) - } - } - - val apks = arrayOf(baseApkFile, libsApkFile, localeApkFile, resApkFile) - - // Replace app icons - if (preferences.replaceIcon) { - step(InstallStep.PATCH_APP_ICON) { - ZipWriter(baseApkFile, true).use { baseApk -> - val mipmaps = arrayOf("mipmap-xhdpi-v4", "mipmap-xxhdpi-v4", "mipmap-xxxhdpi-v4") - val icons = arrayOf("ic_logo_foreground.png", "ic_logo_square.png", "ic_logo_foreground.png") - - for (icon in icons) { - val newIcon = application.assets.open("icons/$icon") - .use { it.readBytes() } - - for (mipmap in mipmaps) { - val path = "res/$mipmap/$icon" - baseApk.deleteEntry(path) - baseApk.writeEntry(path, newIcon) - } - } - } - } - } - - // Patch manifests - step(InstallStep.PATCH_MANIFEST) { - apks.forEach { apk -> - val manifest = ZipReader(apk) - .use { zip -> zip.openEntry("AndroidManifest.xml")?.read() } - ?: throw IllegalStateException("No manifest in ${apk.name}") - - ZipWriter(apk, true).use { zip -> - val patchedManifestBytes = if (apk == baseApkFile) { - ManifestPatcher.patchManifest( - manifestBytes = manifest, - packageName = preferences.packageName, - appName = preferences.appName, - debuggable = preferences.debuggable, - ) - } else { - ManifestPatcher.renamePackage(manifest, preferences.packageName) - } - - zip.deleteEntry("AndroidManifest.xml", apk == libsApkFile) // Preserve alignment in libs apk - zip.writeEntry("AndroidManifest.xml", patchedManifestBytes) - } - } - } - - // Re-order dex files - step(InstallStep.PATCH_DEX) { - val (dexCount, firstDexBytes) = ZipReader(baseApkFile).use { zip -> - Pair( - // Find the amount of .dex files in apk - zip.entryNames.count { it.endsWith(".dex") }, - - // Get the first classes.dex bytes - zip.openEntry("classes.dex")?.read() - ?: throw IllegalStateException("No classes.dex in base apk") - ) - } - - ZipWriter(baseApkFile, true).use { zip -> - // Move first classes.dex to the dex file count + 1 to make place for Aliucord's .dex - zip.deleteEntry("classes.dex") - zip.writeEntry("classes${dexCount + 1}.dex", firstDexBytes) - - // Add Aliucord's .dex and make it load first by being the first .dex - zip.writeEntry("classes.dex", aliucordDexFile.readBytes()) - - // Add bootstrap - zip.writeEntry("bootstrap.js", aliucordBootstrap.readBytes(), ZipCompression.NONE) - } - } - - // Replace libs - step(InstallStep.PATCH_LIBS) { - ZipWriter(libsApkFile, true).use { libsApk -> - // Process the hermes and cpp runtime library - for (libFile in arrayOf(hermesLibrary, cppRuntimeLibrary)) { - libFile ?: continue - - // Map .aar to the embedded .so inside - val binaryName = with(libFile.name) { - when { - startsWith("hermes-release") -> "libhermes.so" - startsWith("hermes-cppruntime-release") -> "libc++_shared.so" - else -> throw Error("Unable to map $this to embedded .so") - } - } - - // Read the embedded .so inside the .aar library - val libBytes = ZipReader(libFile).use { libZip -> - libZip.openEntry("jni/$arch/$binaryName")?.read() - ?: throw IllegalStateException("Failed to read jni/$arch/$binaryName from ${libFile.name}") - } - - // Delete the old binary and add the new one instead - libsApk.deleteEntry("lib/$arch/$binaryName", true) - libsApk.writeEntry("lib/$arch/$binaryName", libBytes, ZipCompression.NONE, 4096) - } - } - } - - step(InstallStep.SIGN_APK) { - // Align resources.arsc due to targeting api 30 for silent install - if (Build.VERSION.SDK_INT >= 31) { - for (file in apks) { - val bytes = ZipReader(file).use { - if (it.entryNames.contains("resources.arsc")) { - it.openEntry("resources.arsc")?.read() - } else { - null - } - } ?: continue - - ZipWriter(file, true).use { - it.deleteEntry("resources.arsc", true) - it.writeEntry("resources.arsc", bytes, ZipCompression.NONE, 4096) - } - } - } - - apks.forEach(Signer::signApk) - } - - step(InstallStep.INSTALL_APK) { - application.installApks(silent = !preferences.devMode, *apks) - - if (!preferences.keepPatchedApks) { - patchedDir.deleteRecursively() - } - } - } - private suspend fun installKotlin() { steps += listOfNotNull( InstallStep.FETCH_KT_VERSION, @@ -645,7 +345,6 @@ class InstallViewModel( } } - @OptIn(ExperimentalTime::class) private inline fun step(step: InstallStep, block: InstallStepData.() -> T): T { steps[step]!!.status = InstallStatus.ONGOING currentStep = step @@ -691,16 +390,6 @@ class InstallViewModel( @StringRes val nameResId: Int ) { - // React Native - DL_BASE_APK(InstallStepGroup.APK_DL, R.string.install_step_dl_apk_base), - DL_LIBS_APK(InstallStepGroup.APK_DL, R.string.install_step_dl_apk_lib), - DL_LANG_APK(InstallStepGroup.APK_DL, R.string.install_step_dl_apk_locale), - DL_RESC_APK(InstallStepGroup.APK_DL, R.string.install_step_dl_apk_resource), - - DL_HERMES(InstallStepGroup.LIB_DL, R.string.install_step_dl_lib_hermes), - DL_ALIUNATIVE(InstallStepGroup.LIB_DL, R.string.install_step_dl_lib_aliunative), - DL_BOOTSTRAP(InstallStepGroup.LIB_DL, R.string.install_step_dl_bootstrap), - // Kotlin FETCH_KT_VERSION(InstallStepGroup.APK_DL, R.string.install_step_fetch_kt_version), DL_KT_APK(InstallStepGroup.APK_DL, R.string.install_step_dl_kt_apk), diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c2df6c6..635b318 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -119,7 +119,7 @@ Download APKs Download Libraries Patch APKs - Install + Install APK Patching app icons Patching apk manifests diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1397867..0c6d1f8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,7 @@ accompanist-systemUiController = { module = "com.google.accompanist:accompanist- androidx-activity = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity" } androidx-core = { module = "androidx.core:core-ktx", version.ref = "androidx-core" } androidx-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "androidx-splashscreen" } -androidx-paging = "androidx.paging:paging-compose:3.3.0-alpha02" # TODO: remove paging +androidx-paging = "androidx.paging:paging-compose:1.0.0-alpha17" # TODO: remove paging # Compose compose-runtime = { module = "androidx.compose.runtime:runtime", version.ref = "compose" } @@ -37,6 +37,7 @@ compose-foundation = { module = "androidx.compose.foundation:foundation", versio compose-animations = { module = "androidx.compose.animation:animation-graphics", version.ref = "compose" } compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" } compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" } +compose-icons = { module = "androidx.compose.material:material-icons-extended", version.ref = "compose" } compose-material3 = { module = "androidx.compose.material3:material3", version.ref = "compose-material3" } # Compose debug tooling @@ -81,6 +82,7 @@ compose = [ "compose-runtime", "compose-ui", "compose-foundation", + "compose-icons", "compose-material3", "compose-animations", ]