With Java 14, we will get back a tool to create native installation archives for our Java applications. While Java on the client unfortunately is not considered a hot topic these days, it is very important that the current gap is closed - again. There used to be a commandline tool called
javafxpackager which was later renamed
javapackager and even later removed from the JDK. java(fx)packager performed tasks related to packaging and signing Java and JavaFX applications, so when JavaFX was unbundled from the JDK, it sort of made sense to temporarily remove related tools as well. With
jpackage a fresh, re-thought and more general implementation returns.
Java 14 will be released in March 2020 so what is available today is preliminary (early access). Further, jpackage is considered an incubator feature, so even what we will see in March may change over time.
Installing Java on a Mac is a matter of a few minutes. After downloading and unzipping the tarball just move the base directory to
cd ~/Downloads tar xzf openjdk-14-ea+28_osx-x64_bin.tar.gz sudo mv jdk-14.jdk /Library/Java/JavaVirtualMachines
Did you know you can list your installed Java versions with
/usr/libexec/java_home -V? By default the Mac will use the latest version, so after this installation
java -version will print something like openjdk version "14-ea" 2020-03-17. Still, typing
jpackage will produce a command not found. To fix this, you could add
PATH. For now I suggest to just use the absolute path when invoking the tool, because you will pass quite a few arguments, so creating a small shell script will make your life much easier.
Take a look at this one:
#!/bin/sh JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-14.jdk/Contents/Home BASEDIR=/Users/thomas/Entwicklung/Bitbucket/clip4moni VERSION=`sed -n -e 's/.*VERSION = \"\(.*\)\".*/\1/p' < $BASEDIR/src/main/classes/com/thomaskuenneth/clip4moni/Clip4Moni.java` $JAVA_HOME/bin/jpackage --name Clip4Moni --icon $BASEDIR/artwork/Clip4Moni.icns --app-version $VERSION --type app-image --module-path $BASEDIR/build/modules -m main/com.thomaskuenneth.clip4moni.Clip4Moni
I use it to create the application bundle for my app Clip4Moni, a small text snippet tool that resides in the system tray (Windows, Linux) or menu bar (on a Mac). It is based upon Java modules. While
jpackage can work with plain jars as well, I strongly suggest bringing your code to recent Java versions. So many nice features have gone into the language, it is more than a pity not to use them. Now, let's go through the script, starting with the last line.
--name is the name of the application.
--icon references the icon file.
--type defines what kind of archive shall be created, in this case it is just the app bundle.
--module-path specifies where the module files are located.
-m identifies the main class.
--app-version sets, well, the version number of the app, for example
1.3.3. If you look at my script I do a funny looking
sed call. Let me explain. I define the app version as a
String constant. So I go to the source file in which the definition resides, and read the version number. This is the input:
... public static final String VERSION = "1.3.3"; ...
jpackage is easy to use. Although it is still in preview it worked flawlessly. There is just a minor thing I noticed. Part of a Mac app bundle is a file called
info.plist that contains important information about the app. It is created by jpackage. Currently it contains these lines:
<!-- See https://developer.apple.com/app-store/categories/ for list of AppStore categories --> <key>LSApplicationCategoryType</key> <string>Unknown</string>
The underlying idea seems to be that developer edits the file. But using the syntax in my script, it is created on the fly. One solution might be to edit it after the invocation of
jpackage. But this may not work if you sign your app (which can be done through
jpackage). Another thing I would love to see is the ability to bring in additional entries. My app resides in the menu bar so I would like to hide the Dock icon. This is done as follows:
It would be cool to specify such entries at the commandline. There may already be solutions to this, so if you, dear reader, know how to do this, please tell me in the comments.