Gradle badass-runtime-plugin and ProGuard Gradle Plugin
Asked Answered
C

2

9

How to run proguard before jPackage?

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


Cyrie answered 11/10, 2019 at 15:41 Comment(0)
D
1

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.

Dorey answered 30/10, 2019 at 18:39 Comment(10)
Thanks for the answer, however, I think mine is not working yet because Your answer requires that shadowjar dep. So the Jar{ } is not used. [task ':cleanClasses', task ':compileJava', task ':processResources', task ':classes', task ':shadowJar', task ':startShadowScripts', task ':installShadowDist', task ':jre', task ':jpackageImage', task ':jpackage']Cyrie
Why do you need the shadow plugin in the first place? You are doing an installer. Adapt the build to your needs and remove what is not necessary.Mabellemable
I dont know why I was using the shadow plugin. I removed and its working now : github.com/KenobySky/hellofxCyrie
Going to leave that repo public so it can help others as well! Thanks José :)Cyrie
Great. Better if you remove compileJava, run and the JavaFX dependencies from the build, all of that is taken care of by the JavaFX plugin.Mabellemable
I removed the "compileJava" and "run". But which javafx deps you mean?Cyrie
These: compile “.org.openjfx:...”Mabellemable
Done. Going to commit and push. If you have any other suggestions, let me know. I hope it helps other users!!Cyrie
Hey José, good morning. If you have time, would you check this question? #58768638Cyrie
Seems I broke runProguard after I added HibernateCyrie
G
0

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.

Gargle answered 20/10, 2019 at 9:43 Comment(3)
You didnt properly explain how to write up the task for the javafx build. Also note that Jpackage is ran after the build. So your answer is incomplete.Cyrie
@KenobiShanhow shall I answer this completely, when not having the Java code? When added the proguard task, this will require writing configuration rules, which can only be written when proguard is complaining about missing classes and alike.Gargle
The build.gradle doesnt require the "java code". Note that the question is regarding using proguard with those plugins involved and with proguard involved. The use of proguard is trivial in common java applications, however, those restrictions is whats making people curious about this questionCyrie

© 2022 - 2024 — McMap. All rights reserved.