java javafx proguard classnotfoundexception fxml
https://www.dropbox.com/s/ot51spvwk6lzo4k/GuardTest.zip?dl=0

ProGuard rompe la aplicación JavaFX



classnotfoundexception fxml (2)

¡He encontrado la solución! El problema es que FXML no puede importar clases que no comiencen con una letra mayúscula. Por lo tanto, uno debe proporcionar una lista propia de los nombres disponibles que ProGuard usa para ofuscar. Esto es hecho por:

-classobfuscationdictionary obfuscationClassNames.txt

Con offuscationClassNames.txt que contiene la lista separada por líneas de nombres de clases disponibles:

A B C D ...

Estoy tratando de ofuscar mi aplicación JavaFX pero falla. El resultado generado no funciona y no entiendo por qué. El archivo jar resultante simplemente falla porque el archivo fxml ya no puede cargar todas las importaciones (ClassNotFoundException).

El flujo de trabajo de implementación:

  1. Crear jar ejecutable (en IntelliJ knwon como artefacto)
  2. Ofuscar ese frasco con ProGuard
  3. Soluciona algunos problemas en ese contenedor que ProGuard no puede hacer

1) La aplicación de ejemplo mínima

La aplicación de ejemplo ''GuardTest'' es un proyecto IntelliJ que consta de 3 clases.

  • sample.Main: contiene el punto de entrada de la aplicación y carga el archivo fxml de la GUI ''sample.fxml''
  • sample.Controller: la clase de controlador para ''sample.fxml''
  • controls.CustomControl: un control javafx simple que hereda de HBox. Esto se usa en ''sample.fxml''

El contenido de ''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) Ofuscación

Ahora uso ProGuard para el archivo jar resultante que se genera a partir del proyecto anterior. Utilizo la siguiente configuración:

-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) Reparar algunas fallas de ProGuard (obvias)

El archivo jar resultante ''Obfuscated.jar'' tiene la siguiente estructura:

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

La clase principal inicia la GUI cargando el archivo ''sample.fxml'' con la siguiente línea:

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

Por eso tengo que mover el archivo ''sample.fxml'' a la carpeta p también para que la línea anterior funcione nuevamente. También soluciono algunos problemas en el archivo fxml donde ProGuard se olvida de cambiar un nombre de clase (ahora ofuscado).

Ahora la estructura se ve así:

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

El archivo sample.fxml ahora se ve así:

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

El problema

Ahora este frasco debería funcionar de nuevo porque todo está bien de nuevo. ¡Pero NO LO HACE! El cargador de fxml no puede cargar CustomControl (ahora denominado / ofuscado ''a.class''). ¿Porqué es eso?

Obtengo el siguiente resultado de error al iniciar el archivo jar (estoy ejecutando Java versión 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 . . .

Configurar el cargador de clases predeterminado en la clase principal con

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

tampoco ayuda.

Archivos de proyecto

Aquí puede encontrar el proyecto de ejemplo (IntelliJ): https://www.dropbox.com/s/ot51spvwk6lzo4k/GuardTest.zip?dl=0

El artefacto de jar generado por IntelliJ se compila para: ./out/artifacts/JavaFXApp/JavaFXApp.jar

El Jar ofuscado se encuentra en: ./out/obfuscated/Obfuscated.jar

El contenedor ofuscado pero fijo (al menos debería serlo) como se describe arriba: ./out/obfuscated/Obfuscated_fixed.jar

Y para mostrar que la declaración de importación en el archivo ''sample.fxml'' causa el problema, eliminé mi control personalizado del archivo fxml y lo guardé en el jar (operativo): ./out/obfuscated/Obfuscated_fixed_work.jar

Lo siento por la larga pregunta. Espero que me ayudes de todos modos :)


Usé los mismos pasos. Puedo ver que las importaciones se actualizan en un archivo fxml, pero su uso no es así.

Obteniendo la excepción:

javafx.fxml.LoadException: MenuBarControl no es un tipo válido.

Pero si veo que las importaciones del archivo fxml están actualizadas, pero no su uso.

< ? import q.A ? > < ? import r.A ? > <VBox fx:id="top"> <MenuBarControl fx:id="menuBarControl"/> </VBox>