Reputation: 750
Introduction
Im developing an app in JavaFx using gradle plugins and packaging it with jPackager, also using the gradle plugins.
The main plugins im using are:
id 'org.openjfx.javafxplugin' version '0.0.8'
id 'org.beryx.runtime' version '1.7.0'
id "com.github.johnrengelman.shadow" version "5.1.0"
My current gradle version is: gradle-5.6.2-all
Problem description
How do I use proguard so the code gets obfuscated and optimized before jPackage do its job?
I can run the proguard tasks, but when I run jPackage, the code doesnt get obfuscated!
Ive found a tutorial (Tutorial) for an older gradle version however im not sure how to mix this with the current plugins. I've tried a few code snippets but they all failed to build and I dont want to clutter this topic with a bunch of non-working code.
My current working build.gradle
// 1. Include proguard dependency
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath 'net.sf.proguard:proguard-gradle:6.2.0'
}
}
plugins {
id 'java'
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.8'
id 'org.beryx.runtime' version '1.7.0'
id "com.github.johnrengelman.shadow" version "5.1.0"
}
dependencies {
compile "org.controlsfx:controlsfx:11.0.0"
compile "eu.hansolo:tilesfx:11.13"
compile "com.jfoenix:jfoenix:9.0.9"
compile "org.apache.httpcomponents:httpclient:4.5.9"
compile "org.json:json:20180813"
compile "mysql:mysql-connector-java:8.0.17"
compile "org.jasypt:jasypt:1.9.3"
compile "com.mchange:c3p0:0.9.5.4"
compile "com.sun.mail:javax.mail:1.6.2"
compile "commons-validator:commons-validator:1.6"
compile 'org.openjfx:javafx-base:11:win'
compile 'org.openjfx:javafx-controls:11:win'
compile 'org.openjfx:javafx-fxml:11:win'
compile 'org.openjfx:javafx-graphics:11:win'
}
repositories {
mavenCentral()
}
javafx {
version = "13"
modules = [ 'javafx.controls','javafx.graphics','javafx.fxml' ]
}
mainClassName = 'Main'
runtime {
options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
jpackage {
jpackageHome = 'C:/Program Files/Java/openjdk-14-jpackage+1-49_windows-x64_bin/'
if(org.gradle.internal.os.OperatingSystem.current().windows) {
installerType = 'msi'
imageOptions = []
installerOptions = ['--win-per-user-install',
'--win-dir-chooser',
'--win-menu',
'--win-shortcut',
'--verbose',
'--description','Test of proguard with jPackage',
'--name', 'Test-ProguardJPackage',
'--vendor','DoesItMatter']
}
}
}
compileJava {
doFirst {
options.compilerArgs = [
'--module-path', classpath.asPath,
'--add-modules', 'javafx.controls,javafx.fxml'
]
}
}
run {
doFirst {
jvmArgs = [
'--module-path', classpath.asPath,
'--add-modules', 'javafx.controls,javafx.fxml'
]
}
}
task cleanClasses(type: Delete) {
delete "${buildDir}/classes/java/main"
delete "${buildDir}/resources/java/main"
}
classes.dependsOn(cleanClasses)
// 2.2 Add proguard task
task proguard(type: proguard.gradle.ProGuardTask, dependsOn: classes) {
injars project.sourceSets.main.output
outjars "${buildDir}/proguard/output.jar"
libraryjars project.sourceSets.main.compileClasspath
configuration 'proguard.conf'
}
// 2.3 Clean after proguard task
task cleanAfterProguard(type: Delete, dependsOn: proguard) {
delete "${buildDir}/classes/java/main"
delete "${buildDir}/resources/java/main"
}
// 2.4 Extract output jar to buildDir
task unpackProguardOutput (type: Copy, dependsOn: cleanAfterProguard) {
from zipTree("${buildDir}/proguard/output.jar")
into file("${buildDir}/classes/java/main")
}
// 3. Create a task to run the app with the proguarded buildDir
task runProguard(type: JavaExec, dependsOn: unpackProguardOutput) {
classpath = sourceSets.main.runtimeClasspath
jvmArgs = ['--module-path', classpath.asPath,
'--add-modules', 'javafx.controls,javafx.fxml' ]
main = 'Main' // <-- this name will depend on the proguard result
}
References
Package a non-modular JavaFX application
Upvotes: 9
Views: 2091
Reputation: 45476
Problem
When you run a Gradle task, you have to take into account the tasks that will be previously executed, based on their dependencies.
In the JavaFX Proguard Obfuscation answer you have linked, you can see that the proguard custom tasks are concatenated between them, and when you run ./gradlew runProguard
, actually you get this order of tasks:
:cleanClasses
:compileJava
:processResources
:classes
:proguard
:cleanAfterProguard
:unpackProguardOutput
:runProguard
If you want to add now there runtime
plugin, for tasks like runtime
or jpackage
, you will get this order:
:cleanClasses
:compileJava
:processResources
:classes
:jar
:startScripts
:installDist
:jre
:runtime
Do you see the problem? There is no call at all to the proguard tasks, because we haven't modified the runtime
task to depend on proguard.
Solution
As you can see, both runtime
and jpackage
depend on the jar of the project. So one easy fix will be hooking up the proguard
task into the jar
task, so we create a jar out of the proguarded classes instead of the original ones.
Something like this in your build should work:
jar.dependsOn(unpackProguardOutput)
However there is an issue with the resources (the proguarded FXML file will be overwritten by the original one), because the original resources are copied again to the jar.
So we can modify the jar task instead:
jar {
dependsOn 'cleanAfterProguard'
manifest {
attributes(
'Main-Class': 'org.openjfx.Launcher'
)
}
from zipTree("${buildDir}/proguard/output.jar")
}
This will be the task order now:
:cleanClasses
:compileJava
:processResources
:classes
:proguard
:cleanAfterProguard
:jar
:startScripts
:installDist
:jre
:runtime
Now running ./gradlew clean runtime
will generate a runtime image based on a proguarded hellofx.jar
. Running build/image/bin/hellofx
should work.
The same applies to jpackage
:
:cleanClasses
:compileJava
:processResources
:classes
:proguard
:cleanAfterProguard
:jar
:startScripts
:installDist
:jre
:jpackageImage
:jpackage
In this pic, you see that the jar included in the hellofx.app contains proguarded classes only.
Upvotes: 1
Reputation: 76809
See the manual, the buildscript
block which provides the dependency looks whole different:
buildscript {
repositories {
flatDir dirs: '/usr/local/java/proguard/lib'
}
dependencies {
classpath ':proguard:'
}
}
While it complains, that it is unable to resolve class proguard.gradle.ProGuardTask
, there likely won't be any proguard.gradle.ProGuardTask
. And dependsOn: 'obfuscatedJar'
is strange, because task myProguardTask
is supposed to obfuscate it.
task myProguardTask(type: proguard.gradle.ProGuardTask) {
...
}
Also make sure, that /usr/local/java/proguard/lib
is even installed eg. with locate proguard
, because for Java it's not being provided by the Android SDK - and so one has to provide it as buildscript
dependency. Then you'll have to write a custom proguard.txt
, based upon all the warnings it throws when obfuscating.
Updating the proguard-gradle
plugin might be another possible option:
dependencies {
classpath 'net.sf.proguard:proguard-gradle:6.2.0'
}
For reference, this would be it's ProGuardTask.java.
Upvotes: 0