Deploying JavaFX Applications

Previous
Next

6 Self-Contained Application Packaging

A self-contained application is a wrapper for your JavaFX application, making it independent of what the user might have installed.

6.1 Introduction

JavaFX packaging tools provide built-in support for several formats of self-contained application packages. The basic package is simply a single folder on your hard drive that includes all application resources as well as Java Runtime. It can be redistributed as is, or you can build an installable package (for example, EXE or DMG format).

From the standpoint of process, producing a self-contained application package is very similar to producing a basic JavaFX application package as discussed in Chapter 5, "Packaging Basics," with the following differences:

  • Self-contained application packages can only be built using JDK 7 Update 6 or later. (The standalone JavaFX SDK does not support self-contained applications.)

  • Self-contained application packages must be explicitly requested by passing additional arguments to the <fx:deploy> Ant task or javafxpackager tool.

  • Operating system and tool requirements must be met to be able to build a package in a specific format.

While it is easy to create a basic self-contained application package, tailoring it to achieve the best user experience for a particular distribution method usually requires some effort and a deeper understanding of the topic.

6.2 Pros and Cons of Self-Contained Application Packages

Deciding whether the uses of self-contained application packages is the best way to deploy your application depends on your requirements.

Self-contained application packages have several benefits:

  • They resemble native applications for the target platform, in that users install the application with an installer that is familiar to them and launch it in the usual way.

  • They offer no-hassle compatibility. The version of Java Runtime used by the application is fully controlled by the application developer.

  • Your application is easily deployed on fresh systems with no requirement for Java Runtime to be installed.

  • Deployment occurs with no need for admin permissions when using ZIP or user-level installers.

On the other hand, there are a few caveats:

  • "Download and run" user experience

    Unlike web deployment, the user experience is not about "launch the application from the web." It is more one of "download, install, and run" process, in which the user might need to go through additional steps to get the application launched. For example, the user might have to accept a browser security dialog, or find and launch the application installer from the download folder.

  • Larger download size

    In general, the size of self-contained application packages will be noticeably larger than the size of a standalone application, because a private copy of Java Runtime is included.

  • Package per target platform

    Self-contained application packages are platform specific and can only be produced for the same system that you build on. If you want to deliver self-contained application packages on Windows, Linux and Mac you will have to build your project on all three platforms.

  • Application updates are the responsibility of developer

    Web-deployed Java applications automatically download application updates from the web as soon as they are available. The Java Autoupdate mechanism takes care of updating the Java and JavaFX Runtimes to the latest secure version several times every year. There is no built-in support for this in self-contained applications.

6.3 Basics

Each self-contained application package includes the following:

  • The application code, packaged into a set of JAR files, plus any other application resources (data files, native libraries)

  • A private copy of the Java and JavaFX Runtimes, to be used by this application only

  • A native launcher for the application

  • Metadata, such as icons

Multiple package formats are possible. Built-in support is provided for several types of packages, but you can assemble your own packages by post-processing a self-contained application packaged as a folder, for example if you want to distribute your application as a ZIP file.

6.3.1 Self-Contained Application Structure

The basic form of a self-contained application is a single folder on your hard drive, such as the example in Figure 6-1. When any of the installable packages are installed, the result is a folder with the same content.

Figure 6-1 Example of a Self-Contained Application Package

Surrounding text describes Figure 6-1 .

The internal structure of a self-contained application folder is platform-specific and may change in future. However, the following points are guaranteed:

  • The application package, as defined in Chapter 5, "Packaging Basics,", is included as a folder, preserving the application directory structure.

  • A copy of Java Runtime is included as another folder, and the Java Runtime directory structure is preserved.

Because directory structure is preserved, the application can load external resources using paths relative to the application JAR or java.home system property.


Note:

Only a subset of Java Runtime is included by default. Some optional and rarely used files are excluded to reduce the package size, such as all executables. If you need something that is not included by default, then you need to copy it in as a post-processing step. For installable packages, you can do this from the config script that is executed after populating the self-contained application folder. See Section 6.3.3, "Customization Using Drop-In Resources."


