HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML

Java development on OS X is similar to Java development on any platform, particularly any Unix platform. The differences are in how your code integrates with the platform. Java lacks a cohesive platform integration strategy, so running a Java application usually doesn't have the same feel as running a native one.

In contrast, Java on OS X is a first-class citizen. You can integrate your app so well that users probably won't even know they're using a Java application. You can package your app so it has one of those lovely 128 x 128 icons and can be launched with a double-click; it can even be bound to particular file types so it's launched when the documents are double-clicked. Swing apps also get the luscious Aqua user interface free, and with a couple of lines of code you can also tell the runtime to let your app use the system menu bar and the hardware acceleration that you won't find on any other platform.

OS X also comes bundled with a great set of developer tools, all at no cost. I'll be using one of them, the PackageMaker, in this article.

Creating a Native Installer
This article shows how to package your Java application into a native OS X installer. I'll use one of the many free development tools that come with the platform, so to follow along, you should be running OS X and have the developer tools installed. Depending on when you bought your system, the developer tools installer may be on a separate CD or preloaded on your system under /Applications/Installers/Developer Tools/. If you can't find the installer, you can always download it from the Apple developer Web site. You'll have to join the Apple Developer Connection, but the minimum membership is free and provides access to the tools. (You should do this anyway if you plan on doing any amount of development for the Macintosh, as it provides access to lots of good information.)

If you haven't already done so, run the installer by double-clicking it; you'll need an administrator password to complete the install.

The installer we'll be creating looks like the one you used to install the developer tools. (They eat their own dog food at Apple, so we're using the same tool they used to create their installer.) Figure 1 shows the installer I built for Ant 1.5, and Figure 2 shows the icon. It all looks very official.

Figure 1 Figure 2

There are two important versions of the package installer. We're documenting version 1.0, which came with OS X 10.0 and 10.1; OS X 10.2, code named Jaguar, which shipped on August 24, comes with version 1.1. Although this tool is much nicer that 1.0, I've opted to cover 1.0 for one important reason: installers created with 1.1 may not be backward compatible with OS X 10.1 and earlier. (This article was written before the final release was available, so this may be addressed by the time they ship.) The extra pain of using 1.0 is minimal, so you may as well make your Java apps available to the widest possible installed base.

The installer we create contains three groups of files; we want to install these files on the user's machine, which PackageMaker packages into an archive file. There are scripts, such as preinstall and postinstall, which are executed at various points during the install process, and a set of files that contains documentation presented to the user when the installer is run. We'll look at each of these in turn.

The files to install are the application, whether a double-clickable JAR file or a fully packaged .app bundle, and any other files you may wish to distribute with your app. Good examples are documentation files, configuration files, external data files, and the like. We'll cover how to build a fully packaged, double-clickable .app bundle, complete with its own icon and everything else in a subsequent article. For now we'll assume that the app is a double-clickable JAR file. (Any JAR file that includes a Main-Class: attribute will automatically be launched when you double-click it in the Finder on OS X.)

You'll need to create a new directory that contains the files you want to install, with the files laid out the way you want in the directory the app is installed in. You'll typically put a folder named for your application in this directory as well as all the files you want to include. When you build the installer, you can specify whether the path contained here should be absolute or relative to a directory that the user chooses. For most apps, the latter is the right choice. Of course, for the Ant installer, I wanted to make sure that the files were installed in /usr/local/ant, and that symbolic links were created so that Ant would be included on the command-search path. Which one is appropriate depends on the kind of application you're working with, but if you can let the user have a choice about where the app lives, you should.

You'll then need to create a second directory for the installer resources at the same level as your first directory hierarchy. Be sure to name it something you'll be able to distinguish from the other directory when you run the installer. Place your scripts and documentation files into this directory.

The install scripts are scripts that are run before and after the archive containing the app is unpacked. There are several optional scripts you can include, each corresponding to a different phase of the install process. The scripts correspond to six phases: preflight, preinstall, preupgrade, postinstall, postupgrade, and postflight. This lets you check out the environment before the installer runs, move old files out of the way, do postinstall configuration, and clean up when you're done. The package installer runtime will execute each script at the appropriate time. They can be written in just about any scripting language, from AppleScript to PERL to a simple shell script. Many simple installers don't even need any scripts. Let's look at the preinstall script from the Ant 1.5 installer to see what it's all about.

#!/bin/sh

if [ -e /usr/local/ant ] ; then
mv /usr/local/ant /usr/local/ant-pre-1.5
fi

My Ant installer preinstall script checks if there's a previously installed version of Ant, and if so, moves it out of the way before the installer unpacks the archive. It's nice not to clobber software someone may have installed by hand! The postinstaller then runs through, looking for any previously installed Ant extensions and copies them into its extensions directory. What you do in these scripts depends entirely on the app you're installing.

