Skip to content
Open
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
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ build/

# Local configuration file (sdk path, etc)
local.properties
old_build.gradle.kts

# Log/OS Files
*.log
Expand All @@ -23,6 +24,9 @@ misc.xml
deploymentTargetDropDown.xml
render.experimental.xml

# Kotlin
.kotlin/

# Keystore files
*.jks
*.keystore
Expand All @@ -32,3 +36,6 @@ google-services.json

# Android Profiling
*.hprof

# Mac files
.DS_Store
9 changes: 9 additions & 0 deletions .run/CLI GUI.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="CLI GUI" type="Application" factoryName="Application">
<option name="MAIN_CLASS_NAME" value="app.morphe.MorpheLauncherKt" />
<module name="morphe-cli.main" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
121 changes: 105 additions & 16 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
alias(libs.plugins.kotlin)
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.compose)
alias(libs.plugins.shadow)
application
`maven-publish`
Expand All @@ -11,10 +13,33 @@ plugins {

group = "app.morphe"

// ============================================================================
// JVM / Kotlin Configuration
// ============================================================================
kotlin {
jvmToolchain {
languageVersion.set(JavaLanguageVersion.of(17))
vendor.set(JvmVendorSpec.ADOPTIUM)
}
compilerOptions {
jvmTarget.set(JvmTarget.JVM_17)
}
}

// ============================================================================
// Application Entry Point
// ============================================================================
// Shadow JAR reads this for Main-Class manifest attribute.
//
// No args / double-click → GUI (Compose Desktop)
// With args (terminal) → CLI (PicoCLI)
application {
mainClass = "app.morphe.cli.command.MainCommandKt"
mainClass.set("app.morphe.MorpheLauncherKt")
}

// ============================================================================
// Repositories
// ============================================================================
repositories {
mavenLocal()
mavenCentral()
Expand All @@ -23,15 +48,20 @@ repositories {
// A repository must be specified for some reason. "registry" is a dummy.
url = uri("https://maven.pkg.github.com/MorpheApp/registry")
credentials {
username = project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR")
password = project.findProperty("gpr.key") as String? ?: System.getenv("GITHUB_TOKEN")
username = project.findProperty("gpr.user") as String?
?: System.getenv("GITHUB_ACTOR")
password = project.findProperty("gpr.key") as String?
?: System.getenv("GITHUB_TOKEN")
}
}
// Obtain baksmali/smali from source builds - https://github.com/iBotPeaches/smali
// Remove when official smali releases come out again.
maven { url = uri("https://jitpack.io") }
}

// ============================================================================
// Dependencies
// ============================================================================
val apkEditorLib by configurations.creating

val strippedApkEditorLib by tasks.registering(org.gradle.jvm.tasks.Jar::class) {
Expand All @@ -52,27 +82,59 @@ val strippedApkEditorLib by tasks.registering(org.gradle.jvm.tasks.Jar::class) {
}

dependencies {
// -- CLI / Core --------------------------------------------------------
implementation(libs.morphe.patcher)
implementation(libs.morphe.library)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.serialization.json)
implementation(libs.picocli)
apkEditorLib(files("$rootDir/libs/APKEditor-1.4.7.jar"))
implementation(files(strippedApkEditorLib))

testImplementation(libs.kotlin.test)
}
// -- Compose Desktop ---------------------------------------------------
// Platform-independent: single JAR runs on all supported OSes.
// Skiko auto-detects the OS at runtime and loads the correct native library.
implementation(compose.desktop.macos_arm64)
implementation(compose.desktop.macos_x64)
implementation(compose.desktop.linux_x64)
implementation(compose.desktop.linux_arm64)
implementation(compose.desktop.windows_x64)
implementation(compose.components.resources)
@Suppress("DEPRECATION")
implementation(compose.material3)
implementation(compose.materialIconsExtended)

// -- Async / Serialization ---------------------------------------------
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.coroutines.swing)
implementation(libs.kotlinx.serialization.json)

kotlin {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11)
}
}
// -- Networking (GUI) --------------------------------------------------
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.cio)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.ktor.client.logging)

// -- DI / Navigation (GUI) ---------------------------------------------
implementation(platform(libs.koin.bom))
implementation(libs.koin.core)
implementation(libs.koin.compose)

java {
targetCompatibility = JavaVersion.VERSION_11
implementation(libs.voyager.navigator)
implementation(libs.voyager.screenmodel)
implementation(libs.voyager.koin)
implementation(libs.voyager.transitions)

// -- APK Parsing (GUI) -------------------------------------------------
implementation(libs.apk.parser)

// -- Testing -----------------------------------------------------------
testImplementation(libs.kotlin.test)
testImplementation(libs.mockk)
}

