Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
## [1.6.4-dev.2](https://github.com/MorpheApp/morphe-cli/compare/v1.6.4-dev.1...v1.6.4-dev.2) (2026-03-31)


### Bug Fixes

* Use same default keystore values as Morphe Manager ([#96](https://github.com/MorpheApp/morphe-cli/issues/96)) ([2d70c01](https://github.com/MorpheApp/morphe-cli/commit/2d70c016f293ba382266fb5c800073f763d633d8))

## [1.6.4-dev.1](https://github.com/MorpheApp/morphe-cli/compare/v1.6.3...v1.6.4-dev.1) (2026-03-30)


### Bug Fixes

* Use patcher implementation of strip libs ([#83](https://github.com/MorpheApp/morphe-cli/issues/83)) ([43f50ea](https://github.com/MorpheApp/morphe-cli/commit/43f50ea133088090648fa318047626f3166b8639)), closes [#80](https://github.com/MorpheApp/morphe-cli/issues/80) [#82](https://github.com/MorpheApp/morphe-cli/issues/82)

## [1.6.3](https://github.com/MorpheApp/morphe-cli/compare/v1.6.2...v1.6.3) (2026-03-28)


Expand Down
3 changes: 1 addition & 2 deletions docs/0_prerequisites.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ To use Morphe CLI, you will need to fulfill specific requirements.

## 🤝 Requirements

- Java Runtime Environment 11 ([Azul Zulu JRE](https://www.azul.com/downloads/?version=java-11-lts&package=jre#zulu) or [OpenJDK](https://jdk.java.net/archive/))
- Java Runtime Environment 17 - [Azul Zulu JRE](https://www.azul.com/downloads/?version=java-17-lts&package=jre#zulu) or [OpenJDK](https://jdk.java.net/archive/)
- [Android Debug Bridge (ADB)](https://developer.android.com/studio/command-line/adb) if you want to install the patched APK file on your device
- x86 or x86-64 (For [other architectures](https://github.com/Morphe/Morphe-manager/tree/main/android/app/src/main/jniLibs) use the `--custom-aapt2-binary` option)

## ⏭️ Whats next

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
org.gradle.parallel = true
org.gradle.caching = true
kotlin.code.style = official
version = 1.6.3
version = 1.6.4-dev.2
89 changes: 60 additions & 29 deletions src/main/kotlin/app/morphe/cli/command/PatchCommand.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,28 @@ import app.morphe.cli.command.model.mergeWith
import app.morphe.cli.command.model.toPatchBundle
import app.morphe.cli.command.model.toSerializablePatch
import app.morphe.cli.command.model.withUpdatedBundle
import app.morphe.engine.ApkLibraryStripper
import app.morphe.engine.PatchEngine
import app.morphe.engine.PatchEngine.Config.Companion.DEFAULT_KEYSTORE_ALIAS
import app.morphe.engine.PatchEngine.Config.Companion.DEFAULT_KEYSTORE_PASSWORD
import app.morphe.engine.PatchEngine.Config.Companion.LEGACY_KEYSTORE_ALIAS
import app.morphe.engine.PatchEngine.Config.Companion.LEGACY_KEYSTORE_PASSWORD
import app.morphe.engine.UpdateChecker
import app.morphe.patcher.apk.ApkUtils
import app.morphe.patcher.apk.ApkUtils.applyTo
import app.morphe.library.installation.installer.*
import app.morphe.library.installation.installer.AdbInstaller
import app.morphe.library.installation.installer.AdbInstallerResult
import app.morphe.library.installation.installer.AdbRootInstaller
import app.morphe.library.installation.installer.DeviceNotFoundException
import app.morphe.library.installation.installer.Installer
import app.morphe.library.installation.installer.RootInstallerResult
import app.morphe.patcher.Patcher
import app.morphe.patcher.PatcherConfig
import app.morphe.patcher.apk.ApkMerger
import app.morphe.patcher.apk.ApkUtils
import app.morphe.patcher.apk.ApkUtils.applyTo
import app.morphe.patcher.logging.toMorpheLogger
import app.morphe.patcher.patch.Patch
import app.morphe.patcher.patch.loadPatchesFromJar
import app.morphe.patcher.patch.setOptions
import app.morphe.patcher.resource.CpuArchitecture
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
Expand Down Expand Up @@ -196,13 +206,13 @@ internal object PatchCommand : Callable<Int> {
description = ["Alias of the private key and certificate pair keystore entry."],
showDefaultValue = ALWAYS,
)
private var keyStoreEntryAlias = "Morphe Key"
private var keyStoreEntryAlias = PatchEngine.Config.DEFAULT_KEYSTORE_ALIAS

@CommandLine.Option(
names = ["--keystore-entry-password"],
description = ["Password of the keystore entry."],
)
private var keyStoreEntryPassword = "" // Empty password by default
private var keyStoreEntryPassword = PatchEngine.Config.DEFAULT_KEYSTORE_PASSWORD

@CommandLine.Option(
names = ["--signer"],
Expand Down Expand Up @@ -286,12 +296,26 @@ internal object PatchCommand : Callable<Int> {
)
private var unsigned: Boolean = false

private var keepArchitectures: Set<CpuArchitecture> = emptySet()
@CommandLine.Option(
names = ["--striplibs"],
description = ["Architectures to keep, comma-separated (e.g. arm64-v8a,x86). Strips all other native architectures."],
split = ",",
)
private var striplibs: List<String> = emptyList()
@Suppress("unused")
private fun setStripLibs(architectures: List<String>) {
this.keepArchitectures = architectures.map { arch ->
CpuArchitecture.valueOfOrNull(arch.trim())
?: throw CommandLine.ParameterException(
spec.commandLine(),
"Invalid architecture \"$arch\" in --striplibs. Valid values are: ${
CpuArchitecture.entries.joinToString(
", "
) { it.arch }
}",
)
}.toSet()
}

@CommandLine.Option(
names = ["--continue-on-error"],
Expand Down Expand Up @@ -460,6 +484,7 @@ internal object PatchCommand : Callable<Int> {
aaptBinaryPath?.path,
patcherTemporaryFilesPath.absolutePath,
if (aaptBinaryPath != null) { false } else { !forceApktool },
keepArchitectures
),
).use { patcher ->
val packageName = patcher.context.packageMetadata.packageName
Expand Down Expand Up @@ -646,33 +671,39 @@ internal object PatchCommand : Callable<Int> {
patcherResult.applyTo(this)
}
)
}.also { rebuiltApk ->
if (striplibs.isNotEmpty()) {
patchingResult.addStepResult(
PatchingStep.STRIPPING_LIBS,
{
ApkLibraryStripper.stripLibraries(rebuiltApk, striplibs) { msg ->
logger.info(msg)
}
}
)
}
}.let { patchedApkFile ->
if (!mount && !unsigned) {
patchingResult.addStepResult(
PatchingStep.SIGNING,
{
ApkUtils.signApk(
patchedApkFile,
outputFilePath,
signer,
ApkUtils.KeyStoreDetails(
keystoreFilePath,
keyStorePassword,
keyStoreEntryAlias,
keyStoreEntryPassword,
),
)
fun signApk(alias: String, password: String) {
ApkUtils.signApk(
patchedApkFile,
outputFilePath,
signer,
ApkUtils.KeyStoreDetails(
keystoreFilePath,
keyStorePassword,
alias,
password,
)
)
}
try {
signApk(keyStoreEntryAlias, keyStoreEntryPassword)
} catch (e: Exception){
// Retry with legacy keystore defaults.
if (keyStoreEntryAlias == DEFAULT_KEYSTORE_ALIAS &&
keyStoreEntryPassword == DEFAULT_KEYSTORE_PASSWORD &&
keystoreFilePath.exists()
) {
logger.info("Using legacy keystore credentials")

signApk(LEGACY_KEYSTORE_ALIAS, LEGACY_KEYSTORE_PASSWORD)
} else {
throw e
}
}
}
)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package app.morphe.cli.command.model
enum class PatchingStep {
PATCHING,
REBUILDING,
STRIPPING_LIBS,
SIGNING,
INSTALLING
}
114 changes: 0 additions & 114 deletions src/main/kotlin/app/morphe/engine/ApkLibraryStripper.kt

This file was deleted.

Loading
Loading