JavaFX Proguard混淆

7
我正在为JavaFX应用程序的混淆而苦苦挣扎。使用此项目作为基础:

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

Proguard会抛出以下错误:
java.io.IOException: Can't write [Path\infile.jar] (Can't read [Path\outfile.jar] (Duplicate jar entry [a.class]))

Proguard配置文件: -dontoptimize -dontshrink

-libraryjars 'E:\Prog\jdk-11.0.2\jmods'
-libraryjars 'E:\Prog\javafx-sdk\lib'

# Save meta-data for stack traces
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable

# Rename FXML files together with related views
-adaptresourcefilenames **.fxml,**.png,**.css
-adaptresourcefilecontents **.fxml
-adaptclassstrings

# Keep all annotations and meta-data
-keepattributes *Annotation*,Signature,EnclosingMethod

# Keep entry-point class
-keep classpackage.App {
    public static void main(java.lang.String[]);
}

# Keep all classes inside application
-keep,allowobfuscation class package.** {
}

# Keep names of fields marked with @FXML attribute
-keepclassmembers class * {
    @javafx.fxml.FXML *;
}

有人有JavaFX混淆的经验吗?

1个回答

10

要使Proguard与Java 11配合使用,我们需要:

  • 最新的Proguard beta版本,在这种情况下是为Gradle准备的。

  • 修改build.gradle文件以包括proguard任务。

  • 添加一个proguard配置文件,包括Java 11所需的更改。

Build.gradle

从HelloFX 示例开始,将修改构建为:

// 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'

我不仅会添加proguard任务,还会添加几个任务来用proguarded的代码替换默认的build/classes。这有助于检查结果。

// 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")
}

最后,添加一个任务来运行经过混淆处理的类的应用程序。

// 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

如何让它与Java 9+兼容的关键在于这个评论中。如果您下载源代码并检查示例文件夹,则会找到不同的配置文件。

检查applications.pro,您可以阅读:

# 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)

就是这样啦!

这是我用于HelloFX示例的配置文件(当然,它也可以用其他许多选项进行扩展):

-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 *;
}

结果

如果你运行./gradlew proguard,你会得到output.jar

如果你运行./gradlew unpackProguardOutput,你可以在build/classes中看到结果:

main
|____a
| |____a
| | |____styles.css
| | |____scene.fxml
| | |____b.class
| | |____a.class
在这种情况下,b.class是主类,所以在runProguard任务中,我已经设置了main = 'a.a.b'。这显然取决于每个情况。

另外,您可以查看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

最后,./gradlew runProguard将成功运行应用程序。


太棒了,谢谢你,它(部分地)起作用了。有一件事没有起作用,就是(!**.jar;!module-info.class) - 它会抛出“找不到文件”异常。而且我还收到了Gradle警告,例如:无法找到引用的方法'void setText(java.lang.String)'和无法找到引用的方法'javafx.scene.control.TableView getTableView()',所以库可能存在问题。 - orzel
好的,我已经修改了任务配置,因为我需要一个fatjar,结果它以相同的错误结束(重复的jar条目[a.class]),所以我认为现在是依赖关系的问题,而不是JavaFX和/或Java11的问题... 有没有什么想法如何解决它?(它可以很好地混淆常规的jar文件) - orzel
我刚刚拿了hellofx示例,并按照发布的方式进行了修改。你可以先尝试一下吗?一旦它能够正常工作,就开始进行修改。 - José Pereda
我刚刚修改了Proguard的输入,以生成fatjar:injars "${buildDir}/libs/out.jar",常规的jar混淆也很好。 - orzel
1
如果您在命令行上运行Proguard(proguard.sh @proguard.conf),它将无法正常工作。会出现“找不到引用类”的错误。请问您该如何解决这个问题? - Patrick
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接