JavaFX Proguard Obfuscation

后端 未结 1 1278
北荒
北荒 2021-01-12 08:31

I\'m struggling with obfuscation of JavaFX application. Using this project as a base:

https://github.com/openjfx/samples/tree/master/IDE/IntelliJ/Non-Modular/Gradle

相关标签:
1条回答
  • 2021-01-12 09:15

    To get Proguard working with Java 11 we need:

    • The latest Proguard beta version, for Gradle in this case.

    • Modify the build gradle file to include the proguard task.

    • Add a proguard config file including the required changes for Java 11.

    Build.gradle

    Starting from the HelloFX sample, the build will be modified to:

    // 1. Include proguard dependency
    buildscript {
        repositories {
            jcenter()
        }
        dependencies {
            classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2'
        }
    }
    
    plugins {
      id 'application'
      id 'org.openjfx.javafxplugin' version '0.0.7'
    }
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
    }
    
    javafx {
        modules = [ 'javafx.controls', 'javafx.fxml' ]
    }
    
    mainClassName = 'org.openjfx.MainApp'
    

    Instead of just adding the proguard task, I'll add a few more tasks to replace the default build/classes with the proguarded ones. This helps inspecting the result.

    // 2. Add tasks
    
    // 2.1 Clean buildDir before running proguard
    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")
    }
    

    Finally, add a task to run the application with the proguarded classes.

    // 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 = 'a.a.b' // <-- this name will depend on the proguard result
    }
    

    proguard.conf

    The key on how to get it working with Java 9+ can be found in this comment. If you download the source code, and check the examples folder, there are different configuration files.

    Checking applications.pro, you can read:

    # Before Java 9, the runtime classes were packaged in a single jar file.
    #-libraryjars <java.home>/lib/rt.jar
    
    # As of Java 9, the runtime classes are packaged in modular jmod files.
    -libraryjars <java.home>/jmods/java.base.jmod(!**.jar;!module-info.class)
    

    So that's it!

    This is the config file I've used with the HelloFX sample (of course it could be extended with other many options):

    -dontoptimize
    -dontshrink
    
    #Java 9+
    -libraryjars <java.home>/jmods/java.base.jmod(!**.jar;!module-info.class)
    
    # Save meta-data for stack traces
    -printmapping out.map
    -renamesourcefileattribute SourceFile
    -keepattributes SourceFile,LineNumberTable
    
    # Rename FXML files together with related views
    -adaptresourcefilenames **.fxml,**.png,**.css,**.properties
    -adaptresourcefilecontents **.fxml
    -adaptclassstrings
    
    # Keep all annotations and meta-data
    -keepattributes *Annotation*,Signature,EnclosingMethod
    
    # Keep entry-point class
    -keep class org.openfjx.MainApp {
      public static void main(java.lang.String[]);
    }
    
    # Keep names of fields marked with @FXML, @Inject and @PostConstruct attributes
    -keepclassmembers class * {
      @javafx.fxml.FXML *;
      @javax.inject.Inject *;
      @javax.annotation.PostConstruct *;
    }
    

    Result

    If you run ./gradlew proguard, you will get the output.jar.

    If you run ./gradlew unpackProguardOutput, you can see the result in build/classes:

    main
    |____a
    | |____a
    | | |____styles.css
    | | |____scene.fxml
    | | |____b.class
    | | |____a.class
    

    In this case, b.class is the main class, so this is why in the runProguard task I've set main = 'a.a.b'. This will depend on each case, obviously.

    Also, you can check the out.map:

    org.openjfx.FXMLController -> a.a.a:
        javafx.scene.control.Label label -> label
        10:10:void <init>() -> <init>
        17:20:void initialize(java.net.URL,java.util.ResourceBundle) -> initialize
    org.openjfx.MainApp -> a.a.b:
        11:11:void <init>() -> <init>
        15:23:void start(javafx.stage.Stage) -> start
        26:27:void main(java.lang.String[]) -> a
    

    Finally, ./gradlew runProguard will successfully run the application.

    0 讨论(0)
提交回复
热议问题