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 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 apps so they have one of those lovely 128x128 icons. Apps can be launched with a double-click, and can even be bound to particular file types so that your app gets launched when the documents are double-clicked. Swing apps also get the luscious Aqua user interface for 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 even use the hardware acceleration, which you won't find on any other platform.

Let's look at how apps are packaged on OS X.

The Extremely Portable Approach
First, the easiest way to package a Java application for OS X is as a JAR file. As long as your JAR file includes the standard Main-Class attribute (and is otherwise properly formatted), you can double-click it and it will launch, or run it from the command line by executing java -jar filename.jar. (Without that Main-Class attribute, you'll have to specify the main class, just as you would on any other platform.)(The source code for this article can be downloaded from below.)

Of course, it won't have its own fancy icon, just the standard OS X JAR file icon (see Figure 1). However, in the write once, run anywhere tradition, this exact same file will run on OS X, Windows, Solaris, Linux, or any other Java platform. If all you're writing is a simple utility and you don't want to spend the extra effort to support OS X, then you're done.

Figure 1

The Extremely Well-Integrated Approach
Although the extremely portable approach works pretty well as far as it goes, what you get doesn't look like a first class application. The first thing you'll notice after the generic icon is that your app looks a little different from other apps when it's running. The application menu, which in other apps contains the name of the application, simply specifies the fully qualified class name of the main class you specified in the manifest or on the command line (see Figure 2). Any menus in your app will show up at the top of the window the MenuBar (or JMenuBar) is associated with as well. This is not what your Mac users will expect, although it works just as well. With a tiny bit of work packaging your app, you can get full integration with the system menu bar (see Figure 3).

Figure 2

Figure 3

Another advantage is that you can associate file types with your application when you package your app according to the Apple guidelines. That way, you can have your app launch automatically when any of its associated files is double-clicked on. I'll show you how to do that in detail in my next article. For now, though, suffice it to say that the little bit of extra work you do packaging your app gives you a lot nicer integration to the platform on OS X.

In the rest of this article, I'll first discuss how to package your app using one of the available tools. Then I'll walk you through the file hierarchy these tools create so you'll know what's really going on underneath it all.

Packaging Tools
There are a few tools that you can use to package your app for OS X. We'll look briefly at three of them, MRJAppBuilder, Project Builder, and OSXize.

MRJAppBuilder is included free in the developer tools that ship with every copy of OS X. You can use it to package your own applications or to package up JAR files that someone else wrote. It also has a nice GUI (see Figure 4).

Figure 4

You'll find MRJAppBuilder and Project Builder in /Developer/Applications once you install the developer tools. (These tools are found on a separate CD or in /Applications/Installers on your hard drive, depending on how you acquired OS X.)

Project Builder
Project Builder is the integrated development environment that's included free in the same set of developer tools as MRJAppBuilder. It's a nice IDE, and I use it for a lot of my own development work, whether it targets OS X or not. (I've written a lot of Web applications that were eventually deployed on Linux, Windows, and Solaris using Project Builder and I like it a lot.) It includes project templates for a wide number of Java project types, Swing applications, Swing applets, AWT applications and applets, command-line Java applications (the template is called "Java Tool"), JNI-based applications, and also Cocoa-Java applications.

I won't go into how to build an application with Project Builder here, but any application project you build with Project Builder is automatically packaged as a first class OS X application. (The JAR file inside is quite portable, however, unless you're using some specific native feature.)

OSXize is a packaging tool I wrote in Java a while back. It can be used from the command line to generate a fully packaged OS X application, and can also be used as an Ant task to automate generation of your OS X application, if you're using Ant for build management. (And you should!) It also has the advantage of being fully cross-platform, so if you're building your apps on a Linux box or on Windows, you don't need to forsake your OS X friends. Like MRJAppBuilder, it can also convert any existing JAR files to fully fledged OS X applications, whether you wrote them or not, and whether you have the source code or not, although since it's a command-line app, you can do it in just a few keystrokes.

In fact, to convert an existing JAR file to an OS X application, all you have to do is run the following command line:

java -jar osxize.jar -addjar MyApp.jar

If MyApp.jar has the Main-Class attribute set, in less than a second you'll have a new application called JavaApplication.app. Okay, so you probably want to specify a more descriptive name for your app. You can handle that by passing the -n attribute:

java -jar osxize.jar -n "My Fabulous Application" -addjar MyApp.jar

OSXize then generates My Fabulous Application.app for you. (It also does some nice things that MRJAppBuilder doesn't do, like making sure your app shows up as My Fabulous Application when you look at what processes are running, e.g., through ps or top.)

There are a number of other flags you can specify as well. No Main-Class attribute in the manifest? No problem. Just specify the main class with -m. Want to specify your own icon file? Make a new icon (see Figure 5) using the ICNS Editor (also in /Developer/Applications) and specify the path to the file with the -i option. Want to specify an application version to show up in the Get Info dialog? Use the -version flag. The full set of options is documented on the Web site as well as how to use the OSXize Ant task. You can download it from www.javaosx.com/apps/.

Figure 5

The .app Application Bundle
What exactly have we created when we've used these tools? Happily, all we've created is a file hierarchy that OS X recognizes as a "bundle." Ever since Mac OS made the big leap to Unix, it's been a lot more file-oriented than previous incarnations. Gone are the days of complex file formats with separate resource and data forks. Well, almost gone. The OS still supports them, but mostly for backward compatibility reasons at this point.

Instead, the Apple team based most of their packaging on special arrangements of files in the filesystem. Modern OS X applications (with the exception of some monolithic Carbon binaries) are a collection of files living in a directory with the .app extension, and not much more. The .app extension is a magic, or "blessed," extension that says: treat this directory differently. (There are a few other magic extensions, such as .kext, that contain other types of bundles, and other special file hierarchies like those in /Library/StartupItems.)

Inside an .app directory, you'll find a special directory hierarchy that's used to contain the files and resources that make up the application. These include the icon file, files with special information for the Finder describing the application, an executable binary file for Java applications, one or more JAR files, the MRJApp.properties file, and a number of other files as well.

The example command line shown earlier would create a file hierarchy as follows:

My Fabulous Application.app/
My Fabulous Application

In the rest of this article, we'll look at what each of these files is and what it does.

The PkgInfo File
This is an 8-byte file, which must contain "APPL" (in ASCII) as its first 4 bytes, and contains as its last 4 bytes the "creator code" that the finder should associate with this application. Mac OS has had the notion of creator codes from the beginning. These are used to associate files with the applications that created them (thus the name). This is why Mac files of the same type may be associated with different applications. You can register your own creator code on the Apple developer Web site for free. Unless you have an officially recognized creator code, though, you must use the reserved code "????" (also in ASCII.) This is reserved to mean "Unknown Application" and is guaranteed not to interfere with any other application. Applications built with OSXize have jNeo as their creator by default.

The Info.plist File
The Info.plist file is one of many .plist files used throughout the operating system to hold parameters. Most of them, including Info.plist, are XML files, although there are some other older formats still in use. Info.plist contains most of the information about the application that the Finder keeps track of, like version information, and which .icns file to use for the icon.

The Application Stub
In the previous directory listing, inside of the MacOS directory, you'll find a file called My Fabulous Application (or if you used MRJAppBuilder, JavaApplication). This is a native OS X executable, which is the file actually launched by the Finder. It then reads the rest of the configuration information in MRJApp.properties and executes the main() method on the appropriate class in the contained JAR file(s).

The big thing to note here is that this file must have the execute bit set in order for the application to work. (In fact, if you use OSXize to generate your application on a Windows machine, you'll need to set the execute bit manually before you can run the app on OS X, since Windows filesystems don't have execute bits.) This execute bit issue is one that often comes up when an app mysteriously won't run. If this happens to you, cd to the /Contents/MacOS directory, and then chmod +x the file you find there. If everything else was okay, your app should now be double-clickable and run appropriately.

The MRJApp.properties File
This file contains important runtime information used to configure, among other things, whether to use the system menu bar for Java menus, whether to use hardware acceleration, at which threshold levels the garbage collector should run, where standard out and standard error should be written, and whether the grow box (in the lower-right corner of a given window) should intrude into the root pane of your window or if the window should be padded vertically so that it doesn't have to intrude. These are useful for tweaking the final appearance and performance of your Java application. It's just a regular Java properties file, so take a look at it. Much of it is fairly self-explanatory.

The ICNS File
OS X icons are packaged in .icns files, which can be created with the Icon Composer app found in /Developer/Applications. You'll need to create your icon files in another application, the most suitable being Adobe Photoshop. (You can directly import these files with full transparency into Icon Composer.) Icon files should follow the Apple Human Interface Guidelines, and are huge and rich compared to icons on other systems. They are 128x128 with full transparency support, thanks to the power of the underlying Quartz graphics engine. If there is interest, I can write about how to create your own icons in my next column.

The JAR Files
Of course, your application bundle needs to have your actual Java code in order to run it. You can have one or more JAR files packaged together into your .app bundle, although you can't just throw JAR files in there and expect them to show up on the classpath. You have to also add them to the com.apple.mrj. application.class path property in the MRJApp.properties file. (Both MRJAppBuilder and OSXize do this for you if you specify additional JAR files.)

That's really all there is to a typical packaged Java application. There are some additional attributes to add to the Info.plist if you want to associate a given file extension with your app, for instance, .foo. You'll also need to include additional .icns files in the Contents/Resources directory if you want to associate icons with the files owned by your app, for instance, a foo.icns file containing the icon the finder should use for all .foo files. Here again, there are some tweaks you'll need to make to Info.plist to tell the finder which icon to associate with which file type.

Having great looking double-clickable applications is just something you can use to make your friends on other platforms a little jealous while waiting for Apple to get the kinks out of their J2SE 1.4 port.

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

Source Code for this Article zip file ~24.6 KB

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.