6.3.2 Basic Build

The easiest way to produce a self-contained application is to modify the deployment task. To request creation of all applicable self-contained application packages simply add nativeBundles="all" to the <fx:deploy> task, as shown in Example 6-1.

Example 6-1 Simple Deployment Task to Create All Self-contained Application Packages

<fx:deploy width="${javafx.run.width}" height="${javafx.run.height}"
           nativeBundles="all"
           outdir="${basedir}/${dist.dir}" outfile="${application.title}">
    <fx:application name="${application.title}" mainClass="${javafx.main.class}"/>
    <fx:resources>
        <fx:fileset dir="${basedir}/${dist.dir}" includes="*.jar"/>
    </fx:resources>
    <fx:info title="${application.title}" vendor="${application.vendor}"/>
</fx:deploy>

You can also specify the exact package format you want to produce. Use the value image to produce a basic package, exe to request an EXE installer, dmg to request a DMG installer, and so on. For the full list of attribute values, see the nativeBundles attribute in the <fx:deploy> entry in the Ant Task Reference.

If you have a JavaFX project in Netbeans 7.2, you can add the above snippet as a post-build step by overriding the "-post-jfx-deploy" target, as shown in Example 6-2. Add the following code to the build.xml file in the main project directory.

Example 6-2 Custom build.xml Script to Create Self-contained Application Packages in NetBeans IDE

<target name="-post-jfx-deploy">
       <fx:deploy width="${javafx.run.width}" height="${javafx.run.height}" 
                  nativeBundles="all"
                  outdir="${basedir}/${dist.dir}" outfile="${application.title}">
          <fx:application name="${application.title}" 
                          mainClass="${javafx.main.class}"/>
          <fx:resources>
              <fx:fileset dir="${basedir}/${dist.dir}"
                          includes="*.jar"/>
          </fx:resources>
          <fx:info title="${application.title}" 
                   vendor="${application.vendor}"/>
        </fx:deploy>          
     </target>

You can also produce native packages using the JavaFX Packager tool. self-contained application packages are built by default if you use the -makeall command, or you can request them explicitly using the -native option in the -deploy command. See the javafxpackager command reference.

Example 6-3 shows the use of the -native option with the -deploy command, used to generate all applicable self-contained application packages for the BrickBreaker application. The -deploy command requires a JAR file as input, so it assumes that dist/BrickBreaker.jar has already been built:

Example 6-3 JavaFX Packager Command to Generate Self-Contained Application Packages

javafxpackager -deploy -native -outdir packages -outfile BrickBreaker 
    -srcdir dist -srcfiles BrickBreaker.jar -appclass brickbreaker.Main 
    -name "BrickBreaker" -title "BrickBreaker demo"

6.3.3 Customization Using Drop-In Resources

The packaging tools use several built-in resources to produce a package, such as the application icon or config files. One way to customize the resulting package is to substitute built-in resource with your customized version.

For this you need to:

  • Know what resources are used

  • Drop custom resources into a location where the packaging tool will look for them

The following sections explain how to do this.

6.3.3.1 Preparing Custom Resources

To get more insight into what resources are being used, enable verbose mode by adding the verbose="true" attribute to <fx:deploy>, or pass the -v option to the javafxpackager -deploy command.

Verbose mode does the following:

  • It prints the following items:

    • A list of config resources used for the package you are generating

    • The role of each resource

    • The expected custom resource name

  • It saves a copy of all config files to the temp folder, so you can use and customize it.

Example 6-4 shows sample output, with the important parts highlighted:

Example 6-4 Sample Output in Verbose Mode

Using base JDK at: /Library/Java/JavaVirtualMachines/jdk1.7.0_06.jdk
  Using default package resource [Bundle config file] (add
    package/macosx/Info.plist to the class path to customize)
  Using default package resource [icon] (add package/macosx/DemoApp.icns
      to the class path to customize)
