Skip to content

Commit

Permalink
fix: Build DEX from patches file by using internal APIs instead of CLIs
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
oSumAtrIX committed Aug 8, 2024
1 parent b1a00e9 commit 2597efe
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 24 deletions.
8 changes: 5 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"}
Expand Down
45 changes: 24 additions & 21 deletions src/main/kotlin/app/revanced/patches/gradle/PatchesPlugin.kt
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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<Project> {
Expand Down Expand Up @@ -102,32 +106,32 @@ abstract class PatchesPlugin : Plugin<Project> {
}

/**
* 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 }
}
}
}
Expand Down Expand Up @@ -167,7 +171,7 @@ abstract class PatchesPlugin : Plugin<Project> {
// Used by gradle-semantic-release-plugin.
// Tracking: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435
tasks["publish"].apply {
dependsOn("buildDexJar")
dependsOn(buildAndroid)
}
}

Expand Down Expand Up @@ -232,4 +236,3 @@ private fun Project.configureJarTask(patchesExtension: PatchesExtension) {
}
}
}

0 comments on commit 2597efe

Please sign in to comment.