The scripts must be named according to naming conventions that the package runtime uses to determine which file to use when. In the 1.0 version of the package tool, the correct name for the preinstall script is <package-name>.pre_install, where <package-name> is replaced by the name of the installer you're creating (without the .pkg or .mpkg extension that all installers have). As of this writing, it looks like 1.1 will remove the underscore character. They do need to be named correctly in order for the package runtime engine to run them, so check the help files for the correct naming convention for the version you're using. They should have the read and execute bits turned on. (chmod a+rx *_install in your resources directory will do this.)

Once your scripts are written, you can add more files that describe the app so that the user is presented with information when installing it. There are three main files to be concerned with here: Welcome, ReadMe, and License. These can be in any of four file formats: HTML, RTF, RTFD, or plain text. They must have the appropriate extension for the file type: .html, .rtf, .rtfd, or .txt, respectively, and again must be named correctly in order for the installer runtime to know when to display them.

You may also include images in your HTML files, and they must also be included in the resources directory when you build your installer.

These files are presented to the user in the order specified earlier. If you include a license file, the user will also be prompted as to whether he or she agrees to your license terms before being allowed to continue the installation process. These files can even be easily globalized, so the single installer will present information in the language of the current locale. You'll have to write the localized content yourself though.

Last, you can even include a background image. This can be a .jpg, .tiff, .gif, .pict, .eps, or .pdf file. (Between Quicktime and Quartz, it must have been too easy to include so many.)

Running PackageMaker
Once your files are all prepared, it's time to launch PackageMaker. You'll find it in /Developer/Applications/. It will present you with a single window (see Figure 3), but without any of the fields filled in.

Figure 3

In the Package Root Directory box, enter the full path to the first directory you created, the one that contains the actual files to install. You can either browse to it by clicking the Change Root button or enter the path if you know it.

In the Package Resources Directory box, specify the resources directory, the second directory you created.

In the Package Information box, fill out the various text fields: Package Title, Package Version, Package Description, with text that's appropriate for your app.

The Default Location field is important and works with the Relocatable checkbox. It specifies which path your app should be installed in.

If your installer is for a regular application, the default location should be /Applications and Relocatable should be checked.

However, if you need to install in a particular directory, specify it here. Remember, any subdirectories inside the Package Root Directory will be installed as subdirectories of the directory specified here. Most likely you'll also need to define that the specified path needs to be on the root volume. I'll show how to do that in a moment.

Depending on where your app needs to be installed and what your install scripts need to do, you may need administrator privileges to complete your install. Avoid requiring this if you can, but if you're installing in system directories or creating new users (as I do in my forthcoming Tomcat installer), you'll need your scripts to run as root for the install to work.

PackageMaker handles this for you. By checking the Needs Authorization box, you can instruct the package you create to request an administrator password. The installer then executes the scripts with the appropriate privileges. The Developer Tools installer worked this way.

The Required checkbox is only relevant if you're going to bundle this package into a Meta Package, a construct that allows users to select optional subpackages, as the Developer Tools package did. I'll cover how to do that another time.

The other checkboxes are fairly self-explanatory and can typically be left unchecked when installing a Java application. Try to avoid requiring a reboot. Now that Mac OS is based on Unix, it can easily stay up for months at a time. Don't make your users sit through a reboot, unless it can't be avoided.

When you're happy with the settings, click the Create Package button and save out your installer.

The last little trick is the one I alluded to earlier. If your package needs to be installed on the root volume, you'll need to resort to using a text editor to tweak a file in the package you just created. (The 1.1 version has a checkbox for Root Volume Only.) Control-click or right-click on the package you just created and select Show Package Contents from the context menu that pops up. Then drill down to Contents /Resources/English.lproj to find the <package-name>.info file. This contains several of the settings we created using the graphical user interface. You can open it by dragging it onto TextEdit or your favorite text editor. You'll need to add a package flag:

rootVolumeOnly YES

Insert this line above the other package flags and save.

Now all you have to do to share your application with the world is to archive it and post it somewhere. The safest way to do this is with gnutar: gnutar -czvf <package-name>.tgz <package-name>.pkg. If you're distributing your app this way, make sure you don't have any filenames longer than 32 characters, since StuffIt Expander still doesn't maintain long filenames correctly, and, by default, browsers will open downloaded archives using it.

Author Bio
Ian McFarland is the president of Neo Ventures Ltd., a software consulting company in San Francisco, and author of Mastering Tomcat Development, available in September from Wiley; he also maintains www.javaosx.com. He's been a Java developer since release 1.0 alpha 2. [email protected]

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.