ProGuard中断JavaFX应用程序


问题内容

我试图混淆我的JavaFX应用程序,但失败了。生成的结果不起作用,我不明白为什么。最终的jar失败了,因为fxml文件无法再加载所有导入(ClassNotFoundException)。

部署工作流程:

  1. 生成可运行的jar(在IntelliJ知识中作为工件)
  2. 用ProGuard混淆那个罐子
  3. 修复ProGuard无法执行的那个jar中的一些问题

1)最小示例应用

示例应用程序“ GuardTest”是一个IntelliJ项目,由3个类组成。

  • sample.Main:包含应用程序入口点并加载GUI fxml文件“ sample.fxml”
  • sample.Controller:“ sample.fxml”的控制器类
  • controls.CustomControl:从HBox继承的简单javafx控件。在’sample.fxml’中使用

“ sample.fxml”的内容:

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.VBox?>

<?import controls.CustomControl?>

<VBox fx:controller="sample.Controller"
          xmlns:fx="http://javafx.com/fxml">
    <children>
        <CustomControl>
            <children>
                <Button text="Test"></Button>
            </children>
        </CustomControl>
    </children>
</VBox>

2)混淆

现在,我将ProGuard用于由上述项目生成的结果jar文件。我使用以下设置:

-target 8

-injars ./out/artifacts/JavaFXApp/JavaFXApp.jar

-outjars ./out/obfuscated/Obfuscated.jar
-ignorewarnings

-printmapping ./out/obfuscated/proguard.map
-dontusemixedcaseclassnames
-dontshrink
-dontoptimize
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers

#-flattenpackagehierarchy
-repackageclasses 'p'
-allowaccessmodification

-libraryjars "<java.home>/lib/rt.jar"
-libraryjars "<java.home>/lib/javaws.jar"
-libraryjars "<java.home>/lib/ext/jfxrt.jar"

-adaptresourcefilecontents **.fxml,**.properties,META-INF/MANIFEST.MF,images/*.jar,publicCerts.store,production.version

-keepattributes javafx.fxml.FXML,Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod
-keepclassmembers class * {
    @javafx.fxml.FXML *;
}

-keepclassmembernames public class com.javafx.main.Main, com.nywelt.sharkload.application.Main {
    public static void main(java.lang.String[]);
}
-keepclasseswithmembers public class com.javafx.main.Main, com.product.main.EntryFX, net.license.LicenseEntryPoint {
    public *; public static *;
}

3)修复一些(显而易见的)ProGuard故障

生成的jar文件’Obfuscated.jar’具有以下结构:

**Obfuscated.jar**
- META-INF
--> MANIFEST.MF
- p
--> a.class
--> b.class
--> c.class
- sample
--> sample.fxml

主类通过以下行加载“ sample.fxml”文件来启动GUI:

Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));

因此,我还必须将“
sample.fxml”文件移动到文件夹p中,以使上述行再次起作用。我还修复了fXML文件中的一些问题,其中ProGuard忘记了更改(现已模糊化)的类名。

现在,结构如下所示:

**Obfuscated_fixed.jar**
- META-INF
--> MANIFEST.MF
- p
--> a.class
--> b.class
--> c.class
--> sample.fxml

现在,sample.fxml文件如下所示:

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.VBox?>

<?import p.a?>

<VBox fx:controller="p.b"
          xmlns:fx="http://javafx.com/fxml">
    <children>
        <a>
            <children>
                <Button text="Test"></Button>
            </children>
        </a>
    </children>
</VBox>

问题

现在,这个罐子应该真的可以再次工作了,因为一切正常。但事实并非如此!fxml加载程序无法加载CustomControl(现已命名/混淆为“
a.class”)。这是为什么?

启动jar文件时,我得到以下错误输出(我正在运行Java版本1.8.0_40):

E:\Eigene Programme\GuardTest\out\obfuscated>java -jar Obfuscated_fixed.jar
Exception in Application start method
Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at sun.launcher.LauncherHelper$FXHelper.main(Unknown Source)
Caused by: java.lang.RuntimeException: Exception in Application start method
        at com.sun.javafx.application.LauncherImpl.launchApplication1(Unknown So
urce)
        at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$152(
Unknown Source)
        at com.sun.javafx.application.LauncherImpl$$Lambda$49/849460928.run(Unkn
own Source)
        at java.lang.Thread.run(Unknown Source)
Caused by: javafx.fxml.LoadException:
file:/E:/Eigene%20Programme/GuardTest/out/obfuscated/Obfuscated_fixed.jar!/p/sam
ple.fxml

        at javafx.fxml.FXMLLoader.constructLoadException(Unknown Source)
        at javafx.fxml.FXMLLoader.importClass(Unknown Source)
        at javafx.fxml.FXMLLoader.processImport(Unknown Source)
        at javafx.fxml.FXMLLoader.processProcessingInstruction(Unknown Source)
        at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
        at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
        at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
        at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
        at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
        at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
        at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
        at javafx.fxml.FXMLLoader.load(Unknown Source)
        at p.c.start(Main.java:13)
        at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$159
(Unknown Source)
        at com.sun.javafx.application.LauncherImpl$$Lambda$52/663980963.run(Unkn
own Source)
        at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$172(Unknown
 Source)
        at com.sun.javafx.application.PlatformImpl$$Lambda$46/410424423.run(Unkn
own Source)
        at com.sun.javafx.application.PlatformImpl.lambda$null$170(Unknown Sourc
e)
        at com.sun.javafx.application.PlatformImpl$$Lambda$48/1149216748.run(Unk
nown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at com.sun.javafx.application.PlatformImpl.lambda$runLater$171(Unknown S
ource)
        at com.sun.javafx.application.PlatformImpl$$Lambda$47/1963387170.run(Unk
nown Source)
        at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
        at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
        at com.sun.glass.ui.win.WinApplication.lambda$null$145(Unknown Source)
        at com.sun.glass.ui.win.WinApplication$$Lambda$36/237061348.run(Unknown
Source)
        ... 1 more
Caused by: java.lang.ClassNotFoundException
        at javafx.fxml.FXMLLoader.loadType(Unknown Source)
        ... 26 more

E:\Eigene Programme\GuardTest\out\obfuscated>Pause
Drücken Sie eine beliebige Taste . . .

在主类中设置默认的类加载器

FXMLLoader.setDefaultClassLoader(this.getClass().getClassLoader());

也没有帮助。

项目文件

在这里您可以找到示例项目(IntelliJ):https
://www.dropbox.com/s/ot51spvwk6lzo4k/GuardTest.zip
? dl
=0

IntelliJ生成的jar工件被编译为: ./out/ artifacts/ JavaFXApp/JavaFXApp.jar

混淆的Jar位于以下位置: ./out/ obfuscated/ Obfuscated.jar

混淆但固定的(至少应该是)jar,如上所述: ./out/obfuscated/Obfuscated_fixed.jar

并显示“ sample.fxml”文件中的import语句导致了问题,我从fxml文件中删除了自定义控件,并将其保存到(工作)jar中:
./out/obfuscated/Obfuscated_fixed_work.jar

很抱歉,这个问题很长。希望您无论如何都能帮助我:)


问题答案:

我找到了解决方案!问题在于FXML无法导入不以大写字母开头的类。因此,必须提供一份自己的可用名称列表,以供ProGuard进行混淆处理。这是通过以下方式完成的:

-classobfuscationdictionary obfuscationClassNames.txt

使用obfuscationClassNames.txt包含可用类名的行分隔列表:

A
B
C
D
...