Creating app bundle: /tmp/test/TestPackage/bundles/DemoApp.app
Config files are saved to /var/folders/rd/vg2ywnnx3qj081sc5pn9_
    vqr0000gn/T/build7039970456896502625.fxbundler/macosx. Use them 
    to customize package.

Now you can grab a copy of the config file and tune it to your needs. For example, you can take Info.plist and add localized package names.

Note: It is recommended that you disable verbose mode once you are done with customization or add a custom cleanup action to remove sample config files.

6.3.3.2 Substituting a Built-In Resource

Packaging tools look for customized resources on the classpath before reverting to built-in resource. The Javafx Packager has "." (the current working directory) added to the classpath by default. Hence, to replace the application icon, simply copy your custom icon to ./package/macosx/DemoApp.icns in the directory where javafxpackager is run (typically, the root project directory).

The classpath for JavaFX Ant tasks is defined when task definitions are loaded. You must add an additional path to the lookup before the path ant-javafx.jar.

Example 6-5 shows how to add "." to the classpath. For a more detailed code snippet, see Example 10-1).

Example 6-5 Enabling Resource Customization for JavaFX Ant Tasks

<taskdef resource="com/sun/javafx/tools/ant/antlib.xml"
         uri="javafx:com.sun.javafx.tools.ant"
         classpath=".:path/to/sdk/lib/ant-javafx.jar"/>

If you created a JavaFX project using Netbeans 7.2 or later, then the JavaFX Ant tasks are predefined, and "." is already added to the classpath by default.

Once you provide a customized resource, verbose build output will report that it is used. For example, if you added a custom icon to an application, then the verbose output would report the addition, shown in Example 6-6.

Example 6-6 Verbose Output After Adding a Customized Icon Resource

Using base JDK at: /Library/Java/JavaVirtualMachines/jdk1.7.0_06.jdk
  Using default package resource [Bundle config file] (add
      package/macosx/Info.plist to the class path to customize)
Using custom package resource [icon] (loaded from
    package/macosx/DemoApp.icns on class path)
Creating app bundle: /tmp/test/TestPackage/bundles/DemoApp.app

6.3.4 Customization Options

Many of the existing JavaFX Ant elements are used to customize self-contained application packages. Different sets or parameters are needed for different packages, and the same element might have different roles. Table 6-1 introduces most of the customization options.

Table 6-1 Customization Options with Ant Elements and Attributes

Tag Attribute Details

<fx:application>

id

Identifier of application. Format is platform/package specific. If not specified, then a value will be generated.


version

Application version. Default: 1.0.


name

Short name of the application. Most bundlers use it to create the name of the output package. If not specified, then the name of the main class is used.

<fx:preferences>

shortcut

If set to true, then a desktop shortcut is requested.


menu

If set to true then an entry in the applications menu is requested.


install

If set to false, then a user-level installer is requested. Default behavior depends on the package format. See Table 6-2.

<fx:fileset>

type

Defines the role of files in the process of assembling the self-contained application package. Resources of types jnlp and native are not used for building self-contained application packages. Resources of type license are used as a source of content for a click-through license or a license embedded into the package

<fx:info>

title

Application title.


vendor

Application vendor.


category

Application category. Category names are package-format specific.


license

License type (for example, GPL). As of JavaFX 2.2, this attribute is used only for Linux bundles.


copyright

Short copyright statement.


description

Application description.

<fx:jvmarg>


JVM arguments to be passed to JVM and used to run the application (for example, large heap size).

<fx:property>


Properties to be set in the JVM running the application.


6.3.5 Platform-Specific Customization for Basic Packages