// ============================================================================
// Tasks
// ============================================================================
tasks {
test {
useJUnitPlatform()
Expand All @@ -82,9 +144,15 @@ tasks {
}

processResources {
expand("projectVersion" to project.version)
// Only expand properties files, not binary files like PNG/ICO
filesMatching("**/*.properties") {
expand("projectVersion" to project.version)
}
}

// -------------------------------------------------------------------------
// Shadow JAR — the only distribution artifact
// -------------------------------------------------------------------------
shadowJar {
Copy link
Contributor

@LisoUseInAIKyrios LisoUseInAIKyrios Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional, but ideally we try to add Proguard to this to strip out unused code/libraries, because with the GUI CLI grows from ~55MB to ~170MB

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main problem with the size is coming from having skiko libs for all the OS. But will add ProGuard tomorrow

exclude(
"/prebuilt/linux/aapt",
Expand All @@ -94,14 +162,35 @@ tasks {
minimize {
exclude(dependency("org.bouncycastle:.*"))
exclude(dependency("app.morphe:morphe-patcher"))
// Compose / Skiko / Swing — cannot be minimized (reflection, native libs)
exclude(dependency("org.jetbrains.compose.*:.*"))
exclude(dependency("org.jetbrains.skiko:.*"))
exclude(dependency("org.jetbrains.kotlinx:kotlinx-coroutines-swing:.*"))
// Ktor uses ServiceLoader
exclude(dependency("io.ktor:.*"))
// Koin uses reflection
exclude(dependency("io.insert-koin:.*"))
}

mergeServiceFiles()
}

distTar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}

distZip {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}

publish {
dependsOn(shadowJar)
}
}

// ============================================================================
// Publishing / Signing
// ============================================================================
// Needed by gradle-semantic-release-plugin.
// Tracking: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435

Expand Down
72 changes: 65 additions & 7 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,20 +1,78 @@
[versions]
shadow = "8.3.9"
# Core
kotlin = "2.3.0"
kotlinx = "1.9.0"
shadow = "8.3.9"

# CLI
picocli = "4.7.7"
morphe-patcher = "1.1.1"
morphe-library = "1.2.0"

# Compose Desktop
compose = "1.10.0"

# Networking
ktor = "3.4.0"

# DI
koin-bom = "4.1.1"

# Navigation
voyager = "1.1.0-beta03"

# Async / Serialization
coroutines = "1.10.2"
kotlinx-serialization = "1.9.0"

# APK
apk-parser = "2.6.10"
arsclib = "1.3.8"

# Testing
mockk = "1.14.3"

[libraries]
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx" }
# Morphe Core
picocli = { module = "info.picocli:picocli", version.ref = "picocli" }
morphe-patcher = { module = "app.morphe:morphe-patcher", version.ref = "morphe-patcher" }
morphe-library = { module = "app.morphe:morphe-library-jvm", version.ref = "morphe-library" }

# Ktor Client
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
ktor-client-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" }

# Koin
koin-bom = { module = "io.insert-koin:koin-bom", version.ref = "koin-bom" }
koin-core = { module = "io.insert-koin:koin-core" }
koin-compose = { module = "io.insert-koin:koin-compose" }

# Voyager Navigation
voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" }
voyager-screenmodel = { module = "cafe.adriel.voyager:voyager-screenmodel", version.ref = "voyager" }
voyager-koin = { module = "cafe.adriel.voyager:voyager-koin", version.ref = "voyager" }
voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyager" }

# Coroutines
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
kotlinx-coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "coroutines" }

# Serialization
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }

# APK
apk-parser = { module = "net.dongliu:apk-parser", version.ref = "apk-parser" }
arsclib = { module = "io.github.reandroid:ARSCLib", version.ref = "arsclib" }

# Testing
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
mockk = { module = "io.mockk:mockk", version.ref = "mockk" }

[plugins]
shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
compose = { id = "org.jetbrains.compose", version.ref = "compose" }
shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }
13 changes: 13 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
pluginManagement {
repositories {
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
google()
mavenCentral()
gradlePluginPortal()
}
}

plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
}

rootProject.name = "morphe-cli"

// Include morphe-patcher and morphe-library as composite builds if they exist locally
Expand Down
40 changes: 40 additions & 0 deletions src/main/composeResources/drawable/morphe_dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading