|
Introduction
If you are a Java developer, one of the first things you fall in love with is seeing your applications run on different platforms. Just give me a Jar file, War file, or the class files, and away I go.
Well, almost. Java is great at being cross-platform, but the greatest weakness in Java's cross-platform design is that each platform requires a different method of launching the application - and usually that is where most people get stuck. Sure, we can tell people to launch our applications using the command line, or we can use the Java Web Start tools. However, when it comes to making your Java application look and feel as close as possible to the native platform, you will need to do a little extra work on most platforms. This is especially true if you want to use the Eclipse SWT GUI toolkit.
SWT? Why on earth do you want to use that? This article is not about the merits of SWT or Swing, and it's not intended to convert anyone to use another toolkit. However, when it comes to making your application look and feel like a native application, SWT does a great job. So, without further ado...
Why Bother With Application Bundles
There are several ways to package a Java application on Mac OS X. However, if you want your application to look and feel like a native Mac OS X application, you will want to opt for creating an application bundle. The advantages to using this method are:
- It looks like a single file in the Finder. You can drag it around while preserving your application directory structure, bundled resources and configuration files. This is especially advantageous for SWT applications since they contain native libraries.
- It's double-clickable. Your users don't need to do anything different with your Java/SWT application.
- Your Java application will get a name in the menu (instead of the full qualified class name) and an icon in the dock
- It makes it easy to set up and maintain your launch configuration (class path, VM arguments, properties, user.dir directory).
- It's the standard and preferred method for packaging Java applications on Mac OS X.
Bundle Directory Structure
So, what exactly is an application bundle anyway? It is simple a directory that contains a predefined directory structure, ends with the ".app" extension, and has the "bundle" flag set. That's it. The Finder does the magic of hiding the directory, finding the icon that you specify, and running the required executables that you provide.
So, in order to create your application bundle, you will first need a directory structure. Create a directory structure like the following:
MyApp.app - Directory
Contents - Directory
Info.plist
MacOS - Directory
java_swt
PkgInfo
Resources - Directory
MyApp.icns
Java - Directory
dll - Directory
libswt-carbon-XXXX.jnilib
libswt-pi-XXXX.jnilib
libswt-webkit-XXXX.jnilib
MyApp.jar
swt.jar
swt-pi.jar
Since the Finder hides the application bundle's sub-directories, you can't browse them by default. However, if you right-click on the application bundle (or Option-click) and choose "Show Package Contents" you will be able to browse the contents of the application directory. You can also access these directories by using the Terminal if you prefer.
Info.plist
The most important configuration file in the bundle is the Info.plist file. This is the file that the Finder uses to set up and launch to java_swt application (which we will get to below) and java_swt uses this file to set the setting in the Java Virtual Machine. So, what is the Info.plist file? It is an XML file that follows the Property List Schema designed by Apple. You can base your file by copying the text below and modifying the data for your application.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC
"-//Apple Computer//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>java_swt</string>
<key>CFBundleGetInfoString</key>
<string>MyApp, Copyright () All rights reserved.</string>
<key>CFBundleIconFile</key>
<string>MyApp.icns</string>
<key>CFBundleIdentifier</key>
<string>org.myorg.myApp</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>MyApp Bundle Name</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>Java</key>
<dict>
<key>ClassPath</key>
<string>$JAVAROOT/swt.jar:$JAVAROOT/swt-pi.jar:$JAVAROOT/MyApp.jar</string>
<key>JVMVersion</key>
<string>1.4*</string>
<key>MainClass</key>
<string>org.myorg.myApp</string>
<key>VMOptions</key>
<string>-Djava.library.path=$JAVAROOT/dll
-Dorg.eclipse.swt.internal.carbon.noFocusRing
-Dorg.eclipse.swt.internal.carbon.smallFonts</string>
<key>WorkingDirectory</key>
<string>$APP_PACKAGE/Contents/Resources/</string>
</dict>
</dict>
</plist>
*Note: You will need to take out the line breaks in the VMOptions string node if you copy thistext directly from the web browser. This node was wrapped for formatting purposes, but thereal file should not contain line break characters.
Some interesting fields to play with in the Info.plist file are:
- CFBundleExecutable: java_swt is a launcher that - among other things - sets the threads up correctly to allow SWT to use carbon widgets. However, if you are running Java 1.4.2_04 and the Eclipse 3.1 stream, you can use the default Java launcher for Mac OSX (JavaApplicationStub) provided that you also specify the JVMOption: <key>StartOnMainThread</key><true/>
- CFBundleName: The Finder will use this name in the Menu Bar and on the Dock.
- noFocusRing & smallFonts: These two optional system properties are a welcome addition to the SWT port to OSX. NoFocusRing will remove the Mac OS focus ring around the currently focused widget (ie, a text box that the user is typing in). It also makes the widgets resize to include the space that used to be used by the focus ring. SmallFonts makes SWT use a smaller font. Both of these options make the user interface more portable, especially if you have used a GUI builder and/or FormLayouts.
- WorkingDirectory: The user.dir directory that gets set in the JVM system properties, so all relative file names will be relative to this directory. You can use this to have your configuration files be written into the application bundle and thus keeping them intact when the application is moved. Note that setting the working directory to point inside the application bundle must be used with caution. If the developer isn't careful, some user files could be written into the bundle, making it difficult for the user to get at. Also, if the bundle is on read-only media, then you will not be able to write into the bundle. However, If you prompt the user for a file name, the File Dialog will not let them enter the application bundle, so those files will be safe.
java_swt
This is the SWT application launcher for Mac OS X. It is a replacement for the standard Java application launcher on Mac OS X (JavaApplicationStub) but it is required for SWT to use the Carbon components correctly. All you have to do is get the java_swt file from the Carbon distribution of the SWT native libraries and move the file to the correct location in the application bundle. You will also want to make sure that the file is marked as executable.
SWT Libraries
Once you have moved the java_swt file to the correct place, you can also move the native libraries (*.jnilib) to the dll directory. Move the swt.jar and swt-pi.jar files into the Java directory.
PkgInfo
This file only needs to contain the following text:
APPL????
MyApp.icns
This is the icon file that the Finder uses. It's a special format file and should match the name that you use in the Info.plist file. However, creating this file is very easy. If you have you icon made up and saved in a JPEG or GIF format, you can open up the "Icon Composer" application provided in the Mac OS X developer tools. This application is located in System > Developer > Applications > Utilities. You can drag the JPEG or GIF files from the Finder and onto the different sized icon spaces in the application. If will resize the images for you if you do not have all the correct sizes. You can even include bit masks to set the "clicking" area of the icon. Once you've finished, you can just save the new icon as an *.icns file with the correct name and put it in the correct location in your application bundle.
Watching Your Resources
When you bundle the application this way, you can include your resource files in the bundle directly and access them through the File interface relative to the WorkingDirectory path you specified in the Info.plist file. However, for the sake of portability, the better way would be to package the resources in a Jar file and include that Jar file in the class path. You can then access the resources using the ClassLoader.getResource() or ClassLoader.getResourceAsStream() interface.
An Extra Tip The latest releases of Eclipse for Mac OSX now come with an exporter that will export the application bundle for you provided that you have a working launch configuration. If youuse Eclipse as your development platform on Mac OSX, after building a few bundles yourself, youmay find that this option is more convient for building a new bundle. You can then make modifications to the bundle as needed.
Conclusion
This should get you well on your way to bundling your SWT application for Mac OS X. Once you have bundled your application, you can create an Internet-enabled .dmg file (Disk Image) to distribute it.
Links of Interest
To learn more about .dmg files visit
here.
To learn more about the ClassLoader interface visit
here.
I was given the tip on bundling SWT applications for Mac OS X from the following link. Thanks goes to the Eclipse team and Andre Weinand for posting their notes.
https://bugs.eclipse.org/bugs/show_bug.cgi?id=40003
http://java.sun.com/developer/technicalArticles/JavaLP/JavaToMac3/
http://developer.apple.com/documentation/Java/Conceptual/Java141Development/
Author
Written by Nathan Callender
Application Developer
September 30, 2004
|