Creation and customization of the basic form of self-contained application packages is a fairly straightforward process, but note the following points:

  • Different icon types are needed for different platforms.

    For example, on Windows, the .ico format is expected, and on Mac it is .icns. No icon is embedded into launcher on Linux.

  • To ensure that the icon is set in runtime, you also need to add it to the application stage. For example, add the following code to to the start() method of your application:

    stage.getIcons().add(new
    Image(this.getClass().getResourceAsStream("app.png")));
  • Consider signing files in output folder if you plan to redistribute them.

    For example, on Windows, the launcher executable can be signed using signtool.exe.

6.3.5.1 Mac OS X

The resulting package on Mac OS X is an "application bundle" (or .app) in the Mac OS "dialect/jargon".

Several config parameters end up in the Info.plist file in the application bundle and need to conform to the rules:

Mac OS X 10.8 introduces Gatekeeper, which prevents execution of untrusted code by default (regardless of whether this code was implemented in Objective-C or Java).

The user can manually enable the application to run, but this is not a perfect user experience. To get optimal user experience, you need to obtain a Developer ID Certificate from Apple and sign the .app folder produced by JavaFX packaging tools, as follows:

   % codesign -s "Developer ID Application" ExampleApp.app

For more details, see the Developer ID and Gatekeeper topic at the Apple Developer site.

6.4 Installable Packages

A self-contained application can be wrapped into a platform-specific installable package to simplify redistribution. JavaFX packaging tools provide built-in support for several formats of installable packages, depending on the availability of third-party tools.

Tuning the user experience for the installation process is specific to the particular installer technology, as described in other sections in this chapter. However, you must decide what type of installer you need. The following considerations that might help with your decision.

  • System-wide or per-user installation?

    System-wide installation results in a package installed into a shared location and can be used by any user on the system. On the other hand it assumes admin permissions and will likely result in additional steps during the installation process, such as an OS prompt to approve elevating installer permissions.

    Per-user installation copies the package into a private user directory and does not require admin permissions. This enables you to show as little dialogs as possible and run the program even if user is not eligible for admin privileges.

    Note that whenever a user- or system-level installable package is requested, the build procedure itself does not require admin permissions.

  • Do you need a click-through license?

    Some installable packages support showing license text before initiating the installation. The installation process starts only after the user accepts the license.

    Think carefully if you really need this, because extra dialogs degrade the user experience.

  • What menu/desktop integration is needed?

    The user should be able to launch your application easily. Therefore, we assume that having a desktop shortcut or adding the application to the list of applications in the menu is required.

Note that the current implementation contains many simplifying assumptions.

For example, installers never ask the user to choose the location to install the package. Developers also have limited control of the installation location—they can only choose system or private user location).

If this is not sufficient for your needs you can try advanced customizations by tuning the config file templates (see Section 6.3.3, "Customization Using Drop-In Resources") or packaging a basic self-contained application and then wrapping it into an installable package on your own.

As of JDK 7u6, the following installable package formats are supported:

Table 6-2 Installable Package Formats

Package format Installation Location(Default mode in bold) Click-Through License Prerequisites

EXE

Per user: %LOCALAPPDATA%

System: %ProgramFiles%

Yes (option)

  • Windows

  • Inno Setup 5 or later

MSI

Per user: %LOCALAPPDATA%

System: %ProgramFiles%

No special support

  • Windows

  • WiX 3.0 or later

DMG

Per user: user's desktop folder

System: /Applications

Yes (option)

  • Mac OS X

RPM

Per user: unsupported

System: /opt

No special support

  • Linux

  • RPMBuild

DEB

Per user: unsupported

System: /opt

No special support

  • Linux

  • Debian packaging tools


6.4.1 EXE Package

As of JavaFX 2.2, in order to generate an EXE package, you must have Inno Setup 5 or later installed and available on the PATH. To validate that it is available, try running iscc.exe from the command line where you launch the build or from your build script.

By default, the generated package:

  • Does not require admin privileges to install

  • Is optimized to have a minimum number of dialogs

  • Must be referenced from programs menu or have desktop shortcut (having both are fine)

  • Is configured so the application launches at the end of installation

