JavaPackager is a hybrid plugin for Maven and Gradle which provides an easy way to package Java applications in native Windows, Mac OS X or GNU/Linux executables, and generate installers for them.
SNAPSHOT version is not released to Maven Central, so you have to install it manually.
It was born while teaching to my students how to build and distribute their Java apps, and after seeing that a chain of several plugins was needed to achieve this task, I decided to develop a plugin 💍 to govern them all.
Add the following plugin
tag to your pom.xml
:
<plugin>
<groupId>io.github.fvarrui</groupId>
<artifactId>javapackager</artifactId>
<version>1.6.6</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>package</goal>
</goals>
<configuration>
<!-- mandatory -->
<mainClass>path.to.your.mainClass</mainClass>
<!-- optional -->
<bundleJre>true|false</bundleJre>
<generateInstaller>true|false</generateInstaller>
<administratorRequired>true|false</administratorRequired>
<platform>auto|linux|mac|windows</platform>
<additionalResources>
<additionalResource>file path</additionalResource>
<additionalResource>folder path</additionalResource>
<additionalResource>...</additionalResource>
</additionalResources>
<linuxConfig>...</linuxConfig>
<macConfig>...</macConfig>
<winConfig>...</winConfig>
[...]
</configuration>
</execution>
</executions>
</plugin>
See Maven plugin configuration samples to know more.
And execute the next command in project's root folder:
mvn package
Apply JavaPackager plugin in build.gradle
using legacy mode (because at the moment it's only available in Maven Central repository):
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'io.github.fvarrui:javapackager:1.6.6'
}
}
apply plugin: 'io.github.fvarrui.javapackager.plugin'
Create your packaging task:
task packageMyApp(type: io.github.fvarrui.javapackager.gradle.PackageTask, dependsOn: build) {
// mandatory
mainClass = 'path.to.your.mainClass'
// optional
bundleJre = true|false
generateInstaller = true|false
administratorRequired = true|false
platform = auto|linux|mac|windows
additionalResources = [ file('file path'), file('folder path'), ... ]
linuxConfig {
...
}
macConfig {
...
}
winConfig {
...
}
...
}
See Gradle plugin configuration samples to know more.
And execute the next command in project's root folder:
gradle packageMyApp
By default it will generate next artifacts in ${outputDirectory}
folder:
Artifact | Description | Platform | Requires |
---|---|---|---|
${name} |
Directory with native application and other assets. | All | |
${name}-${version}-runnable.jar |
Runnable JAR file. | All | |
${name}_${version}.deb |
DEB package file. | All | |
${name}_${version}.rpm |
RPM package file. | All | |
${name}_${version}.exe |
Setup file. | Windows | Inno Setup |
${name}_${version}.msi |
MSI installer file. | Windows | WiX Toolset |
${name}_${version}.msm |
MSI merge module file. | Windows | WiX Toolset |
${name}_${version}.dmg |
Disk image file (uses hdiutil). | Mac OS | |
${name}_${version}.pkg |
PKG installer file (uses pkgbuild). | Mac OS | |
${name}-${version}-${platform}.zip |
Zipball containing generated directory ${name} . |
All | |
${name}-${version}-${platform}.tar.gz |
Compressed tarball containing generated directory ${name} . |
All | |
assets |
Directory with all intermediate files generated by JavaPackager. | All |
Inno Setup and WiX Toolset installation guide.
Property | Mandatory | Default value | Description |
---|---|---|---|
additionalModulePaths |
❌ | [] |
Additional module paths for jdeps . |
additionalModules |
❌ | [] |
Additional modules to the ones identified by jdeps or the specified with modules property. |
additionalResources |
❌ | [] |
Additional files and folders to include in the bundled app. |
administratorRequired |
❌ | false |
App will run as administrator (with elevated privileges). |
assetsDir |
❌ | ${basedir}/assets or ${projectdir}/assets |
Assets location (icons and custom Velocity templates). |
bundleJre |
❌ | false |
Embeds a customized JRE with the app. |
classpath |
❌ | List of additional paths to JVM classpath, separated with ; (recommended) or : . |
|
copyDependencies |
❌ | true |
Bundles all dependencies (JAR files) with the app. |
createTarball |
❌ | false |
Bundles app folder in tarball. |
createZipball |
❌ | false |
Bundles app folder in zipball. |
customizedJre |
❌ | true |
Generates a customized JRE, including only identified or specified modules. Otherwise, all modules will be included. |
description |
❌ | ${project.description} or ${displayName} |
Project description. |
displayName |
❌ | ${project.name} or ${name} |
App name to show. |
envPath |
❌ | Defines PATH environment variable in GNU/Linux and Mac OS X startup scripts. | |
extra |
❌ | Map with extra properties to be used in customized Velocity templates, accesible through $info.extra variable. |
|
forceInstaller |
❌ | false |
If true , skips operating system check when generating installers. |
generateInstaller |
❌ | true |
Generates an installer for the app. |
jdkPath |
❌ | ${java.home} |
JDK used to generate a customized JRE. It allows to bundle customized JREs for different platforms. |
jreDirectoryName |
❌ | "jre" |
Bundled JRE directory name. |
jreMinVersion |
❌ | JRE minimum version. If an appropriate version cannot be found display error message. Disabled if a JRE is bundled. | |
jrePath |
❌ | "" |
Path to JRE folder. If specified, it will bundle this JRE with the app, and won't generate a customized JRE. For Java 8 version or least. |
licenseFile |
❌ | ${project.licenses[0].url} or ${basedir}/LICENSE or ${projectdir}/LICENSE |
Path to project license file. |
mainClass |
✔️ | ${exec.mainClass} |
Full path to your app main class. |
manifest |
❌ | Allows adding additional entries to MANIFEST.MF file. | |
modules |
❌ | [] |
Modules to customize the bundled JRE. Don't use jdeps to get module dependencies. |
name |
❌ | ${project.name} or ${project.artifactId} |
App name. |
organizationName |
❌ | ${project.organization.name} or "ACME" |
Organization name. |
organizationUrl |
❌ | ${project.organization.url} |
Organization website URL. |
organizationEmail |
❌ | Organization email. | |
outputDirectory |
❌ | ${project.build.directory} or ${project.builddir} |
Output directory (where the artifacts will be generated). |
packagingJdk |
❌ | ${java.home} |
JDK used in the execution of jlink and other JDK tools. |
platform |
❌ | auto |
Defines the target platform, which could be different to the execution platform. Possible values: auto , mac , linux , windows . Use auto for using execution platform as target. |
runnableJar |
❌ | Defines your own JAR file to be bundled. If it's ommited, the plugin packages your code in a runnable JAR and bundle it with the app. | |
scripts |
❌ | Specify bootstrap script. Pre and post-install scripts comming soon! | |
url |
❌ | App website URL. | |
useResourcesAsWorkingDir |
❌ | true |
Uses app resources folder as default working directory (always true on Mac OS). |
version |
❌ | ${project.version} |
App version. |
vmArgs |
❌ | [] |
VM arguments. |
Some default values depends on the used building tool.
Platform specific properties
Property | Mandatory | Default | Description |
---|---|---|---|
linuxConfig |
❌ | GNU/Linux specific properties. | |
macConfig |
❌ | Mac OS X specific properties. | |
winConfig |
❌ | Windows specific properties. |
⚠️ Be careful when using theplatform
property if your project uses platform dependent libraries, so the libraries of the current platform will be copied, not those required for the target platform. You can solve this problem usingclassifiers
.
Some assets, such as application icons and templates, could be placed in ${assetsDir}
folder organized by platform.
${assetsDir}/
├── linux/
├── mac/
└── windows/
If icons are located in ${assetsDir}
folder, it would not be necessary to use icon properties:
${assetsDir}/
├── linux/
│ └── ${name}.png # on GNU/Linux it has to be a PNG file
├── mac/
│ └── ${name}.icns # on Mac OS X it has to be a ICNS file
└── windows/
└── ${name}.ico # on Windows it has to be a ICO file
⚠️ If icon is not specified , it will use an icon by default for all platforms.
Velocity templates (.vtl
files) are used to generate some artifacts which have to be bundled with the app or needed to generate other artifacts.
It is possible to use your own customized templates. You just have to put one of the following templates in the ${assetsDir}
folder organized by platform, and the plugin will use these templates instead of default ones:
${assetsDir}/
├── linux/
| ├── assembly.xml.vtl # maven-assembly-plugin template to generate ZIP/TGZ bundles for GNU/Linux
| ├── control.vtl # DEB control template
| ├── desktop.vtl # Desktop template
│ └── startup.sh.vtl # Startup script template
├── mac/
| ├── assembly.xml.vtl # maven-assembly-plugin template to generate ZIP/TGZ bundles for Mac OS X
| ├── customize-dmg.applescript.vtl # DMG customization Applescript template
| ├── Info.plist.vtl # Info.plist template
│ └── startup.vtl # Startup script template
└── windows/
├── assembly.xml.vtl # maven-assembly-plugin template to generate ZIP/TGZ bundles for Windows
├── exe.manifest.vtl # exe.manifest template
├── ini.vtl # WinRun4J INI template
├── iss.vtl # Inno Setup Script template
├── msm.wxs.vtl # WiX Toolset WXS template to generate Merge Module
├── startup.vbs.vtl # Startup script template (VB Script)
└── wxs.vtl # WiX Toolset WXS template to generate MSI
An object called info
of type PackagerSettings
is passed to all templates with all plugin properties.
You can use default templates as examples to create your own templates, and use the extra
map property to add your own properties in the plugin settings to use in your custom templates (e.g. ${info.extra["myProperty"]}
).
When you build your app, all configuration details are hardcoded into the executable and cannot be changed without recreating it or hacking with a resource editor. JavaPackager introduces a feature that allows to pass additional JVM options at runtime from an .l4j.ini
file (like Launch4j does, but available for all platforms in the same way). So, you can specify these options in the packager's configuration (packaging time), in INI file (runtime) or in both.
The INI file's name must correspond to ${name}.l4j.ini
and it has to be located next to the executable on Windows and GNU/Linux, and in Resources
folder on Mac OS X.
The options should be separated with spaces or new lines:
# Additional JVM options
-Dswing.aatext=true
-Dsomevar="%SOMEVAR%"
-Xms16m
An VM argument per line.
And then bundle this file with your app:
<additionalResources>
<additionalResource>${name}.l4j.ini</additionalResource>
</additionalResources>
Last property copies
${name}.l4j.ini
file next to the EXE/binary on Windows/Linux, and inResources
folder on MacOS.
Useful to try SNAPSHOT versions.
Execute next commands in BASH (GNU/Linux or macOS) or CMD (Windows):
- Download source code and change to the project directory:
git clone https://github.com/fvarrui/JavaPackager.git [--branch x]
cd JavaPackager
where
x
is branch name (e.g.devel
)
- Compile, package and install the plugin in your local repository (ommit
./
on Windows):
./gradlew publishToMavenLocal
Run next command (ommit ./
on Windows):
./gradlew -Prelease uploadArchives closeAndReleaseRepository
Related guide.
Only the first time, run next command:
./gradlew login
And then, run (ommit ./
on Windows):
./gradlew publishPlugins
Related guide.
Check the TO-DO list to know the features we plan to add to JavaPackager.