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
JavaFX Proguard Obfuscation
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With