Figure 6-2 shows a typical dialog box for a self-contained JavaFX application being installed on Windows.

Figure 6-2 Windows Installation Dialog for a Self-Contained JavaFX Application

Surrounding text describes Figure 6-2 .

Customization tips:

  • If you chose system-wide installation, then the user will need to have admin permissions, and the application will not be launched at the end of installation.

  • A click-through license is supported (an .rtf file is required).

  • The image shown in the installation dialogs is different from the application icon.

    You can customize it using the "drop-in technique" described in Section 6.3.3, "Customization Using Drop-In Resources."

    The current version of Inno Setup assumes the image is a bitmap file with maximum size of 55x58 pixels.

  • To ensure the icon is set in the runtime, make sure to explicitly add it to the stage. See Section 6.3.5, "Platform-Specific Customization for Basic Packages."

  • Consider signing the resulting .exe package. If you distribute an unsigned executable, then many versions of Windows will scare the user with an "Unknown Publisher" warning dialog.

    If you sign your package, then this warning will be removed. You will need to get a certificate and then can use the signtool.exe utility to sign the code.

  • You can fine tune the self-contained application folder before it is wrapped into an .exe file, for example to sign the launcher executable.

    To do this, provide a Windows script file, using the technique from Section 6.3.3, "Customization Using Drop-In Resources."


Note:

While the resulting package is displayed in the list of installed applications, it does not use Windows Installer (MSI) technology and does not require the use of GUIDs. See the Inno Setup FAQ for details.


6.4.2 MSI Package

MSI packages are generated using the Windows Installer XML (WiX) toolset (also known as WiX). As of JavaFX 2.2, WiX 3.0 or later is required, and it must be available on the PATH. To validate, try running candle /? from the command line where you launch the build or from your build script.

By default, a generated MSI package:

  • Is optimized for deployment using enterprise deployment tools

  • Installs to a system-wide location

  • Does not have any click-through UI. Only a progress dialog is shown.

  • Must to be referenced from the programs menu or have a desktop shortcut (having both is fine)

  • Will remove all files in the installation folder, even if they were created outside of the installation process. (WiX 3.5 or later is required.)

  • Will try to use the application identifier as UpgradeCode.

    If the application identifier is not a valid GUID, then a random GUID for UpgradeCode is generated.

  • ProductCode is randomly generated. To use a fixed Product code, customize the WiX template file using the technique from Section 6.3.3, "Customization Using Drop-In Resources."

If you plan to distribute your MSI package on the network, then consider signing it for the best user experience.

You can also fine tune the self-contained application folder before it is wrapped into the .msi file, (for example, to sign the launcher executable). For details, see Section 6.4.1, "EXE Package."

To add a custom UI to the MSI package, you can customize WiX template file used by JavaFX Packager using technique from Section 6.3.3, "Customization Using Drop-In Resources.". Consult WiX documentation for more details.

6.4.3 DMG Package

By default, a DMG package provides a simple drag-and-drop installation experience. Figure 6-3 shows an example of the default behavior during installation.

Figure 6-3 Example of Default Installer for Mac OS X

Surrounding text describes Figure 6-3 .

To customize the appearance of the installation window, you can provide a custom background image.

If the background image has different dimensions or you need to position the icons differently, then you must also customize the DMG setup script that is used to tweak sizes and positions of elements on the install view. For details about how to do this, see Section 6.3.3, "Customization Using Drop-In Resources."

To fine tune the self-contained application folder before it is wrapped, you can provide your own bash script to be executed after the application folder is populated. You can use it, for example, to enrich it with localization files, and so on. Figure 6-4 shows an example of a "tuned" application installer.

Figure 6-4 Example of Customized Appearance of Installable Package for Mac OS X

Surrounding text describes Figure 6-4 .

