From 2597efe474f24c93b68e0683bc0e9622e48623d1 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Thu, 8 Aug 2024 18:37:38 +0200 Subject: [PATCH] fix: Build DEX from patches file by using internal APIs instead of CLIs This commit uses D8 internal libraries which doesn't require an Android SDK anymore installed and apkzlib instead of an existing zip binary in path. --- build.gradle.kts | 8 ++-- gradle/libs.versions.toml | 2 + .../revanced/patches/gradle/PatchesPlugin.kt | 45 ++++++++++--------- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index e2a6afe..cb5bcf8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,12 +16,14 @@ repositories { } dependencies { - implementation(gradleApi()) - implementation(gradleKotlinDsl()) + implementation(libs.android.application) implementation(libs.binary.compatibility.validator) + implementation(libs.guava) implementation(libs.kotlin) implementation(libs.kotlin.android) - implementation(libs.android.application) + + implementation(gradleApi()) + implementation(gradleKotlinDsl()) } java { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 77d7070..f040071 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,12 +4,14 @@ pluginPublish = "1.2.1" binary-compatibility-validator = "0.15.1" #noinspection GradleDependency agp = "8.2.2" # 8.3.0 causes Java verifier error: https://github.com/ReVanced/revanced-patches/issues/2818 +guava = "33.2.1-jre" [libraries] binary-compatibility-validator = { module = "org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin", version.ref = "binary-compatibility-validator" } kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } kotlin-android = { module = "org.jetbrains.kotlin.android:org.jetbrains.kotlin.android.gradle.plugin", version.ref = "kotlin" } android-application = { module = "com.android.application:com.android.application.gradle.plugin", version.ref = "agp" } +guava = { module = "com.google.guava:guava", version.ref = "guava" } [plugins] kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin"} diff --git a/src/main/kotlin/app/revanced/patches/gradle/PatchesPlugin.kt b/src/main/kotlin/app/revanced/patches/gradle/PatchesPlugin.kt index 754bb3e..f0d3e13 100644 --- a/src/main/kotlin/app/revanced/patches/gradle/PatchesPlugin.kt +++ b/src/main/kotlin/app/revanced/patches/gradle/PatchesPlugin.kt @@ -1,5 +1,11 @@ package app.revanced.patches.gradle +import com.android.tools.build.apkzlib.zip.ZFile +import com.android.tools.r8.CompilationMode +import com.android.tools.r8.D8 +import com.android.tools.r8.D8Command +import com.android.tools.r8.OutputMode +import com.android.tools.r8.utils.ArchiveResourceProvider import kotlinx.validation.BinaryCompatibilityValidatorPlugin import org.gradle.api.JavaVersion import org.gradle.api.Plugin @@ -12,12 +18,10 @@ import org.gradle.api.publish.maven.MavenPublication import org.gradle.api.tasks.SourceSetContainer import org.gradle.jvm.tasks.Jar import org.gradle.kotlin.dsl.get -import org.gradle.kotlin.dsl.support.listFilesOrdered import org.gradle.plugins.signing.SigningExtension import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension import org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper -import java.io.File @Suppress("unused") abstract class PatchesPlugin : Plugin { @@ -102,32 +106,32 @@ abstract class PatchesPlugin : Plugin { } /** - * Adds a task to build the DEX file of the patches and add it to the patches file to use on Android, + * Adds a task to build the DEX file of the patches and adds it to the patches file to use on Android, * adds the publishing plugin to the project to publish the patches API and * configures the publication with the "about" information from the extension. */ private fun Project.configurePublishing(patchesExtension: PatchesExtension) { - tasks.register("buildDexJar") { - it.description = "Build and add a DEX to the JAR file" - it.group = "build" + val buildAndroid = tasks.register("buildAndroid") { task -> + task.description = "Builds the project for Android by compiling to DEX and adding it to the patches file." + task.group = "build" - it.dependsOn(tasks["build"]) + task.dependsOn(tasks["jar"]) - it.doLast { - val d8 = File(System.getenv("ANDROID_HOME")).resolve("build-tools") - .listFilesOrdered().last().resolve("d8").absolutePath + task.doLast { + val workingDirectory = layout.buildDirectory.dir("revanced").get().asFile - val patchesJar = configurations["archives"].allArtifacts.files.files.first().absolutePath - val workingDirectory = layout.buildDirectory.dir("libs").get().asFile + val patchesFile = tasks["jar"].outputs.files.first() + val classesZipFile = workingDirectory.resolve("classes.zip") - exec { execSpec -> - execSpec.workingDir = workingDirectory - execSpec.commandLine = listOf(d8, "--release", patchesJar) - } + D8Command.builder() + .addProgramResourceProvider(ArchiveResourceProvider.fromArchive(patchesFile.toPath(), true)) + .setMode(CompilationMode.RELEASE) + .setOutput(classesZipFile.toPath(), OutputMode.DexIndexed) + .build() + .let(D8::run) - exec { execSpec -> - execSpec.workingDir = workingDirectory - execSpec.commandLine = listOf("zip", "-u", patchesJar, "classes.dex") + ZFile.openReadWrite(patchesFile).use { zFile -> + zFile.mergeFrom(ZFile.openReadOnly(classesZipFile)) { false } } } } @@ -167,7 +171,7 @@ abstract class PatchesPlugin : Plugin { // Used by gradle-semantic-release-plugin. // Tracking: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435 tasks["publish"].apply { - dependsOn("buildDexJar") + dependsOn(buildAndroid) } } @@ -232,4 +236,3 @@ private fun Project.configureJarTask(patchesExtension: PatchesExtension) { } } } -