Reproducible Builds (#3559)

* fix: remove ShadowJar plugin

 - unable to control file dates of archive entries

* refactor: use native Gradle "fatJar" method

* refactor: drop proguard for r8

* fix: wire up R8

* wip: remove fail-fast

* Revert "wip: remove fail-fast"

This reverts commit 5d005bf82e87c89efa5552ee8f8e9c0a569aea0d.

* fix: suppress unused proguard keep messages

* fix: require java11+ for r8
This commit is contained in:
Connor Tumbleson 2024-04-07 11:45:55 -04:00 committed by GitHub
parent 25826db417
commit e69ecb578d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 54 additions and 47 deletions

View File

@ -1,25 +1,15 @@
import proguard.gradle.ProGuardTask
val apktoolVersion: String by rootProject.extra val apktoolVersion: String by rootProject.extra
plugins { plugins {
alias(libs.plugins.shadow)
application application
} }
// Buildscript is deprecated, but the alternative approach does not support expanded properties val r8: Configuration by configurations.creating
// https://github.com/gradle/gradle/issues/9830
// So we must hard-code the version here.
buildscript {
dependencies {
// Proguard doesn't support plugin DSL - https://github.com/Guardsquare/proguard/issues/225
classpath(libs.proguard)
}
}
dependencies { dependencies {
implementation(libs.commons.cli) implementation(libs.commons.cli)
implementation(project(":brut.apktool:apktool-lib")) implementation(project(":brut.apktool:apktool-lib"))
r8(libs.r8)
} }
application { application {
@ -28,10 +18,9 @@ application {
tasks.run.get().workingDir = file(System.getProperty("user.dir")) tasks.run.get().workingDir = file(System.getProperty("user.dir"))
} }
tasks.withType<Jar> { tasks.withType<AbstractArchiveTask>().configureEach {
manifest { isPreserveFileTimestamps = false
attributes["Main-Class"] = "brut.apktool.Main" isReproducibleFileOrder = true
}
} }
tasks.register<Delete>("cleanOutputDirectory") { tasks.register<Delete>("cleanOutputDirectory") {
@ -40,34 +29,50 @@ tasks.register<Delete>("cleanOutputDirectory") {
}) })
} }
tasks.register<ProGuardTask>("proguard") { val shadowJar = tasks.create("shadowJar", Jar::class) {
dependsOn("build")
dependsOn("cleanOutputDirectory") dependsOn("cleanOutputDirectory")
dependsOn("shadowJar")
injars(tasks.named("shadowJar").get().outputs.files)
val javaHome = System.getProperty("java.home") group = "build"
if (JavaVersion.current() <= JavaVersion.VERSION_1_8) { description = "Creates a single executable JAR with all dependencies"
libraryjars("$javaHome/lib/jce.jar") manifest.attributes["Main-Class"] = "brut.apktool.Main"
libraryjars("$javaHome/lib/rt.jar") duplicatesStrategy = DuplicatesStrategy.EXCLUDE
} else {
libraryjars(mapOf("jarfilter" to "!**.jar", "filter" to "!module-info.class"), val dependencies = configurations
{ .runtimeClasspath
"$javaHome/jmods/" .get()
} .map(::zipTree)
)
from(dependencies)
with(tasks.jar.get())
}
tasks.register<JavaExec>("proguard") {
dependsOn("shadowJar")
onlyIf {
JavaVersion.current().isJava11Compatible
} }
dontobfuscate() val proguardRules = file("proguard-rules.pro")
dontoptimize() val originalJar = shadowJar.outputs.files.singleFile
keep("class brut.apktool.Main { public static void main(java.lang.String[]); }") inputs.files(originalJar.toString(), proguardRules)
keepclassmembers("enum * { public static **[] values(); public static ** valueOf(java.lang.String); }") outputs.file("build/libs/apktool-$apktoolVersion.jar")
dontwarn("com.google.common.base.**")
dontwarn("com.google.common.collect.**")
dontwarn("com.google.common.util.**")
dontwarn("javax.xml.xpath.**")
dontnote("**")
val outPath = "build/libs/apktool-$apktoolVersion.jar" classpath(r8)
outjars(outPath) mainClass.set("com.android.tools.r8.R8")
args = mutableListOf(
"--release",
"--classfile",
"--no-minification",
"--map-diagnostics:UnusedProguardKeepRuleDiagnostic", "info", "none",
"--lib", javaLauncher.get().metadata.installationPath.toString(),
"--output", outputs.files.singleFile.toString(),
"--pg-conf", proguardRules.toString(),
originalJar.toString()
)
} }
tasks.getByPath(":release").dependsOn("proguard")

View File

@ -0,0 +1,7 @@
-keep class brut.apktool.Main {
public static void main(java.lang.String[]);
}
-keepclassmembers enum * {
static **[] values();
static ** valueOf(java.lang.String);
}

View File

@ -55,7 +55,6 @@ if ("release" !in gradle.startParameter.taskNames) {
} }
plugins { plugins {
alias(libs.plugins.shadow)
`java-library` `java-library`
`maven-publish` `maven-publish`
signing signing

View File

@ -6,8 +6,7 @@ commons_lang3 = "3.14.0"
commons_text = "1.11.0" commons_text = "1.11.0"
guava = "32.0.1-jre" guava = "32.0.1-jre"
junit = "4.13.2" junit = "4.13.2"
proguard = "7.4.2" r8 = "8.3.37"
shadow = "8.1.1"
smali = "3.0.5" smali = "3.0.5"
xmlpull = "1.1.4c" xmlpull = "1.1.4c"
xmlunit = "2.9.1" xmlunit = "2.9.1"
@ -20,10 +19,7 @@ commons_lang3 = { module = "org.apache.commons:commons-lang3", version.ref = "co
commons_text = { module = "org.apache.commons:commons-text", version.ref = "commons_text" } commons_text = { module = "org.apache.commons:commons-text", version.ref = "commons_text" }
guava = { module = "com.google.guava:guava", version.ref = "guava" } guava = { module = "com.google.guava:guava", version.ref = "guava" }
junit = { module = "junit:junit", version.ref = "junit" } junit = { module = "junit:junit", version.ref = "junit" }
proguard = { module = "com.guardsquare:proguard-gradle", version.ref = "proguard" } r8 = { module = "com.android.tools:r8", version.ref = "r8" }
smali = { module = "com.android.tools.smali:smali", version.ref = "smali" } smali = { module = "com.android.tools.smali:smali", version.ref = "smali" }
xmlpull = { module = "xpp3:xpp3", version.ref = "xmlpull" } xmlpull = { module = "xpp3:xpp3", version.ref = "xmlpull" }
xmlunit = { module = "org.xmlunit:xmlunit-legacy", version.ref = "xmlunit" } xmlunit = { module = "org.xmlunit:xmlunit-legacy", version.ref = "xmlunit" }
[plugins]
shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" }