To create a Gatekeeper-friendly package (for Mac OS X 10.8 or later, see Section 6.3.5.1, "Mac OS X"), the application in the DMG package must be signed. It is not necessary to sign the DMG file itself. To sign the application, you can use a technique described in Section 6.3.3, "Customization Using Drop-In Resources" to provide a config script to be executed after the application bundle is populated. For sample DemoApp, the config script is located in the package/macosx/DemoApp-post-image.sh and has the content shown in Example 6-7.

Example 6-7 Example of Config Script to Sign the Application

echo "Signing application bundle"
#Move to the folder containing application bundle
cd ../images/dmg.image
#do sign
codesign -s "Developer ID Application" *.app
echo "Done with signing"

The DMG installer also supports a click-though license provided in the text format. If use of rich text format is desired, then prepare the license.plist file externally, then add it to the package using the technique from Section 6.3.3, "Customization Using Drop-In Resources."

No third party tools are needed to create a DMG package.

6.4.4 Linux Packages

Producing install packages for Linux assumes that the native tools needed to build install packages are installed. For RPM packages, this typically means the RPMBuild package and its dependencies. For DEB packages, dpkg-deb and dependencies are needed.

No admin permissions are needed to build the package.

By default the resulting package:

  • Will install the application to /opt

  • Will add a shortcut to the application menu

  • Does not have any UI for installation (normal behavior for Linux packages)

Customization tips:

  • To place the application into a specific category in the application menu, use the category attribute of <fx:info>.

    Refer to Desktop Menu Specification and your window manager docs for the list of category names.

  • The icon is expected to be a .png file

  • Advanced customization is possible by tuning the build template files using techniques from Section 6.3.3, "Customization Using Drop-In Resources.".

    Consult the DEB/RPM packaging guides to get more background on available options.

6.5 Working Through a Deployment Scenario

Consider following scenario. You have a JavaFX application that:

  • Uses several third-party libraries

  • One of the third-party libraries uses JNI and loads a platform-specific native library using System.loadLibrary()

  • Needs a large 1Gb heap

How do you package it as a self-contained application that does not need admin permissions to install?

It is assumed that your application works fine as a standalone, that the main JAR file is built in the dist folder (using <fx:jar>) and that third-party libraries are copied to the dist/lib directory.

One way to assemble a self-contained application package is shown in Example 6-8. The approach is:

  • Include all application JAR files.

  • Add native libraries applicable to current platform as resources of type data.

    Ensure that the fileset base directory is set to the folder containing the library. This ensures that the libraries are copied to the top-level application folder.

  • Request a user-level installation with <fx:preferences install="false"/>

Note that the top-level application folder is added to the library search path, and therefore System.loadLibrary() will work fine.

Example 6-8 shows an example <fx:deploy> task.

Example 6-8 Example <fx:deploy> Task

<fx:deploy nativeBundles="all" width="600" height="400"
           outdir="${basedir}/dist" outfile="NativeLibDemo">
    <fx:application name="NativeLib Demo" mainClass="${javafx.main.class}"/>
 
    <fx:resources>
        <!-- include application jars -->
        <fx:fileset dir="dist" includes="*.jar"/>       
        <fx:fileset dir="dist" includes="lib/*.jar"/>

        <!-- native libs for self-contained application -->
        <!-- assume they are stored as
                 native/windows/x86/JNativeHook.dll
                 native/linux/x86_64/libJNativeHook.so
                 .... -->
        <!-- ensure libraries are included as top level elements
                to get them on java.library.path -->
        <fx:fileset dir="${basedir}/native/${os.name}/${os.arch}"
                    type="data">
            <include name="*.dll"/>
            <include name="*.jnilib"/>
            <include name="*.so"/>
        </fx:fileset>
    </fx:resources>
 
    <!-- Custom JVM setup for application -->
    <fx:platform>
        <fx:jvmarg value="-Xmx1024m"/>
        <fx:jvmarg value="-verbose:jni"/>
        <property name="my.property" value="something"/>
    </fx:platform>
 
    <!-- request user level installation -->
    <fx:preferences install="false"/>
</fx:deploy> 
Previous
Next