Skip to content

how to build a JavaFX application into native binaries with Maven using JLink and JPackage

Notifications You must be signed in to change notification settings

Til7701/javafx-native-image-sample

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

how to build a JavaFX application into native binaries with Maven using JLink and JPackage

.github/workflows/native.yaml

Known Issues

  • XSetErrorHandler() called with a GDK error trap pushed. Don't do that. when running on linux. Seems to be a known issue since 2016: JDK-8156779
  • The application name on Gnome is currently de.holube.demo.MyApplication. This is a known issue since 2022: JDK-8287848. There are Workarounds available on StackOverflow. They are not implemented here.

TODOs

  • figure out, why apt does not run installation scripts properly

Native Package Example for JavaFX Application

Everyone always talks about how to code fancy stuff in all kinds of programming languages, but never about how to deploy what you made in a user-friendly way. This repository wants to change that. It is an example of how to package a JavaFX application into native binaries. Specifically, a deb package for Linux and a setup.exe for Windows users. It was a wild ride of trial and error :)

In the following chapters I will explain how this is done and what you have to change, if you want to use this process for you own application.

The JavaFX application

The folder src/ contains a normal, modular JavaFX application. For this example it could be reduced a little bit more, however I think these two additions might be interesting.

Firstly, JavaFX provides preloaders. Before the application is started, the preloader is run. You can set the preloader by calling System.setProperty("javafx.preloader", "de.holube.demo.MyPreloader"); before you call launch() for the application. The class to provide should extend Preloader. I don't know whether this is best practice, but it is nice to know.

Secondly, in MyApplication is a method called setupIcons. This method is called in the start method and sets the icon src/main/resources/icons/icon.png in the application bar and taskbar/dock. These icons are not always set automatically. So here they are set manually at runtime.

Maven

The dependencies and build are configured with maven in the pom.xml. So lets break it down.

At the top, there are some properties, used to define versions of dependencies and plugins. Under that are some dependencies. JavaFX is necessary for obvious reasons, but you could remove lombok and the test frameworks. If you remove lombok, you have to de-lombok first. In this project it is only one @RequiredArgsConstructorand the annotation processor for lombok in the maven-compiler-plugin configuration.

Next are the profiles. Here they are used to configure jpackage. So we will cover them in that chapter. In general, profiles provide optional dependencies and configuration for plugins, which can be activated by adding the -P profile-id option to the maven build command.

JLink

JLink builds the application into a native binary and creates a custom JRE, which only contains the classes needed for this application. It is configured via the javafx-maven-plugin and called by the javafx:jlink goal. By adding the following to the plugin configuration, a lot of things are removed. These are not important for the end user.

<configuration>
    <stripDebug>true</stripDebug>
    <compress>1</compress>
    <noHeaderFiles>true</noHeaderFiles>
    <noManPages>true</noManPages>
</configuration>

JPackage

jpackage is a command line tool, which can package the binary built by jlink into a native setup binary. Documentation can be found here.

In this project jpackage is configured by the jpackage-maven-plugin from org.panteleyev. Documentation for the plugin can be found here.

The application can be built with three different targets. A .deb package, a windows setup executable and an app-image for the os you are on. JPackage provides more options, but these are the ones, which are configured here. So lets take a look at each of them.

Also note the resource directory set by <resourceDir>./jpackage</resourceDir>. I will refer to this for the different goals.

DEB Package

Configuration

The maven profile linux-deb adds a bit of configuration to the jpackage-maven-plugin.

<configuration>
    <type>DEB</type>
    <linuxShortcut>true</linuxShortcut>
    <linuxPackageName>fx-demo</linuxPackageName>
    <linuxAppCategory>Utilities</linuxAppCategory>
    <linuxMenuGroup>Utilities</linuxMenuGroup>
</configuration>

This configuration also uses the resource directory.

The icon for the app is automatically PublicDemoName.png due to the name set in the common plugin configuration.

DEB packages have some scripts, which are called automatically by dpkg. Here two of them are overridden to add some functionality. The scripts are pretty self-explanatory. Documentation on these scripts in general can be found here.

Building the package

You can build the package by running:

mvn -P jpackage -P linux-deb clean compile javafx:jlink jpackage:jpackage

The package can be found in target/dist/.

Installation

To install this package on your computer, download the .deb file from the latest release and run:

dpkg -i fx-demo_amd64.deb

Note: In our testing, installing via apt did not work properly. So you should use dpkg.

Windows Setup EXE

Configuration

The maven profile windows-exe adds a bit of configuration to the jpackage-maven-plugin.

<configuration>
    <type>EXE</type>
    <winMenu>true</winMenu>
    <winUpgradeUuid>ed0a813c-d868-488d-9c23-1e16f0f4e8f6</winUpgradeUuid>
</configuration>

This configuration also uses the resource directory.

The icon for the app is automatically PublicDemoName.ico due to the name set in the common plugin configuration.

Building the package

You can build the package by running:

mvn -P jpackage -P windows-exe clean compile javafx:jlink jpackage:jpackage

The setup exe can be found in target/dist/.

Installation

To install this package on your computer, download the .exe file from the latest release and run it. It is not signed, so windows will ask you whether you really want to run it. Click "more information" and "Run Anyway". You can now find the application in your list of programs in the start menu.

App Image

This should not be confused with the package format AppImage for linux. This option creates a standalone zip, which has a launcher script and only runs on the operating system it was built for.

Configuration

The maven profile app-image adds a bit of configuration to the jpackage-maven-plugin.

<configuration>
    <type>APP_IMAGE</type>
</configuration>

This configuration also uses the resource directory.

The icon for the app is automatically PublicDemoName.png due to the name set in the common plugin configuration.

Building the package

You can build the package by running:

mvn -P jpackage -P app-image clean compile javafx:jlink jpackage:jpackage

The image can be found in target/dist/.

Installation

To install this package on your computer, download the .exe file from the latest release and run it. It is not signed, so windows will ask you whether you really want to run it. Click "more information" and "Run Anyway". You can now find the application in your list of programs in the start menu.

JAR with dependencies

This builds the project into a jar with dependencies. This is the most well known format for applications written with Java. However, this format is not very user-friendly, since the user needs a JRE installed on their system. The module-info.java file is deleted for this. So the project is no longer a module and you will get the JavaFX warning on startup.

Configuration

The maven profile fat-jar configures, how this project is built into a jar with dependencies. I won't go into detail of how this is done. There are enough tutorials for that.

Building the package

You can build the package by running:

mvn -P fat-jar --batch-mode --update-snapshots clean install package

The jar can be found in target/.

JPackage without JLink

You can use jpackage without jlink in case you cannot make a modular project due to dependencies. Keep in mind, that the results will be larger, as they contain all classes in the JVM.

To do that, replace the jar-jpackage profile with the jlink-jpackage profile and remove the javafx:jlink goal.

Building with GraalVM

To build a native image with GraalVM, just pass the fat jar to GraalVM. However, GraalVM has some problems with reflection and JavaFX is not yet supported. Maybe Gluon is a valid alternative, but they have a priced license in some cases and I could not be bothered to investigate it further.

To build a native image with GraalVM, build the fat jar, setup GraalVM on your system and run: native-image -jar target/fx-demo.jar

Note: The jar has to be built with GraalVM as well.

Further Reading

Thanks to JayPi4c for testing and helping

About

how to build a JavaFX application into native binaries with Maven using JLink and JPackage

Topics

Resources

Stars

Watchers

Forks