From c8d4f56d61f3b2f98384062187702405e2058771 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Fri, 15 Sep 2023 02:56:55 +0200 Subject: [PATCH 01/17] build: Bump dependencies --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2f3c07d..18e2e07 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,7 @@ jackson-module-kotlin = "2.14.3" jadb = "2531a28109" kotlin-reflect = "1.9.0" kotlin-test = "1.8.20-RC" -kotlinx-coroutines-core = "1.7.1" +kotlinx-coroutines-core = "1.7.3" picocli = "4.7.3" revanced-patcher = "15.0.0-dev.2" From d09aca65dfd3d70052f8e3162fc6349685624c34 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Fri, 15 Sep 2023 03:00:34 +0200 Subject: [PATCH 02/17] chore: Move ReVanced CLI to subproject --- build.gradle.kts | 58 ++----------------- revanced-cli/build.gradle.kts | 55 ++++++++++++++++++ .../cli/command/ListPatchesCommand.kt | 0 .../app/revanced/cli/command/MainCommand.kt | 0 .../revanced/cli/command/OptionsCommand.kt | 0 .../app/revanced/cli/command/PatchCommand.kt | 0 .../cli/command/utility/InstallCommand.kt | 0 .../cli/command/utility/UninstallCommand.kt | 0 .../cli/command/utility/UtilityCommand.kt | 0 .../main/kotlin/app/revanced/utils/Options.kt | 0 .../app/revanced/utils/adb/AdbManager.kt | 0 .../kotlin/app/revanced/utils/adb/Commands.kt | 0 .../app/revanced/utils/adb/Constants.kt | 0 .../app/revanced/utils/align/ZipAligner.kt | 0 .../revanced/utils/align/zip/Extensions.kt | 0 .../app/revanced/utils/align/zip/ZipFile.kt | 0 .../align/zip/structures/ZipEndRecord.kt | 0 .../utils/align/zip/structures/ZipEntry.kt | 0 .../app/revanced/utils/signing/ApkSigner.kt | 0 .../revanced/utils/signing/SigningOptions.kt | 0 .../app/revanced/cli/version.properties | 0 .../patcher/options/PatchOptionsTest.kt | 0 settings.gradle.kts | 2 +- 23 files changed, 60 insertions(+), 55 deletions(-) create mode 100644 revanced-cli/build.gradle.kts rename {src => revanced-cli/src}/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt (100%) rename {src => revanced-cli/src}/main/kotlin/app/revanced/cli/command/MainCommand.kt (100%) rename {src => revanced-cli/src}/main/kotlin/app/revanced/cli/command/OptionsCommand.kt (100%) rename {src => revanced-cli/src}/main/kotlin/app/revanced/cli/command/PatchCommand.kt (100%) rename {src => revanced-cli/src}/main/kotlin/app/revanced/cli/command/utility/InstallCommand.kt (100%) rename {src => revanced-cli/src}/main/kotlin/app/revanced/cli/command/utility/UninstallCommand.kt (100%) rename {src => revanced-cli/src}/main/kotlin/app/revanced/cli/command/utility/UtilityCommand.kt (100%) rename {src => revanced-cli/src}/main/kotlin/app/revanced/utils/Options.kt (100%) rename {src => revanced-cli/src}/main/kotlin/app/revanced/utils/adb/AdbManager.kt (100%) rename {src => revanced-cli/src}/main/kotlin/app/revanced/utils/adb/Commands.kt (100%) rename {src => revanced-cli/src}/main/kotlin/app/revanced/utils/adb/Constants.kt (100%) rename {src => revanced-cli/src}/main/kotlin/app/revanced/utils/align/ZipAligner.kt (100%) rename {src => revanced-cli/src}/main/kotlin/app/revanced/utils/align/zip/Extensions.kt (100%) rename {src => revanced-cli/src}/main/kotlin/app/revanced/utils/align/zip/ZipFile.kt (100%) rename {src => revanced-cli/src}/main/kotlin/app/revanced/utils/align/zip/structures/ZipEndRecord.kt (100%) rename {src => revanced-cli/src}/main/kotlin/app/revanced/utils/align/zip/structures/ZipEntry.kt (100%) rename {src => revanced-cli/src}/main/kotlin/app/revanced/utils/signing/ApkSigner.kt (100%) rename {src => revanced-cli/src}/main/kotlin/app/revanced/utils/signing/SigningOptions.kt (100%) rename {src => revanced-cli/src}/main/resources/app/revanced/cli/version.properties (100%) rename {src => revanced-cli/src}/test/kotlin/app/revanced/patcher/options/PatchOptionsTest.kt (100%) diff --git a/build.gradle.kts b/build.gradle.kts index 9c6b335..f03e3dd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,57 +1,7 @@ plugins { - kotlin("jvm") version "1.8.20" - alias(libs.plugins.shadow) + kotlin("jvm") version "1.9.0" apply false } -group = "app.revanced" - -dependencies { - implementation(libs.revanced.patcher) - implementation(libs.kotlin.reflect) - implementation(libs.kotlinx.coroutines.core) - implementation(libs.picocli) - implementation(libs.jadb) // Updated fork - implementation(libs.apksig) - implementation(libs.bcpkix.jdk15on) - implementation(libs.jackson.module.kotlin) - testImplementation(libs.kotlin.test) -} - -kotlin { jvmToolchain(11) } - -tasks { - test { - useJUnitPlatform() - testLogging { - events("PASSED", "SKIPPED", "FAILED") - } - } - - processResources { - expand("projectVersion" to project.version) - } - - shadowJar { - manifest { - attributes("Main-Class" to "app.revanced.cli.command.MainCommandKt") - } - minimize { - exclude(dependency("org.jetbrains.kotlin:.*")) - exclude(dependency("org.bouncycastle:.*")) - exclude(dependency("app.revanced:.*")) - } - } - - build { - dependsOn(shadowJar) - } - - // Dummy task to fix the Gradle semantic-release plugin. - // Remove this if you forked it to support building only. - // Tracking issue: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435 - register("publish") { - group = "publish" - description = "Dummy task" - dependsOn(build) - } -} +allprojects { + group = "app.revanced" +} \ No newline at end of file diff --git a/revanced-cli/build.gradle.kts b/revanced-cli/build.gradle.kts new file mode 100644 index 0000000..3912e5f --- /dev/null +++ b/revanced-cli/build.gradle.kts @@ -0,0 +1,55 @@ +plugins { + kotlin("jvm") version "1.9.0" + alias(libs.plugins.shadow) +} + +dependencies { + implementation(libs.revanced.patcher) + implementation(libs.kotlin.reflect) + implementation(libs.kotlinx.coroutines.core) + implementation(libs.picocli) + implementation(libs.jadb) // Updated fork + implementation(libs.apksig) + implementation(libs.bcpkix.jdk15on) + implementation(libs.jackson.module.kotlin) + testImplementation(libs.kotlin.test) +} + +kotlin { jvmToolchain(11) } + +tasks { + test { + useJUnitPlatform() + testLogging { + events("PASSED", "SKIPPED", "FAILED") + } + } + + processResources { + expand("projectVersion" to project.version) + } + + shadowJar { + manifest { + attributes("Main-Class" to "app.revanced.cli.command.MainCommandKt") + } + minimize { + exclude(dependency("org.jetbrains.kotlin:.*")) + exclude(dependency("org.bouncycastle:.*")) + exclude(dependency("app.revanced:.*")) + } + } + + build { + dependsOn(shadowJar) + } + + // Dummy task to fix the Gradle semantic-release plugin. + // Remove this if you forked it to support building only. + // Tracking issue: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435 + register("publish") { + group = "publish" + description = "Dummy task" + dependsOn(build) + } +} diff --git a/src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt b/revanced-cli/src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt similarity index 100% rename from src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt rename to revanced-cli/src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt diff --git a/src/main/kotlin/app/revanced/cli/command/MainCommand.kt b/revanced-cli/src/main/kotlin/app/revanced/cli/command/MainCommand.kt similarity index 100% rename from src/main/kotlin/app/revanced/cli/command/MainCommand.kt rename to revanced-cli/src/main/kotlin/app/revanced/cli/command/MainCommand.kt diff --git a/src/main/kotlin/app/revanced/cli/command/OptionsCommand.kt b/revanced-cli/src/main/kotlin/app/revanced/cli/command/OptionsCommand.kt similarity index 100% rename from src/main/kotlin/app/revanced/cli/command/OptionsCommand.kt rename to revanced-cli/src/main/kotlin/app/revanced/cli/command/OptionsCommand.kt diff --git a/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt b/revanced-cli/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt similarity index 100% rename from src/main/kotlin/app/revanced/cli/command/PatchCommand.kt rename to revanced-cli/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt diff --git a/src/main/kotlin/app/revanced/cli/command/utility/InstallCommand.kt b/revanced-cli/src/main/kotlin/app/revanced/cli/command/utility/InstallCommand.kt similarity index 100% rename from src/main/kotlin/app/revanced/cli/command/utility/InstallCommand.kt rename to revanced-cli/src/main/kotlin/app/revanced/cli/command/utility/InstallCommand.kt diff --git a/src/main/kotlin/app/revanced/cli/command/utility/UninstallCommand.kt b/revanced-cli/src/main/kotlin/app/revanced/cli/command/utility/UninstallCommand.kt similarity index 100% rename from src/main/kotlin/app/revanced/cli/command/utility/UninstallCommand.kt rename to revanced-cli/src/main/kotlin/app/revanced/cli/command/utility/UninstallCommand.kt diff --git a/src/main/kotlin/app/revanced/cli/command/utility/UtilityCommand.kt b/revanced-cli/src/main/kotlin/app/revanced/cli/command/utility/UtilityCommand.kt similarity index 100% rename from src/main/kotlin/app/revanced/cli/command/utility/UtilityCommand.kt rename to revanced-cli/src/main/kotlin/app/revanced/cli/command/utility/UtilityCommand.kt diff --git a/src/main/kotlin/app/revanced/utils/Options.kt b/revanced-cli/src/main/kotlin/app/revanced/utils/Options.kt similarity index 100% rename from src/main/kotlin/app/revanced/utils/Options.kt rename to revanced-cli/src/main/kotlin/app/revanced/utils/Options.kt diff --git a/src/main/kotlin/app/revanced/utils/adb/AdbManager.kt b/revanced-cli/src/main/kotlin/app/revanced/utils/adb/AdbManager.kt similarity index 100% rename from src/main/kotlin/app/revanced/utils/adb/AdbManager.kt rename to revanced-cli/src/main/kotlin/app/revanced/utils/adb/AdbManager.kt diff --git a/src/main/kotlin/app/revanced/utils/adb/Commands.kt b/revanced-cli/src/main/kotlin/app/revanced/utils/adb/Commands.kt similarity index 100% rename from src/main/kotlin/app/revanced/utils/adb/Commands.kt rename to revanced-cli/src/main/kotlin/app/revanced/utils/adb/Commands.kt diff --git a/src/main/kotlin/app/revanced/utils/adb/Constants.kt b/revanced-cli/src/main/kotlin/app/revanced/utils/adb/Constants.kt similarity index 100% rename from src/main/kotlin/app/revanced/utils/adb/Constants.kt rename to revanced-cli/src/main/kotlin/app/revanced/utils/adb/Constants.kt diff --git a/src/main/kotlin/app/revanced/utils/align/ZipAligner.kt b/revanced-cli/src/main/kotlin/app/revanced/utils/align/ZipAligner.kt similarity index 100% rename from src/main/kotlin/app/revanced/utils/align/ZipAligner.kt rename to revanced-cli/src/main/kotlin/app/revanced/utils/align/ZipAligner.kt diff --git a/src/main/kotlin/app/revanced/utils/align/zip/Extensions.kt b/revanced-cli/src/main/kotlin/app/revanced/utils/align/zip/Extensions.kt similarity index 100% rename from src/main/kotlin/app/revanced/utils/align/zip/Extensions.kt rename to revanced-cli/src/main/kotlin/app/revanced/utils/align/zip/Extensions.kt diff --git a/src/main/kotlin/app/revanced/utils/align/zip/ZipFile.kt b/revanced-cli/src/main/kotlin/app/revanced/utils/align/zip/ZipFile.kt similarity index 100% rename from src/main/kotlin/app/revanced/utils/align/zip/ZipFile.kt rename to revanced-cli/src/main/kotlin/app/revanced/utils/align/zip/ZipFile.kt diff --git a/src/main/kotlin/app/revanced/utils/align/zip/structures/ZipEndRecord.kt b/revanced-cli/src/main/kotlin/app/revanced/utils/align/zip/structures/ZipEndRecord.kt similarity index 100% rename from src/main/kotlin/app/revanced/utils/align/zip/structures/ZipEndRecord.kt rename to revanced-cli/src/main/kotlin/app/revanced/utils/align/zip/structures/ZipEndRecord.kt diff --git a/src/main/kotlin/app/revanced/utils/align/zip/structures/ZipEntry.kt b/revanced-cli/src/main/kotlin/app/revanced/utils/align/zip/structures/ZipEntry.kt similarity index 100% rename from src/main/kotlin/app/revanced/utils/align/zip/structures/ZipEntry.kt rename to revanced-cli/src/main/kotlin/app/revanced/utils/align/zip/structures/ZipEntry.kt diff --git a/src/main/kotlin/app/revanced/utils/signing/ApkSigner.kt b/revanced-cli/src/main/kotlin/app/revanced/utils/signing/ApkSigner.kt similarity index 100% rename from src/main/kotlin/app/revanced/utils/signing/ApkSigner.kt rename to revanced-cli/src/main/kotlin/app/revanced/utils/signing/ApkSigner.kt diff --git a/src/main/kotlin/app/revanced/utils/signing/SigningOptions.kt b/revanced-cli/src/main/kotlin/app/revanced/utils/signing/SigningOptions.kt similarity index 100% rename from src/main/kotlin/app/revanced/utils/signing/SigningOptions.kt rename to revanced-cli/src/main/kotlin/app/revanced/utils/signing/SigningOptions.kt diff --git a/src/main/resources/app/revanced/cli/version.properties b/revanced-cli/src/main/resources/app/revanced/cli/version.properties similarity index 100% rename from src/main/resources/app/revanced/cli/version.properties rename to revanced-cli/src/main/resources/app/revanced/cli/version.properties diff --git a/src/test/kotlin/app/revanced/patcher/options/PatchOptionsTest.kt b/revanced-cli/src/test/kotlin/app/revanced/patcher/options/PatchOptionsTest.kt similarity index 100% rename from src/test/kotlin/app/revanced/patcher/options/PatchOptionsTest.kt rename to revanced-cli/src/test/kotlin/app/revanced/patcher/options/PatchOptionsTest.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index 9bd8dc7..01e6885 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -20,4 +20,4 @@ dependencyResolutionManagement { } } -rootProject.name = "revanced-cli" \ No newline at end of file +include("revanced-cli") From 2b77608651d3b46ee12688f9fbd4feca6bc71557 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Fri, 15 Sep 2023 03:01:09 +0200 Subject: [PATCH 03/17] chore: Add ReVanced Library subproject boilerplate --- revanced-cli/build.gradle.kts | 2 + revanced-cli/settings.gradle.kts | 1 + revanced-lib/build.gradle.kts | 69 +++++++++++++++++++ revanced-lib/settings.gradle.kts | 1 + .../app/revanced/lib/version.properties | 1 + settings.gradle.kts | 2 +- 6 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 revanced-cli/settings.gradle.kts create mode 100644 revanced-lib/build.gradle.kts create mode 100644 revanced-lib/settings.gradle.kts create mode 100644 revanced-lib/src/main/resources/app/revanced/lib/version.properties diff --git a/revanced-cli/build.gradle.kts b/revanced-cli/build.gradle.kts index 3912e5f..e9e54f6 100644 --- a/revanced-cli/build.gradle.kts +++ b/revanced-cli/build.gradle.kts @@ -4,6 +4,8 @@ plugins { } dependencies { + implementation(project(":revanced-lib")) + implementation(libs.revanced.patcher) implementation(libs.kotlin.reflect) implementation(libs.kotlinx.coroutines.core) diff --git a/revanced-cli/settings.gradle.kts b/revanced-cli/settings.gradle.kts new file mode 100644 index 0000000..028b7bc --- /dev/null +++ b/revanced-cli/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "revanced-cli" \ No newline at end of file diff --git a/revanced-lib/build.gradle.kts b/revanced-lib/build.gradle.kts new file mode 100644 index 0000000..63c2c30 --- /dev/null +++ b/revanced-lib/build.gradle.kts @@ -0,0 +1,69 @@ +plugins { + kotlin("jvm") version "1.9.0" + `maven-publish` +} + +dependencies { + testImplementation(libs.kotlin.test) +} + +kotlin { jvmToolchain(11) } + +java { + withSourcesJar() +} + +tasks { + test { + useJUnitPlatform() + testLogging { + events("PASSED", "SKIPPED", "FAILED") + } + } +} + +publishing { + repositories { + mavenLocal() + maven { + name = "GitHubPackages" + url = uri("https://maven.pkg.github.com/revanced/revanced-cli") + credentials { + username = System.getenv("GITHUB_ACTOR") + password = System.getenv("GITHUB_TOKEN") + } + } + } + publications { + create("gpr") { + from(components["java"]) + + version = project.version.toString() + + pom { + name = "ReVanced Library" + description = "Library for ReVanced" + url = "https://revanced.app" + + licenses { + license { + name = "GNU General Public License v3.0" + url = "https://www.gnu.org/licenses/gpl-3.0.en.html" + } + } + developers { + developer { + id = "ReVanced" + name = "ReVanced" + email = "contact@revanced.app" + } + } + scm { + connection = "scm:git:git://github.com/revanced/revanced-cli.git" + developerConnection = "scm:git:git@github.com:revanced/revanced-cli.git" + url = "https://github.com/revanced/revanced-cli" + } + } + } + } +} \ No newline at end of file diff --git a/revanced-lib/settings.gradle.kts b/revanced-lib/settings.gradle.kts new file mode 100644 index 0000000..f1bcd72 --- /dev/null +++ b/revanced-lib/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "revanced-lib" \ No newline at end of file diff --git a/revanced-lib/src/main/resources/app/revanced/lib/version.properties b/revanced-lib/src/main/resources/app/revanced/lib/version.properties new file mode 100644 index 0000000..308c9f8 --- /dev/null +++ b/revanced-lib/src/main/resources/app/revanced/lib/version.properties @@ -0,0 +1 @@ +version=${projectVersion} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 01e6885..3225d82 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -20,4 +20,4 @@ dependencyResolutionManagement { } } -include("revanced-cli") +include("revanced-cli", "revanced-lib") \ No newline at end of file From 7794327a11e8a0e0f28176cd45fad797b924c45f Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sat, 16 Sep 2023 19:42:36 +0200 Subject: [PATCH 04/17] feat: Use ReVanced Library in ReVanced CLI --- gradle/libs.versions.toml | 4 +- revanced-cli/build.gradle.kts | 7 +- .../app/revanced/cli/command/MainCommand.kt | 45 +--- .../revanced/cli/command/OptionsCommand.kt | 19 +- .../app/revanced/cli/command/PatchCommand.kt | 238 ++++++++---------- .../cli/command/utility/InstallCommand.kt | 16 +- .../cli/command/utility/UninstallCommand.kt | 16 +- .../revanced/utils/align/zip/Extensions.kt | 33 --- .../revanced/utils/signing/SigningOptions.kt | 7 - revanced-lib/api/revanced-lib.api | 111 ++++++++ revanced-lib/build.gradle.kts | 23 +- .../main/kotlin/app/revanced/lib/ApkUtils.kt | 84 +++++++ .../main/kotlin/app/revanced/lib}/Options.kt | 23 +- .../app/revanced/lib}/adb/AdbManager.kt | 55 ++-- .../kotlin/app/revanced/lib}/adb/Commands.kt | 2 +- .../kotlin/app/revanced/lib}/adb/Constants.kt | 2 +- .../kotlin/app/revanced/lib/logging/Logger.kt | 78 ++++++ .../app/revanced/lib}/signing/ApkSigner.kt | 18 +- .../revanced/lib/signing/SigningOptions.kt | 9 + .../kotlin/app/revanced/lib/zip/Extensions.kt | 33 +++ .../app/revanced/lib/zip}/ZipAligner.kt | 6 +- .../kotlin/app/revanced/lib}/zip/ZipFile.kt | 6 +- .../lib}/zip/structures/ZipEndRecord.kt | 12 +- .../revanced/lib}/zip/structures/ZipEntry.kt | 100 ++++---- .../app/revanced/lib/version.properties | 1 - .../patcher/options/PatchOptionsTest.kt | 6 +- 26 files changed, 587 insertions(+), 367 deletions(-) delete mode 100644 revanced-cli/src/main/kotlin/app/revanced/utils/align/zip/Extensions.kt delete mode 100644 revanced-cli/src/main/kotlin/app/revanced/utils/signing/SigningOptions.kt create mode 100644 revanced-lib/api/revanced-lib.api create mode 100644 revanced-lib/src/main/kotlin/app/revanced/lib/ApkUtils.kt rename {revanced-cli/src/main/kotlin/app/revanced/utils => revanced-lib/src/main/kotlin/app/revanced/lib}/Options.kt (85%) rename {revanced-cli/src/main/kotlin/app/revanced/utils => revanced-lib/src/main/kotlin/app/revanced/lib}/adb/AdbManager.kt (69%) rename {revanced-cli/src/main/kotlin/app/revanced/utils => revanced-lib/src/main/kotlin/app/revanced/lib}/adb/Commands.kt (97%) rename {revanced-cli/src/main/kotlin/app/revanced/utils => revanced-lib/src/main/kotlin/app/revanced/lib}/adb/Constants.kt (98%) create mode 100644 revanced-lib/src/main/kotlin/app/revanced/lib/logging/Logger.kt rename {revanced-cli/src/main/kotlin/app/revanced/utils => revanced-lib/src/main/kotlin/app/revanced/lib}/signing/ApkSigner.kt (87%) create mode 100644 revanced-lib/src/main/kotlin/app/revanced/lib/signing/SigningOptions.kt create mode 100644 revanced-lib/src/main/kotlin/app/revanced/lib/zip/Extensions.kt rename {revanced-cli/src/main/kotlin/app/revanced/utils/align => revanced-lib/src/main/kotlin/app/revanced/lib/zip}/ZipAligner.kt (70%) rename {revanced-cli/src/main/kotlin/app/revanced/utils/align => revanced-lib/src/main/kotlin/app/revanced/lib}/zip/ZipFile.kt (97%) rename {revanced-cli/src/main/kotlin/app/revanced/utils/align => revanced-lib/src/main/kotlin/app/revanced/lib}/zip/structures/ZipEndRecord.kt (89%) rename {revanced-cli/src/main/kotlin/app/revanced/utils/align => revanced-lib/src/main/kotlin/app/revanced/lib}/zip/structures/ZipEntry.kt (74%) delete mode 100644 revanced-lib/src/main/resources/app/revanced/lib/version.properties rename {revanced-cli => revanced-lib}/src/test/kotlin/app/revanced/patcher/options/PatchOptionsTest.kt (92%) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 18e2e07..31a079e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,8 @@ kotlin-reflect = "1.9.0" kotlin-test = "1.8.20-RC" kotlinx-coroutines-core = "1.7.3" picocli = "4.7.3" -revanced-patcher = "15.0.0-dev.2" +revanced-patcher = "15.0.0-dev.4" +binary-compatibility-validator = "0.13.2" [libraries] apksig = { module = "com.android.tools.build:apksig", version.ref = "apksig" } @@ -23,3 +24,4 @@ revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "re [plugins] shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" } +binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" } diff --git a/revanced-cli/build.gradle.kts b/revanced-cli/build.gradle.kts index e9e54f6..eaeae60 100644 --- a/revanced-cli/build.gradle.kts +++ b/revanced-cli/build.gradle.kts @@ -5,15 +5,10 @@ plugins { dependencies { implementation(project(":revanced-lib")) - implementation(libs.revanced.patcher) - implementation(libs.kotlin.reflect) implementation(libs.kotlinx.coroutines.core) implementation(libs.picocli) - implementation(libs.jadb) // Updated fork - implementation(libs.apksig) - implementation(libs.bcpkix.jdk15on) - implementation(libs.jackson.module.kotlin) + testImplementation(libs.kotlin.test) } diff --git a/revanced-cli/src/main/kotlin/app/revanced/cli/command/MainCommand.kt b/revanced-cli/src/main/kotlin/app/revanced/cli/command/MainCommand.kt index 5d71526..e1e1e03 100644 --- a/revanced-cli/src/main/kotlin/app/revanced/cli/command/MainCommand.kt +++ b/revanced-cli/src/main/kotlin/app/revanced/cli/command/MainCommand.kt @@ -1,52 +1,27 @@ package app.revanced.cli.command import app.revanced.cli.command.utility.UtilityCommand +import app.revanced.lib.logging.Logger import picocli.CommandLine import picocli.CommandLine.Command import picocli.CommandLine.IVersionProvider import java.util.* -import java.util.logging.* fun main(args: Array) { - System.setProperty("java.util.logging.SimpleFormatter.format", "%4\$s: %5\$s %n") - Logger.getLogger("").apply { - handlers.forEach { - it.close() - removeHandler(it) - } - - object : Handler() { - override fun publish(record: LogRecord) = formatter.format(record).toByteArray().let { - if (record.level.intValue() > Level.INFO.intValue()) - System.err.write(it) - else - System.out.write(it) - } - - override fun flush() { - System.out.flush() - System.err.flush() - } - - override fun close() = flush() - }.also { - it.level = Level.ALL - it.formatter = SimpleFormatter() - }.let(::addHandler) - } - + Logger.setDefault() CommandLine(MainCommand).execute(*args) } private object CLIVersionProvider : IVersionProvider { - override fun getVersion(): Array { - Properties().apply { - load(MainCommand::class.java.getResourceAsStream("/app/revanced/cli/version.properties")) - }.let { - return arrayOf("ReVanced CLI v${it.getProperty("version")}") - } - } + override fun getVersion() = arrayOf( + MainCommand::class.java.getResourceAsStream( + "/app/revanced/cli/version.properties" + )?.use { stream -> + Properties().apply { load(stream) }.let { + "ReVanced CLI v${it.getProperty("version")}" + } + } ?: "ReVanced CLI") } @Command( diff --git a/revanced-cli/src/main/kotlin/app/revanced/cli/command/OptionsCommand.kt b/revanced-cli/src/main/kotlin/app/revanced/cli/command/OptionsCommand.kt index f81c273..ceedbb0 100644 --- a/revanced-cli/src/main/kotlin/app/revanced/cli/command/OptionsCommand.kt +++ b/revanced-cli/src/main/kotlin/app/revanced/cli/command/OptionsCommand.kt @@ -1,8 +1,8 @@ package app.revanced.cli.command +import app.revanced.lib.Options +import app.revanced.lib.Options.setOptions import app.revanced.patcher.PatchBundleLoader -import app.revanced.utils.Options -import app.revanced.utils.Options.setOptions import picocli.CommandLine import picocli.CommandLine.Help.Visibility.ALWAYS import java.io.File @@ -37,10 +37,17 @@ internal object OptionsCommand : Runnable { ) private var update: Boolean = false - override fun run() = if (!filePath.exists() || overwrite) with(PatchBundleLoader.Jar(*patchBundles)) { - if (update && filePath.exists()) setOptions(filePath) + override fun run() = try { + PatchBundleLoader.Jar(*patchBundles).let { patches -> + if (!filePath.exists() || overwrite) { + if (update && filePath.exists()) patches.setOptions(filePath) - Options.serialize(this, prettyPrint = true).let(filePath::writeText) + Options.serialize(patches, prettyPrint = true).let(filePath::writeText) + } else throw OptionsFileAlreadyExistsException() + } + } catch (ex: OptionsFileAlreadyExistsException) { + logger.severe("Options file already exists, use --overwrite to override it") } - else logger.severe("Options file already exists, use --overwrite to override it") + + class OptionsFileAlreadyExistsException : Exception() } \ No newline at end of file diff --git a/revanced-cli/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt b/revanced-cli/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt index b39b048..16d9bf0 100644 --- a/revanced-cli/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt +++ b/revanced-cli/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt @@ -1,17 +1,19 @@ package app.revanced.cli.command -import app.revanced.patcher.* -import app.revanced.utils.Options -import app.revanced.utils.Options.setOptions -import app.revanced.utils.adb.AdbManager -import app.revanced.utils.align.ZipAligner -import app.revanced.utils.align.zip.ZipFile -import app.revanced.utils.align.zip.structures.ZipEntry -import app.revanced.utils.signing.ApkSigner -import app.revanced.utils.signing.SigningOptions +import app.revanced.lib.ApkUtils +import app.revanced.lib.Options +import app.revanced.lib.Options.setOptions +import app.revanced.lib.adb.AdbManager +import app.revanced.lib.signing.SigningOptions +import app.revanced.patcher.PatchBundleLoader +import app.revanced.patcher.PatchSet +import app.revanced.patcher.Patcher +import app.revanced.patcher.PatcherOptions import kotlinx.coroutines.runBlocking import picocli.CommandLine import picocli.CommandLine.Help.Visibility.ALWAYS +import picocli.CommandLine.Model.CommandSpec +import picocli.CommandLine.Spec import java.io.File import java.io.PrintWriter import java.io.StringWriter @@ -24,21 +26,15 @@ import java.util.logging.Logger internal object PatchCommand : Runnable { private val logger = Logger.getLogger(PatchCommand::class.java.name) - @CommandLine.Parameters( - description = ["APK file to be patched"], arity = "1..1" - ) + @Spec + lateinit var spec: CommandSpec // injected by picocli + private lateinit var apk: File - @CommandLine.Option( - names = ["-b", "--patch-bundle"], description = ["One or more bundles of patches"], required = true - ) - private var patchBundles = emptyList() - - @CommandLine.Option( - names = ["-m", "--merge"], description = ["One or more DEX files or containers to merge into the APK"] - ) private var integrations = listOf() + private var patchBundles = emptyList() + @CommandLine.Option( names = ["-i", "--include"], description = ["List of patches to include"] ) @@ -94,7 +90,7 @@ internal object PatchCommand : Runnable { @CommandLine.Option( names = ["--keystore"], description = ["Path to the keystore to sign the patched APK file with"] ) - private var keystorePath: String? = null + private var keystoreFilePath: File? = null @CommandLine.Option( names = ["--password"], description = ["The password of the keystore to sign the patched APK file with"] @@ -108,10 +104,7 @@ internal object PatchCommand : Runnable { ) private var resourceCachePath = File("revanced-resource-cache") - @CommandLine.Option( - names = ["--custom-aapt2-binary"], description = ["Path to a custom AAPT binary to compile resources with"] - ) - private var aaptBinaryPath = File("") + private var aaptBinaryPath: File? = null @CommandLine.Option( names = ["-p", "--purge"], @@ -120,36 +113,58 @@ internal object PatchCommand : Runnable { ) private var purge: Boolean = false + @CommandLine.Parameters( + description = ["APK file to be patched"], arity = "1..1" + ) + @Suppress("unused") + private fun setApk(apk: File) { + if (!apk.exists()) throw CommandLine.ParameterException( + spec.commandLine(), + "APK file ${apk.name} does not exist" + ) + this.apk = apk + } + + @CommandLine.Option( + names = ["-m", "--merge"], description = ["One or more DEX files or containers to merge into the APK"] + ) + @Suppress("unused") + private fun setIntegrations(integrations: Array) { + integrations.firstOrNull { !it.exists() }?.let { + throw CommandLine.ParameterException(spec.commandLine(), "Integrations file ${it.name} does not exist") + } + this.integrations += integrations + } + + @CommandLine.Option( + names = ["-b", "--patch-bundle"], description = ["One or more bundles of patches"], required = true + ) + private fun setPatchBundles(patchBundles: Array) { + patchBundles.firstOrNull { !it.exists() }?.let { + throw CommandLine.ParameterException(spec.commandLine(), "Patch bundle ${it.name} does not exist") + } + this.patchBundles = patchBundles.toList() + } + + @CommandLine.Option( + names = ["--custom-aapt2-binary"], description = ["Path to a custom AAPT binary to compile resources with"] + ) + private fun setAaptBinaryPath(aaptBinaryPath: File) { + if (!aaptBinaryPath.exists()) throw CommandLine.ParameterException( + spec.commandLine(), + "AAPT binary ${aaptBinaryPath.name} does not exist" + ) + this.aaptBinaryPath = aaptBinaryPath + } + override fun run() { - // region Prepare - - if (!apk.exists()) { - logger.severe("APK file ${apk.name} does not exist") - return - } - - integrations.filter { !it.exists() }.let { - if (it.isEmpty()) return@let - - it.forEach { integration -> - logger.severe("Integration file ${integration.name} does not exist") - } - return - } - - val adbManager = deviceSerial?.let { serial -> - if (mount) AdbManager.RootAdbManager(serial) - else AdbManager.UserAdbManager(serial) - } - - // endregion + val adbManager = deviceSerial?.let { serial -> AdbManager.getAdbManager(serial, mount) } // region Load patches logger.info("Loading patches") val patches = PatchBundleLoader.Jar(*patchBundles.toTypedArray()) - val integrations = integrations logger.info("Setting patch options") @@ -160,57 +175,62 @@ internal object PatchCommand : Runnable { // endregion - // region Patch - - val patcher = Patcher( + Patcher( PatcherOptions( apk, resourceCachePath, - aaptBinaryPath.path, + aaptBinaryPath?.path, resourceCachePath.absolutePath, ) - ) + ).use { patcher -> + // region Patch - val result = patcher.apply { - acceptIntegrations(integrations) - acceptPatches(filterPatchSelection(patches)) + val patcherResult = patcher.apply { + acceptIntegrations(integrations) + acceptPatches(filterPatchSelection(patches)) - // Execute patches. - runBlocking { - apply(false).collect { patchResult -> - patchResult.exception?.let { - StringWriter().use { writer -> - it.printStackTrace(PrintWriter(writer)) - logger.severe("${patchResult.patch.name} failed:\n$writer") - } - } ?: logger.info("${patchResult.patch.name} succeeded") + // Execute patches. + runBlocking { + apply(false).collect { patchResult -> + patchResult.exception?.let { + StringWriter().use { writer -> + it.printStackTrace(PrintWriter(writer)) + logger.severe("${patchResult.patch.name} failed:\n$writer") + } + } ?: logger.info("${patchResult.patch.name} succeeded") + } } - } - }.get() + }.get() - patcher.close() + // endregion - // endregion + // region Save - // region Finish - - val alignAndSignedFile = sign( - apk.newAlignedFile( - result, resourceCachePath.resolve("${outputFilePath.nameWithoutExtension}_aligned.apk") + ApkUtils.alignAndSign( + apk, + outputFilePath, + SigningOptions( + commonName, + password, + keystoreFilePath ?: outputFilePath.parentFile + .resolve("${outputFilePath.nameWithoutExtension}.keystore"), + ), + patcherResult ) - ) - logger.info("Copying to ${outputFilePath.name}") - alignAndSignedFile.copyTo(outputFilePath, overwrite = true) + // endregion - adbManager?.install(AdbManager.Apk(outputFilePath, patcher.context.packageMetadata.packageName)) + // region Install + + adbManager?.install(AdbManager.Apk(outputFilePath, patcher.context.packageMetadata.packageName)) + + // endregion + } if (purge) { logger.info("Purging temporary files") purge(resourceCachePath) } - - // endregion } @@ -279,64 +299,6 @@ internal object PatchCommand : Runnable { } } - /** - * Create a new aligned APK file. - * - * @param result The result of the patching process. - * @param outputFile The file to save the aligned APK to. - */ - private fun File.newAlignedFile( - result: PatcherResult, outputFile: File - ): File { - logger.info("Aligning $name") - - if (outputFile.exists()) outputFile.delete() - - ZipFile(outputFile).use { file -> - result.dexFiles.forEach { - file.addEntryCompressData( - ZipEntry.createWithName(it.name), it.stream.readBytes() - ) - } - - result.resourceFile?.let { - file.copyEntriesFromFileAligned( - ZipFile(it), ZipAligner::getEntryAlignment - ) - } - - // TODO: Do not compress result.doNotCompress - - file.copyEntriesFromFileAligned( - ZipFile(this), ZipAligner::getEntryAlignment - ) - } - - return outputFile - } - - /** - * Sign the APK file. - * - * @param inputFile The APK file to sign. - * @return The signed APK file. If [mount] is true, the input file will be returned. - */ - private fun sign(inputFile: File) = if (mount) inputFile - else { - logger.info("Signing ${inputFile.name}") - - val keyStoreFilePath = keystorePath - ?: outputFilePath.absoluteFile.parentFile.resolve("${outputFilePath.nameWithoutExtension}.keystore").canonicalPath - - val options = SigningOptions( - commonName, password, keyStoreFilePath - ) - - ApkSigner(options).signApk( - inputFile, resourceCachePath.resolve("${outputFilePath.nameWithoutExtension}_signed.apk") - ) - } - private fun purge(resourceCachePath: File) { val result = if (resourceCachePath.deleteRecursively()) "Purged resource cache directory" else "Failed to purge resource cache directory" diff --git a/revanced-cli/src/main/kotlin/app/revanced/cli/command/utility/InstallCommand.kt b/revanced-cli/src/main/kotlin/app/revanced/cli/command/utility/InstallCommand.kt index 593680d..680ed20 100644 --- a/revanced-cli/src/main/kotlin/app/revanced/cli/command/utility/InstallCommand.kt +++ b/revanced-cli/src/main/kotlin/app/revanced/cli/command/utility/InstallCommand.kt @@ -1,6 +1,6 @@ package app.revanced.cli.command.utility -import app.revanced.utils.adb.AdbManager +import app.revanced.lib.adb.AdbManager import picocli.CommandLine.* import java.io.File import java.util.logging.Logger @@ -28,15 +28,11 @@ internal object InstallCommand : Runnable { ) private var packageName: String? = null - override fun run() = try { - deviceSerials.forEach { deviceSerial -> - if (packageName != null) { - AdbManager.RootAdbManager(deviceSerial) - } else { - AdbManager.UserAdbManager(deviceSerial) - }.install(AdbManager.Apk(apk, packageName)) + override fun run() = deviceSerials.forEach { deviceSerial -> + try { + AdbManager.getAdbManager(deviceSerial, packageName != null).install(AdbManager.Apk(apk, packageName)) + } catch (e: AdbManager.DeviceNotFoundException) { + logger.severe(e.toString()) } - } catch (e: AdbManager.DeviceNotFoundException) { - logger.severe(e.toString()) } } \ No newline at end of file diff --git a/revanced-cli/src/main/kotlin/app/revanced/cli/command/utility/UninstallCommand.kt b/revanced-cli/src/main/kotlin/app/revanced/cli/command/utility/UninstallCommand.kt index e17bec7..52463f4 100644 --- a/revanced-cli/src/main/kotlin/app/revanced/cli/command/utility/UninstallCommand.kt +++ b/revanced-cli/src/main/kotlin/app/revanced/cli/command/utility/UninstallCommand.kt @@ -1,6 +1,6 @@ package app.revanced.cli.command.utility -import app.revanced.utils.adb.AdbManager +import app.revanced.lib.adb.AdbManager import picocli.CommandLine.* import picocli.CommandLine.Help.Visibility.ALWAYS import java.util.logging.Logger @@ -26,15 +26,11 @@ internal object UninstallCommand : Runnable { ) private var unmount: Boolean = false - override fun run() = try { - deviceSerials.forEach { deviceSerial -> - if (unmount) { - AdbManager.RootAdbManager(deviceSerial) - } else { - AdbManager.UserAdbManager(deviceSerial) - }.uninstall(packageName) + override fun run() = deviceSerials.forEach { deviceSerial -> + try { + AdbManager.getAdbManager(deviceSerial, unmount).uninstall(packageName) + } catch (e: AdbManager.DeviceNotFoundException) { + logger.severe(e.toString()) } - } catch (e: AdbManager.DeviceNotFoundException) { - logger.severe(e.toString()) } } \ No newline at end of file diff --git a/revanced-cli/src/main/kotlin/app/revanced/utils/align/zip/Extensions.kt b/revanced-cli/src/main/kotlin/app/revanced/utils/align/zip/Extensions.kt deleted file mode 100644 index 330c689..0000000 --- a/revanced-cli/src/main/kotlin/app/revanced/utils/align/zip/Extensions.kt +++ /dev/null @@ -1,33 +0,0 @@ -package app.revanced.utils.align.zip - -import java.io.DataInput -import java.io.DataOutput -import java.nio.ByteBuffer - -fun UInt.toLittleEndian() = - (((this.toInt() and 0xff000000.toInt()) shr 24) or ((this.toInt() and 0x00ff0000) shr 8) or ((this.toInt() and 0x0000ff00) shl 8) or (this.toInt() shl 24)).toUInt() - -fun UShort.toLittleEndian() = (this.toUInt() shl 16).toLittleEndian().toUShort() - -fun UInt.toBigEndian() = (((this.toInt() and 0xff) shl 24) or ((this.toInt() and 0xff00) shl 8) - or ((this.toInt() and 0x00ff0000) ushr 8) or (this.toInt() ushr 24)).toUInt() - -fun UShort.toBigEndian() = (this.toUInt() shl 16).toBigEndian().toUShort() - -fun ByteBuffer.getUShort() = this.getShort().toUShort() -fun ByteBuffer.getUInt() = this.getInt().toUInt() - -fun ByteBuffer.putUShort(ushort: UShort) = this.putShort(ushort.toShort()) -fun ByteBuffer.putUInt(uint: UInt) = this.putInt(uint.toInt()) - -fun DataInput.readUShort() = this.readShort().toUShort() -fun DataInput.readUInt() = this.readInt().toUInt() - -fun DataOutput.writeUShort(ushort: UShort) = this.writeShort(ushort.toInt()) -fun DataOutput.writeUInt(uint: UInt) = this.writeInt(uint.toInt()) - -fun DataInput.readUShortLE() = this.readUShort().toBigEndian() -fun DataInput.readUIntLE() = this.readUInt().toBigEndian() - -fun DataOutput.writeUShortLE(ushort: UShort) = this.writeUShort(ushort.toLittleEndian()) -fun DataOutput.writeUIntLE(uint: UInt) = this.writeUInt(uint.toLittleEndian()) diff --git a/revanced-cli/src/main/kotlin/app/revanced/utils/signing/SigningOptions.kt b/revanced-cli/src/main/kotlin/app/revanced/utils/signing/SigningOptions.kt deleted file mode 100644 index 9ffdc6d..0000000 --- a/revanced-cli/src/main/kotlin/app/revanced/utils/signing/SigningOptions.kt +++ /dev/null @@ -1,7 +0,0 @@ -package app.revanced.utils.signing - -data class SigningOptions( - val cn: String, - val password: String, - val keyStoreFilePath: String -) \ No newline at end of file diff --git a/revanced-lib/api/revanced-lib.api b/revanced-lib/api/revanced-lib.api new file mode 100644 index 0000000..32bbe4f --- /dev/null +++ b/revanced-lib/api/revanced-lib.api @@ -0,0 +1,111 @@ +public final class app/revanced/lib/ApkUtils { + public static final field INSTANCE Lapp/revanced/lib/ApkUtils; + public final fun alignAndSign (Ljava/io/File;Ljava/io/File;Lapp/revanced/lib/signing/SigningOptions;Lapp/revanced/patcher/PatcherResult;)V +} + +public final class app/revanced/lib/Options { + public static final field INSTANCE Lapp/revanced/lib/Options; + public final fun deserialize (Ljava/lang/String;)[Lapp/revanced/lib/Options$Patch; + public final fun serialize (Ljava/util/Set;Z)Ljava/lang/String; + public static synthetic fun serialize$default (Lapp/revanced/lib/Options;Ljava/util/Set;ZILjava/lang/Object;)Ljava/lang/String; + public final fun setOptions (Ljava/util/Set;Ljava/io/File;)V + public final fun setOptions (Ljava/util/Set;Ljava/lang/String;)V +} + +public final class app/revanced/lib/Options$Patch { + public final fun getOptions ()Ljava/util/List; + public final fun getPatchName ()Ljava/lang/String; +} + +public final class app/revanced/lib/Options$Patch$Option { + public final fun getKey ()Ljava/lang/String; + public final fun getValue ()Ljava/lang/Object; +} + +public abstract class app/revanced/lib/adb/AdbManager { + public static final field Companion Lapp/revanced/lib/adb/AdbManager$Companion; + public synthetic fun (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + protected final fun getDevice ()Lse/vidstige/jadb/JadbDevice; + protected final fun getLogger ()Ljava/util/logging/Logger; + public fun install (Lapp/revanced/lib/adb/AdbManager$Apk;)V + public fun uninstall (Ljava/lang/String;)V +} + +public final class app/revanced/lib/adb/AdbManager$Apk { + public fun (Ljava/io/File;Ljava/lang/String;)V + public synthetic fun (Ljava/io/File;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun getFile ()Ljava/io/File; + public final fun getPackageName ()Ljava/lang/String; +} + +public final class app/revanced/lib/adb/AdbManager$Companion { + public final fun getAdbManager (Ljava/lang/String;Z)Lapp/revanced/lib/adb/AdbManager; + public static synthetic fun getAdbManager$default (Lapp/revanced/lib/adb/AdbManager$Companion;Ljava/lang/String;ZILjava/lang/Object;)Lapp/revanced/lib/adb/AdbManager; +} + +public final class app/revanced/lib/adb/AdbManager$DeviceNotFoundException : java/lang/Exception { +} + +public final class app/revanced/lib/adb/AdbManager$RootAdbManager : app/revanced/lib/adb/AdbManager { + public static final field Utils Lapp/revanced/lib/adb/AdbManager$RootAdbManager$Utils; + public fun install (Lapp/revanced/lib/adb/AdbManager$Apk;)V + public fun uninstall (Ljava/lang/String;)V +} + +public final class app/revanced/lib/adb/AdbManager$RootAdbManager$Utils { +} + +public final class app/revanced/lib/adb/AdbManager$UserAdbManager : app/revanced/lib/adb/AdbManager { + public fun install (Lapp/revanced/lib/adb/AdbManager$Apk;)V + public fun uninstall (Ljava/lang/String;)V +} + +public final class app/revanced/lib/logging/Logger { + public static final field INSTANCE Lapp/revanced/lib/logging/Logger; + public final fun addHandler (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;)V + public final fun removeAllHandlers ()V + public final fun setDefault ()V + public final fun setFormat (Ljava/lang/String;)V + public static synthetic fun setFormat$default (Lapp/revanced/lib/logging/Logger;Ljava/lang/String;ILjava/lang/Object;)V +} + +public final class app/revanced/lib/signing/ApkSigner { + public fun (Lapp/revanced/lib/signing/SigningOptions;)V + public final fun signApk (Ljava/io/File;Ljava/io/File;)V +} + +public final class app/revanced/lib/signing/SigningOptions { + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/io/File;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/io/File; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/io/File;)Lapp/revanced/lib/signing/SigningOptions; + public static synthetic fun copy$default (Lapp/revanced/lib/signing/SigningOptions;Ljava/lang/String;Ljava/lang/String;Ljava/io/File;ILjava/lang/Object;)Lapp/revanced/lib/signing/SigningOptions; + public fun equals (Ljava/lang/Object;)Z + public final fun getCommonName ()Ljava/lang/String; + public final fun getKeyStoreOutputFilePath ()Ljava/io/File; + public final fun getPassword ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class app/revanced/lib/zip/ZipAligner { + public static final field INSTANCE Lapp/revanced/lib/zip/ZipAligner; + public final fun getEntryAlignment (Lapp/revanced/lib/zip/structures/ZipEntry;)Ljava/lang/Integer; +} + +public final class app/revanced/lib/zip/ZipFile : java/io/Closeable { + public fun (Ljava/io/File;)V + public final fun addEntryCompressData (Lapp/revanced/lib/zip/structures/ZipEntry;[B)V + public fun close ()V + public final fun copyEntriesFromFileAligned (Lapp/revanced/lib/zip/ZipFile;Lkotlin/jvm/functions/Function1;)V +} + +public final class app/revanced/lib/zip/structures/ZipEntry { + public static final field Companion Lapp/revanced/lib/zip/structures/ZipEntry$Companion; + public fun (Ljava/lang/String;)V +} + +public final class app/revanced/lib/zip/structures/ZipEntry$Companion { +} + diff --git a/revanced-lib/build.gradle.kts b/revanced-lib/build.gradle.kts index 63c2c30..ea0a0b0 100644 --- a/revanced-lib/build.gradle.kts +++ b/revanced-lib/build.gradle.kts @@ -1,18 +1,21 @@ plugins { kotlin("jvm") version "1.9.0" + alias(libs.plugins.binary.compatibility.validator) `maven-publish` } dependencies { + implementation(libs.revanced.patcher) + implementation(libs.kotlin.reflect) + implementation(libs.jadb) // Updated fork + implementation(libs.apksig) + implementation(libs.bcpkix.jdk15on) + implementation(libs.jackson.module.kotlin) + + testImplementation(libs.revanced.patcher) testImplementation(libs.kotlin.test) } -kotlin { jvmToolchain(11) } - -java { - withSourcesJar() -} - tasks { test { useJUnitPlatform() @@ -22,6 +25,12 @@ tasks { } } +kotlin { jvmToolchain(11) } + +java { + withSourcesJar() +} + publishing { repositories { mavenLocal() @@ -42,7 +51,7 @@ publishing { pom { name = "ReVanced Library" - description = "Library for ReVanced" + description = "Library containing common utilities for ReVanced" url = "https://revanced.app" licenses { diff --git a/revanced-lib/src/main/kotlin/app/revanced/lib/ApkUtils.kt b/revanced-lib/src/main/kotlin/app/revanced/lib/ApkUtils.kt new file mode 100644 index 0000000..930ffdf --- /dev/null +++ b/revanced-lib/src/main/kotlin/app/revanced/lib/ApkUtils.kt @@ -0,0 +1,84 @@ +package app.revanced.lib + +import app.revanced.lib.signing.ApkSigner +import app.revanced.lib.signing.SigningOptions +import app.revanced.lib.zip.ZipAligner +import app.revanced.lib.zip.ZipFile +import app.revanced.lib.zip.structures.ZipEntry +import app.revanced.patcher.PatcherResult +import java.io.File +import java.util.logging.Logger + +object ApkUtils { + private val logger = Logger.getLogger(ApkUtils::class.java.name) + + /** + * Aligns and signs the apk at [apkFile] and writes it to [outputFile]. + * + * @param apkFile The apk to align and sign. + * @param outputFile The apk to write the aligned and signed apk to. + * @param signingOptions The options to use for signing. + * @param patchedEntriesSource The result of the patcher to add the patched dex files and resources. + */ + fun alignAndSign( + apkFile: File, + outputFile: File, + signingOptions: SigningOptions, + patchedEntriesSource: PatcherResult + ) { + if (outputFile.exists()) outputFile.delete() + + align(apkFile, outputFile, patchedEntriesSource) + sign(outputFile, outputFile, signingOptions) + } + + /** + * Creates a new apk from [apkFile] and [patchedEntriesSource] and writes it to [outputFile]. + * + * @param apkFile The apk to copy entries from. + * @param outputFile The apk to write the new entries to. + * @param patchedEntriesSource The result of the patcher to add the patched dex files and resources. + */ + private fun align(apkFile: File, outputFile: File, patchedEntriesSource: PatcherResult) { + logger.info("Aligning ${apkFile.name}") + + ZipFile(outputFile).use { file -> + patchedEntriesSource.dexFiles.forEach { + file.addEntryCompressData( + ZipEntry(it.name), it.stream.readBytes() + ) + } + + patchedEntriesSource.resourceFile?.let { + file.copyEntriesFromFileAligned( + ZipFile(it), ZipAligner::getEntryAlignment + ) + } + + // TODO: Do not compress result.doNotCompress + + // TODO: Fix copying resources that are not needed anymore. + file.copyEntriesFromFileAligned( + ZipFile(apkFile), ZipAligner::getEntryAlignment + ) + } + } + + + /** + * Signs the apk at [apk] and writes it to [output]. + * + * @param apk The apk to sign. + * @param output The apk to write the signed apk to. + * @param signingOptions The options to use for signing. + */ + private fun sign( + apk: File, + output: File, + signingOptions: SigningOptions, + ) { + logger.info("Signing ${apk.name}") + + ApkSigner(signingOptions).signApk(apk, output) + } +} \ No newline at end of file diff --git a/revanced-cli/src/main/kotlin/app/revanced/utils/Options.kt b/revanced-lib/src/main/kotlin/app/revanced/lib/Options.kt similarity index 85% rename from revanced-cli/src/main/kotlin/app/revanced/utils/Options.kt rename to revanced-lib/src/main/kotlin/app/revanced/lib/Options.kt index 7891d4a..3bef852 100644 --- a/revanced-cli/src/main/kotlin/app/revanced/utils/Options.kt +++ b/revanced-lib/src/main/kotlin/app/revanced/lib/Options.kt @@ -1,15 +1,19 @@ -package app.revanced.utils +@file:Suppress("MemberVisibilityCanBePrivate") + +package app.revanced.lib +import app.revanced.lib.Options.Patch.Option +import app.revanced.patcher.PatchClass import app.revanced.patcher.PatchSet import app.revanced.patcher.patch.options.PatchOptionException -import app.revanced.utils.Options.PatchOption.Option import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import java.io.File import java.util.logging.Logger +private typealias PatchList = List -internal object Options { +object Options { private val logger = Logger.getLogger(Options::class.java.name) private var mapper = jacksonObjectMapper() @@ -24,7 +28,7 @@ internal object Options { fun serialize(patches: PatchSet, prettyPrint: Boolean = false): String = patches .filter { it.options.any() } .map { patch -> - PatchOption( + Patch( patch.name!!, patch.options.values.map { option -> Option(option.key, option.value) } ) @@ -42,12 +46,11 @@ internal object Options { * Deserializes the options for the patches in the list. * * @param json The JSON string containing the options. - * @return The list of [PatchOption]s. - * @see PatchOption + * @return The list of [Patch]s. + * @see Patch * @see PatchList */ - @Suppress("MemberVisibilityCanBePrivate") - fun deserialize(json: String): Array = mapper.readValue(json, Array::class.java) + fun deserialize(json: String): Array = mapper.readValue(json, Array::class.java) /** * Sets the options for the patches in the list. @@ -88,7 +91,7 @@ internal object Options { * @property patchName The name of the patch. * @property options The [Option]s for the patch. */ - internal data class PatchOption( + class Patch internal constructor( val patchName: String, val options: List