Introduction
jpackage
is a new tool with JDK 14 that generates native system installers for distributing your appliction.
It will create .msi
for Windows, .dmg
for Mac, and .deb
or .rpm
for Linux distrubtions. This is ideal for GUI applications.
This guide will demonstrate how to use this tool to create system native installers for your applications.
jlink vs jpackage
jlink
was introduced in Java 9 and jpackage
builds on top of jlink
and came with Java 14.
jpackage
uses jlink
under the hood.
To understand jlink
better, check out my tutorial How to Create Java Runtime Images with jlink.
You can manually perform the jlink step before running jpackage, otherwise jpackage automatically invokes jlink during the process
jlink
generates the executable (e.g. .exe
, .app
), but jpackage
creates the installer for the executable (e.g. .msi
, .dmg
, .deb
, .rpm
).
Packaging non-modular apps
Though jpackage
only supports JDK11+, you can still build traditional non-modular apps.
This is the simplest example to demonstrate how jpackage
works.
You take an executable jar file, in this case myapp.jar
, and specify the class inside that you want to execute. The input directory tells jpackage
where to look for the JAR.
# input dir is where the main jar resides (`target/` typically with Maven projects)
# main jar path should be relative to the input dir
# main class is the executable class with a main() method
jpackage -i ./target/ --main-class com.devdungeon.Main --main-jar myapp.jar
This generates a single standalone .exe
file that will install your application.
Packaging modular apps
With a modular app, you have a couple options. You could use jlink
to build the runtime image first. You could include your application and dependencies in this runtime, or you can use jpackage
to
Automatically generate a runtime image
jpackage
will automatically run jlink
and generate a runtime with the modules needed. There is no need to run jlink
yourself unless you want something very custom. This example will generate the runtime and installer package with your module.
jpackage \
--module-path .;target/my.jar \
--module mymodule/com.devdungeon.Main \
--add-modules java.desktop,mymodule \
Use a custom runtime image
If you already have a runtime image with the modules in it, you can simply tell jpackage
to use the runtime image you want with the --runtime-image
option.
Specify the main class with the --module
option.
To learn how to create a custom runtime, check out my tutorial How to Create Java Runtime Images with jlink.
Here is an example of packaging an existing runtime to run a specific class.
jpackage \
--runtime-image my-custom-jre-with-app \
--module mymodule/com.devdungeon.Main
Add a startup splash screen
# APPDIR resolves to app final install dir
--java-options '-splash:$APPDIR/splash.png'
Associating file extensions with your app
--file-associations
For example, if I wanted to create a file extension .dano
for my application.
You can specify the following things for your custom file type:
- the file icon
- the mime-type you want to use
- the file extension
Common Windows options
Here are a few useful options when generating a Windows installer.
Let users choose the install directory
--win-dir-chooser
Creating a console launcher
# Create a console launcher for CLI applications
--win-console
Creating Start menu entry
# Add app to start menu
--win-menu
# defaults to "Unknown" folder without --win-menu-group
--win-menu-group <name>
# Create desktop shortcut
--win-shortcut
Install for user instead of system-wide
--win-per-user-install
Conclusion
After reading this guide, you should understand how to use jpackage
to generate a system-native installer for a Java application whether it is module or non-modular.