As most Java developers have come to realize, one of the most challenging aspects of developing cross-platform Java applications, is how to deploy them, in the most native way possible, to their various target platforms e.g. Windows, Linux and Mac OS X. There are several commercial solutions available, but these cost in the range of $500 to $2000, which may be a bit steep for an independent software developer. In this article, I will provide an overview of how I approached this problem, while developing PWMinder, using a combination of open source tools; and I hope this will provide a framework for those of you facing similar issues.
In my search for a free solution, the first thing I had to accept was, that no single solution would meet all of my needs, and instead, I would need to us a combination of different tools. This approach requires a lot more work than would be needed using a commercial solution, but this is the price for having something for free. The following are the tools I used to create the installers.
Most Java developers should be familiar with Apache Ant. It is a build tool that comes with many built-in tasks, for things such as moving and deleting files, creating folder structures, archiving files, etc., to build and packages applications. While it can be used for building any kind of software, it is targeted for Java applications and includes tasks to compile Java code, create jar files, create Javadoc API documentation, etc. Apache Ant is also extensible, and custom tasks can be created for it. Many third party tools can be incorporated directly into Ant by using their supplied tasks. In my process of creating cross-platform installers, Apache Ant serves the main control center.
Launch4j is a tool that wraps an executable .jar file into a native Windows executable (.exe). Using Launch4j you can set an icon for your .exe, set Windows file manifests, create a native pre-JRE splash screen, set both environment variables and Java runtime parameters, and more. Launch4J come with a GUI front end, that is used to set up the configuration parameters. This configuration is saved as an .xml file that can also be edited by hand. Launch4j comes with an Ant task, and can, therefore, be easily integrated into an Ant script. When launching from an Ant script, variables defined in the Ant script, such as build number, etc., can be passed in to Launch4j, providing even more flexibility. Launch4j basically allows your executable .jar file to act like a Windows .exe.
NSIS is a tool used to generate standard Windows based installers. NSIS is script based and is quite powerful, allowing for a lot of flexibility when creating an installer. I found that this flexibility comes with some complexity, and found there to be a bit of a learning curve when it comes to using NSIS scripts. Having said that, there are many examples available, that can help to set up a basic installer quite quickly. The installer allows for creation of Windows short cuts, creation of an uninstaller, adding and/or updating Windows registry settings. During the install, it can display panels prompting users for install location, display an license screen and even start he application when the installer has completed. As mentioned NSIS is script based, and while you can use any text editor, I would recommend either using EclipseNSIS (plugin for Eclipse) or HM NSIS edit, which both include wizards to help get you started. While NSIS does not come with Ant task, it can be run from Ant, using Ant’s ability to execute commands.
JarBundler Ant Task
JarBundler is an Ant extension that is used to create a Mac .app bundle from an executable .jar file, which can be used to run a Java application on a Mac. An .app bundle is basically a specialized folder structure containing resources, and configuration information to run an application. When this folder is copied onto a Mac, it appears as a file that is used to start the application. JarBundler is configured within an Ant script as an Ant task. The configuration is quite extensive and allows you to control many properties of the .app bundle including its icon, version, working directory, help book location and more. Most of these properties are mapped to bundle variables defined in Mac OS X Runtime Configuration Guidelines (http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPRuntimeConfig/Runtime_Configuration.pdf)
IzPack is a cross-platform installers that creates an installers as an executable .jar file. Similar to NSIS, it allow for panels to display license information, select installation folder, etc. It also includes a utility to create short cuts for both Windows and Unix, and supports creating an uninstaller. Both the installer and uninstaller are .jar files, however, which may not be what users are expecting when installing software. IzPack is configured using one or more xml files and can then be executed within Ant using an IzPack task. While it can create installers for Windows, the installer produced by NSIS looks more native and has more Windows specific features, which is why for Windows I use NSIS.
The Diagram below gives the basic flow I used, to create the installers:
The first step is to use Ant, to compile the Java source, generate an executable .jar file (app.jar in the figure above) and collect and organize any other files necessary for the application (e.g. library .jar file, and support files such as user guide, release notes, license files, images, etc.) into a staging area. Starting from app.jar, the library and support files, the paths for each Operating System diverge.
On Windows, most user would expect to download an executable (.exe) setup file, which when executed, would launch an installation wizard, that would lead them through a set of steps to install the application. The application itself would also be available as an .exe, and shortcuts would be generated in the Start menu. To accomplish this, I first used Launch4j, to convert the app.jar file to a Windows .exe file (app.exe). Next, using Ant, I organized app.exe with any necessary library .jar file and support files into a staging location. I then used NSIS to to create an installer (setup_win.exe) which, when run creates the short cuts, uninstaller, registry entries, etc. The user can then download setup_win.exe directly and run it.
Linux users are a little more relaxed about how to install software, but I still wanted something more professional, than to simply unzip the files to a desired location. For Linux, I kept app.jar as it is, and created a bash script to execute it. Next, using Ant, I organized app.jar with any necessary library .jar files, the bash script and support files into a staging location. I then used IzPack to create the installer, as setup.jar file. Rather than have the user download a .jar file, which they may not be as familiar with, I put the setup.jar file into a .tar.gz file. The user would download the setup_lin.tar.gz file and extract setup.jar file. They would then run the setup.jar, which would install the application and create shortcuts. The user can then either start the application using the short cuts created or by running the bash scripts.
Mac OS X
On Mac, users expect to use .app bundles to run their applications. So for Mac deployment, I used the Ant based utility called JarBundler, to convert app.jar, to a an .app bundle (app.app). I then used IzPack to take the app.app, the library files, and the support files and create an installer .jar file (setup.jar). I then used IzPack’s own utility to convert this setup.jar to an installer .app (setup_mac.app). Lastly, to facilitate downloading of the setup_mac.app folder structure, I put it into a .zip file (setup_mac.zip). The user would download the setup_mac.zip file, extract the setup_mac.app. They would then run setup_mac.app which would install the application, including app.app. To run the application the user would then double-click the app.app, just as they would for any other application they have.
While there are a lot of steps involved, what is nice about all of the above tools is that they can be all integrated into Apache Ant, so at the end I can compile the code, create the executable .jar file, organize the files and then create the installers for Windows, Linux and Mac, all from one Ant script.
Note: this article first appeared in the December 2009 Issue of ASPects, The Monthly Newsletter of the Association of Software Professionals.