Embedded JRE for Windows
by Sasha Elaine Fox
Deploying Java Desktop Apps on Windows
So you’ve written your shiny new Java app, and now it’s time to deploy on Windows.
Thanks to Java’s platform independence, all we need to do is bundle up our app in
a .jar
and, assuming the end-user has the Java Runtime Environment (JRE) installed,
we are good to go right?
Unfortunately there is no guarantee that the end user will have the JRE installed, nor are we guaranteed that the correct version will be installed if the JRE is present.
We are left with two options: either install the required version of the JRE on the host system, or ship a version of the JRE embedded into our app. If we go with the latter option, we will need a way to make sure that our app knows how to used the embedded JRE.
There’s also the question of Executable files. Windows users are usually expecting (for better or worse) apps to be shipped as self-contained installers and exe files.
Launch4j
Installation and Set-Up
Unfortunately launch4j is not available via chocolatey and needs to be installed from the Launch4j Sourceforge.
By default launch4j is not added to the system Path. To make it accessible via
the command line you’ll need to add the launch4j.exe
and launch4jc.exe
(the command line version of launch4j) folder location to the Path. One
way to done this is by modifying your Powershell profile, Microsoft.PowerShell_profile.ps1
and adding the following line.
# Add Launch4J to the PATH.
$env:Path += "C:\Program Files (x86)\Launch4j";
Once launch4j is accessible via the command line, a GUI interface can be launched as follows:
launch4j
This GUI is designed to aid in generating config files. However, config files can ben generated and edited manually if desired.
Once an appropriate config file has been generated the executable wrapper is generated using launch4jc as follows.
launch4jc config.xml
System Wide Java Installation
Launch4J can enforce the use of a system-wide JRE/JDK installation to run an app. Launch4J will build a self-contained executable that will check to see if an appropriate JRE is present on the host system and if one is not found, prevent the program from starting (along with directing the user to a place to download a JRE).
Let’s assume we have a project with following structure.
C:.
│ config.xml
│ ProjectIcon.ico
│ ProjectJar.jar
<?xml version="1.0" encoding="UTF-8"?>
<launch4jConfig>
<dontWrapJar>false</dontWrapJar>
<headerType>gui</headerType>
<jar>ProjectJar.jar</jar>
<outfile>bin\ProjectExe.exe</outfile>
<errTitle></errTitle>
<cmdLine></cmdLine>
<chdir>.</chdir>
<priority>normal</priority>
<downloadUrl>http://java.com/download</downloadUrl>
<supportUrl></supportUrl>
<stayAlive>false</stayAlive>
<restartOnCrash>false</restartOnCrash>
<manifest></manifest>
<icon>$ProjectIcon.ico</icon>
<jre>
<path></path>
<bundledJre64Bit>false</bundledJre64Bit>
<bundledJreAsFallback>false</bundledJreAsFallback>
<minVersion>1.8</minVersion>
<maxVersion></maxVersion>
<jdkPreference>preferJre</jdkPreference>
<runtimeBits>64/32</runtimeBits>
</jre>
</launch4jConfig>
Some things to note about the config:
<jar>
: Path to our JAR file, relative toconfig.xml
.<bundledJre64Bit>
: Should we use an embedded 64-bit version of the JRE?<bundledJreAsFallback>
: If we can’t install a system-wide JRE should we us an embedded one?<jdkPreference>
: Should we use a JRE, JDK, or both?<minVersion>
: Minimal valid JRE version. (can be left blank)<maxVersion>
: Maximum valid JRE version. (can be left blank)<runtimeBits>
: Can we use 64 bits, 32 bits, or both?
When we run launch4jc config.xml
our project will look as follows:
C:.
│ config.xml
│ ProjectIcon.ico
│ ProjectJar.jar
├───bin
│ │ ProjectExe.exe
Running ProjectExe.exe
will run our .jar file using the system-wide installation
of Java.
Embedded JRE
Lauch4J can also included a self-contained version of the JRE. Launch4J will produce an executable that contains a JRE that will be used whenever our app is run.
First we’ll need to get an embeddable JRE from here.
Let’s assume we have a project structured as follows. Note that jre1.8.0_191
is the root directory of the embedded JRE that will be included with our project.
C:.
│ config.xml
│ ProjectIcon.ico
│ ProjectJar.jar
├───bin
│ │ ProjectExe.exe
| ├───jre1.8.0_191
| │ ├───bin
| │ └───lib
<?xml version="1.0" encoding="UTF-8"?>
<launch4jConfig>
<dontWrapJar>false</dontWrapJar>
<headerType>gui</headerType>
<jar>ProjectJar.jar</jar>
<outfile>bin\ProjectExe.exe</outfile>
<errTitle></errTitle>
<cmdLine></cmdLine>
<chdir>.</chdir>
<priority>normal</priority>
<downloadUrl>http://java.com/download</downloadUrl>
<supportUrl></supportUrl>
<stayAlive>false</stayAlive>
<restartOnCrash>false</restartOnCrash>
<manifest></manifest>
<icon>$ProjectIcon.ico</icon>
<jre>
<path>jre1.8.0_191</path>
<bundledJre64Bit>true</bundledJre64Bit>
<bundledJreAsFallback>false</bundledJreAsFallback>
<minVersion>1.8</minVersion>
<maxVersion></maxVersion>
<jdkPreference>jdkOnly</jdkPreference>
<runtimeBits>64/32</runtimeBits>
</jre>
</launch4jConfig>
Note that the major change is <bundledJre64Bit>
being set to true. This tells
Launch4J that we should use the JRE specified in <path>
instead of a system-wide
JRE installation.
Note that the path to the JRE is relative to where ever the project executable is, ($PROJECT_EXE_DIR in or example) not the jar file, or the chdir path.
tags: java - deployment - windows