How many times has this happened to you? You've written a little Java utility, or maybe even a more complex application, and you want to create Mac OS X application bundle for easy distribution.
You'd like to be able to do it automatically from your build process, but you're forced to go run the Apple Jar Bundler and tweak all the settings manually every time you build.
Well no more! JarBundler is a feature-rich Ant task which will create a Mac OS X application bundle from a list of Jar files and a main class name. You can add an Icon resource, set various Mac OS X native look-and-feel bells and whistles, and maintain your application bundles as part of your normal build and release cycle. It is free software licensed under the GNU General Public License.
This release is based on the earlier work of Seth Morabito's JarBundler 1.4 found at http://loomcom.com/jarbundler/
Source and binary, all platforms (ZIP): | jarbundler.zip |
Source and binary, all platforms (TAR): | jarbundler.tar.gz |
Move the file jarbundler-1.7.jar into /Developer/Java/Ant/lib or into your local ANT lib directory. Remove any older versions at this time.
To use the Jar Bundler Ant Task, create a task definition in your ANT build.xml file like this:
<taskdef name="jarbundler" classname="net.sourceforge.jarbundler.JarBundler" />
Now, from a target, you can add the "jarbundler" task.
<jarbundler dir="release" name="MyApp" mainclass="org.foo.myapp.Main" jar="myapp.jar" />
Attribute | Description |
---|---|
dir | The directory in which your application bundle will be created. |
name | The name of your application bundle (minus the ".app" extension). |
mainclass | The name of the main class to run when the application bundle is launched.
The corresponding bundle variable is
MainClass
|
jar | A single jar file to be used in your application.
Not Required if there are nested <jarfileset> or
<jarfilelist> nested tasks.
Can be used with nested <jarfileset> and/or <jarfilelist>
tasks i.e. all jar files will be added to the class path.
|
Attribute | Description |
---|---|
arguments | Extra command-line arguments for the Java application.
The corresponding bundle variable is
Arguments
|
build | Application build number. This string is used in the default
"About..." box along with the 'version' number. This default About Box format is "version (build)" i.e.
"4.3.1 (231)". Also see version and infostring attributes.
The corresponding bundle variable is
CFBundleVersion
Default: the value of the version attribute
|
bundleid | Unique identifier string for the bundle. This string should be in
the form of a java package name, for example com.apple.myapp.
The corresponding bundle variable is
CFBundleIdentifier
|
chmod | The full path to the BSD 'chmod' command.
Mac OS X and UNIX uses do not normally have to worry about changing this.
|
developmentregion | The development region of the bundle.
The corresponding bundle variable is
CFBundleDevelopmentRegion
Default: English
|
extraclasspath | A list of files or patternsets (space or comma seperated) to add to the bundle's classpath. The files referenced by this property will not be copied into the bundle, so the resulting .app may only work on systems that have these external resources available. |
helpbookfolder | Specify the directory name of the Help Book in the "resources"
directory. When this name must match the directory name when using
the <resourcefileset> task to copy the Help Book HTML files into the bundle.
The corresponding bundle variable is
CFBundleHelpBookFolder
|
helpbookname | Specify the name of the Help Book. This is string is also used
as the META tag to designate the initial HTML file to be loaded into the Help Viewer application.
<meta name="AppleTitle" content="Hello World Help"/>
NB: The Apple Help Book system does not open the file index.html by default. Although
it is a good practice to use this filename with the embedded META tag shown above.
The corresponding bundle variable is
CFBundleHelpBookName
|
icon | File reference to a Mac OS X icon file. This file is created with the Mac OS application located at "/Developer/Applications/Utilites/Icon Composer" |
infostring | A string for display in the Finder's Get Info panel. Also see version and build attributes.
The corresponding bundle variable is
CFBundleGetInfoString
Default: the value of the version attribute
|
jvmversion | The version of the JVM required to run the application.
Typically a string in the form "1.3", "1.3+", "1.4", "1.4+", etc.
The corresponding bundle variable is
JVMVersion
Default: 1.3+
|
shortname | The string used in the application menu.
This string is often shorter than
the application's name. For example, "Microsoft Word" displays "Word"..
Apple recommends that this string be limited to 16 characters. JarBuilder enforces this
limit silently by truncating shortname. If the shortname is not specified then
the application's name will be used with no truncation. |
signature | The four-letter code identifying the bundle.
The corresponding bundle variable is
CFBundleSignature
Default: ????
|
stubfile | If set, the location of the Mac OS X Java Application Stub file
to use for this app bundle. See the section "Specifying the Java Launching
Stub File" below. Required for Windows or Linux |
verbose | If true, output more verbose information to Ant while the task is
running.
Default: false
|
version | Version number displayed in Finder, this version number can be though of
as the "Marketing" version without distracting build information. The marketing version
is a string that usually displays the major and minor version of the bundle. This string
is usually of the form n.n.n where n is a number. Also see build and
infostring attributes.
The corresponding bundle variable is
CFBundleShortVersionString
Default: 1.0
|
vmoptions | Command line options to pass the JVM at startup.
The corresponding bundle variable is
VMOptions
|
workingdirectory | The working directory for the Java application.
The corresponding bundle variable is
WorkingDirectory
|
Attribute | Description |
---|---|
aboutmenuname | The string to display in the "About" menu of the running application. (Deprecated under JVM 1.4.1) |
antialiasedgraphics | If set to true, use anti-aliasing when rendering graphics.
Use <javaproperty name="apple.awt.antialiasing" .../>
|
antialiasedtext | If set to true, use anti-aliasing when rendering text.
Use <javaproperty name="apple.awt.textantialiasing" .../>
|
execs | A list of files or patternsets (space or comma seperated) to
place into the "Resources/MacOS" directory and set executable.
Usage Warning: Filenames and directory paths can sometimes contain spaces and
commas. If these characters are present the build will fail mysteriously when using this
attribute.
Use <execfileset/> or <execfilelist/> nested tasks instead.
|
growbox | Show the Aqua resize (grow) box.
Use <javaproperty name="apple.awt.showGrowBox" .../>
|
growboxintrudes | Resizable window's growbox (resize control) intrudes into AWT content. If turned off, the bottom of the window is pushed down 15 pixels. (Deprecated under JVM 1.4.1) |
jars |
A list of jar files or patternsets (space or comma seperated) to be used in your application.
Usage Warning: Filenames and directory paths can sometimes contain spaces and
commas. If these characters are present the build will fail mysteriously when using this
attribute.
Use <jarfileset> and/or <jarfilelist> nested tasks instead.
|
type | The Mac OS type of the bundle.
This attribute is redundant with the implied behavior this ANT task i.e. CFBundlePackageType
should always be set to APPL for applications.
|
shortinfostring | Use infostring attribute instead. |
smalltabs | If set to true, tab controls in Swing applications more closely resemble the Metal look and feel. If set to false, the tabs assume a larger size more similar to the default Aqua controls. (Deprecated under JVM 1.4.1) |
liveresize | If set to true, enable live-resizing of windows. (Deprecated under JVM 1.4.1) |
screenmenu | If set to true, puts Swing menus in the Mac OS X menu bar if using the Aqua look and feel. |
The nested jarfileset element specifies a FileSet. All files included in this fileset will be included in the application bundle and added to the app bundle classpath. Only required if the jars attribute is not set.
The nested jarfilelist element specifies a FileList. All files included in this filelist will be included in the application bundle and added to the app bundle classpath. Only required if the jars attribute is not set.
This ANT DataType element allows developers to specify java properties for the info.plist. This DataType repalces many jarbundler tag attributes. However, if a deprecated attribute is used it will take precedent over a javaproperty. This was done to maintain backward compatibility with earlier versions of jarbundler.
This task takes name/value pairs:
<javaproperty name="apple.awt.showGrowBox" value="true"/>
Additional Java Properites can be found in the Apple Developer Connection document: Apple Java Properties for JDK 1.4+
The nested execfileset element specifies a FileSet. All files included in this fileset will be added to the application bundle's "Contents/MacOS" directory and set executable. Optional.
The nested execfilelist element specifies a FileList. All files included in this filelist will be added to the application bundle's "Contents/MacOS" directory and set executable. Optional.
The nested resourcefileset element specifies a FileSet. All files included in this fileset will be added to the application bundle's "Contents/Resources" directory. Optional.
The nested resourcefilelist element specifies a FileList. All files included in this filelist will be added to the application bundle's "Contents/Resources" directory. Optional.
The nested javafileset element specifies a FileSet. All files included in this fileset will be added to the application bundle's "Contents/Resources/Java" directory. Optional.
The nested javafilelist element specifies a FileList. All files included in this filelist will be added to the application bundle's "Contents/Resources/Java" directory. Optional.
The nested extraclasspathfileset element specifies a FileSet. All files included in this fileset will be added to the application bundle's classpath, but the files will not be copied into the bundle itself. This allows you to specify external system classpath dependencies without bundling the resources. Resources can be files or directories. Optional.
The nested extraclasspathfilelist element specifies a FileList. All files included in this filelist will be added to the application bundle's classpath, but the files will not be copied into the bundle itself. This allows you to specify external system classpath dependencies without bundling the resources. Resources can be files or directories. Optional.
Note that in fact the files are installed in locations which have the same relation to either Contents/MacOS or Contents/Resources directories as the files in the FileSet or FileList have to the 'dir' attribute. Thus in the case:
<resourcefileset dir="builddir/architectures" includes="ppc/*.jnilib"/>
the *.jnilib files will be installed in Contents/Resources/ppc
The nested documenttype task adds the appropriate elements to the Info.plist file to associate a set of document file types with the application. This association means that this application:
It is important to note that these association are done by the operation system, your application must supply to proper code to handle the open document requires.
Also see Apple Developer Documentation on the CFBundleDocumentTypes key.
NB: You must use at least one of the attributes "extensions" or "ostypes". Both may, of course, be used.
Attribute | Description |
---|---|
name |
An application's unique name for this document type. For example, "Text Document" or
"Raw Data Document"
NB: Required attribute
|
extensions | A comma or space delimited string of filename extensions. Do not specify the leading period. To open documents with any extension, specify an extension with a single asterisk "*". |
ostypes | A comma or space delimited string of Mac OS types. Each value contains a four-letter type. To open documents of any type, include four asterisk characters "****" as the type code. These codes are equivalent to the legacy type codes used by Mac OS 9. Currently, OS Types with leading or trainling spaces or comma cannot be processed. |
icontype | Specifies the name of an icon file used to associate with this document type. This icon file is copied into the application bundle. These icons will be used for the document look if this application is associated as the default application for this document type use the Finder "Get info" command with the document. |
role |
This key specifies the application's role with respect to the type. The value can be
Editor, Viewer, Shell, or None. See
"Document Configuration"
for descriptions of these values.
NB: Required attribute
|
A minimal example might look like this
<jarbundler dir="release" name="MyApp" mainclass="org.foo.myapp.Main" jar="build/myapp.jar" />
This will create a Mac OS X application bundle called "MyApp.app" in the directory "release" using a JAR file which was created in the "build" directory.
You can use FileSets or FileLists for more complex builds. For example:
<jarbundler dir="release" name="MyApp 1.0" mainclass="org.foo.myapp.Main" > <jarfileset dir="${bin}"> <include name="**/*.jar" /> <exclude name="**/CVS" /> </jarfileset> </jarbundler>
A longer example with all the optional goodies will set the various Mac OS X native look-and-feel bells and whistles, copy in the appropriate Icon resource, and specify that the application requires JVM version 1.4 or the highest JVM available.
NB: Currently you must delete any existing applicaiton bundler before invoking the jarbundler task. This requirement will be relased in a future release of JarBundler.
<target name="complex" depends="jar, jni" description="Build an example application"> <delete dir="release/Hello World.app"/> <taskdef name="release/jarbundler" classname="net.sourceforge.jarbundler.JarBundler"/> <jarbundler dir="release" name="Hello World" shortname="Hello" signature="Helo" mainclass="net.sourceforge.jarbundler.example.HelloWorld" jar="build/Hello World.jar" icon="icons/Hello World.icns" jvmversion="1.4+" version="1.2" infostring="Hello World, 2006 MyCompany" build="213" bundleid="net.sourceforge.jarbundler.example.HelloWorld" helpbookfolder="HelpBook" helpbookname="Hello World Help" > <!-- Adjust the look, feel and behavior --> <javaproperty name="apple.laf.useScreenMenuBar" value="true"/> <javaproperty name="apple.awt.brushMetal" value="true"/> <javaproperty name="apple.awt.showGrowBox" value="false"/> <!-- Associate document types with this application --> <documenttype name="Hello World text document" extensions="txt text" ostypes="TEXT sEXT ttro" iconFile="icons/txt.icns" role="Editor"/> <documenttype name="Hello World HTML document" extensions="html htm" iconFile="icons/html.icns" role="Editor"/> <documenttype name="Hello World RTF document" extensions="rtf" role="Viewer"/> <!-- Just proving we can include a file. Might use it in the About box --> <resourcefilelist dir=".." files="LICENSE.TXT"/> <!-- Copy the HelpBook JNI library --> <javafilelist dir="./build" files="libHelpBookJNI.jnilib"/> <!-- Copy the HelpBook contents --> <resourcefileset dir="." includes="HelpBook/**/*.*/"/> </jarbundler>
Documentation for creating Apple Help Book support can be found here. Basically one needs to specify both the HelpBook directory name and the Help Book name. The application must also have a unique Bundle ID so that the Help Viewer can reference the application. The Help Book itself consists of pure HTML files, images, and optional CSS styling. This is easy to create and develop outside of the application. The "Hello, World" Help Book HTML can be used as a starter or checkout any application exiting Help Book folder now that you know where to find it.
The Help Book viewer does not automatcially open the file named index.html as does a web server. The root file must contain a META tag specifing the name AppleTitle. The content of this tag must match the value specified in the helpbookname attributer of the jarbundler task. This META tag is used to both designate the root HTML file and its content is used by the Help Viewer in its "Library" listing.
<html> <head> . . <meta name="AppleTitle" content="Hello World Help"/> . . </head>
Finally, one needs a JNI library to communicate between the "Help" menu item and the "Help Book Viewer" or whichever application is being used to render Help Book help. This is a very simple file and usage is demonstrated in the "Hello, World" example. Windows and Linux users will not be able to generate the JNI library on their platforms. I have any idea at this point how to generate a univeral binary for this library using command line. Feedback is welcome -- a technique using XCode is described here.
<jarbundler dir="${basedir}" name="${ant.project.name}" . . . bundleid="net.sourceforge.jarbundler.example.HelloWorld" helpbookfolder="HelpBook" helpbookname="Hello World Help" > <!-- Copy the HelpBook JNI library --> <javafilelist dir="${basedir}/build" files="libHelpBookJNI.jnilib"/> <!-- Copy the HelpBook contents --> <resourcefileset dir="${basedir}" includes="HelpBook/**/*.*/"/> </jarbundler>
During development the Help Viewer sometimes refuses to update the contents of a Help Book which changed. The Apple Developer Docs suggest to delete or edit the file ~/Library/Preferences/com.apple.help.plist. This file contains the list of known Help Books. If you double-click on this file the XML Property Editor applicaiton will be launched and re can 'delete' your bundle ID entry and "save" this file. Deleting this file does no harm but is a less elegant way to deal with the problem.
This document also suggests deleting the folder ~/Library/Caches/com.apple.helpui to help with refresh problem during development.
This Help Book creation technique should work for 90% of the Java applications desiring Help Book support. The nested tag <resourcefileset> can be used to move localized Help Books into their proper location. At some point a <helpbook> task may be added to facilitate deploying multilingual Help Books.
The stub file "JavaApplicationStub" is located inside of your application bundle in the subdirectory "Contents/MacOS/". It is used by the Mac OS X system to launch and the read the applications plist and launch the Java VM with the appropriate properties.
In early 2006 an Apple upgrade to Quicktime (7.0.4) caused older versions of "JavaApplicationStub" to fail to start up. These old versions came from developers who first created the application bundle as directory and then released their applications by replacing the JAR files within the bundle and not replacing "JavaApplicationStub" with a more current copy.
When run on OS X system, the JarBundler ANT task uses the current copy of the JavaApplicationStub from the developer's disk.
Creating a bundle with the your current copy of Java Launching Stub could lead to a future situation where the JavaApplicationStub file could become incompatible with a future OS X update.
Under Mac OS X one could replace the "JavaApplicationStub" file with a symbolic link to the user's current copy. This should guarentee that the end user would always be using a current copy of the stub file. I have used this technique on several versions of OS X and have not have had any reported problems with its use.
This is not yet an option of the JarBundler task but can be accomplished with the following lines of ANT code after building the bundle. NB: This will not work when building under Windows and is untested under Linux .
. . . </jarbundler> <!-- Delete the JavaApplicationStub and replace it with a symbolic link --> <!-- which should work on older and future versions of OS X --> <delete file="${release}/${name}.app/Contents/MacOS/JavaApplicationStub"/> <exec executable="ln"> <arg line="-s /System/Library/Frameworks/JavaVM.framework/Resources/MacOS/JavaApplicationStub"/> <arg value="${release}/${name}.app/Contents/MacOS/JavaApplicationStub"/> </exec> </target>
Windows and Linux users of this Ant task should obtain a copy the JavaApplicationStub file from a Mac OS X system and use the stubfile attribute in the jarbundler task.
Added <resourcefileset> and <resourcefilelist> nested elements, which mirror <execfileset> and <execfilelist>, and add files to the Contents/Resources directory.
Added build attribute to jarbundler task. See also version and infostring for usage.
Added jar attribute to jarbundler task.
Added shortname attribute to jarbundler task. See also name for usage.
JarBundler is now a SourceForge project!
Changed task package to net.sourceforge.jarbundler
Changed the package from 'com.loomcom.ant.tasks.jarbundler' to 'com.informagen.ant.tasks.jarbundler' so that version 1.4 can remain installed without conflict
Added a nested DataType called "javaproperty" so that new properties can be added by end users and deprecated properties can be removed. Former jarbundler tag atributes are still available but have been deprecated in favor of their 'javaproperty' equivalents.
Currently, a jarbundler tag attribute overrides a javaproperty tag. This was done to maintain backward compatibility with version 1.4
Fixed a bug that was causing application arguments not to be set.
Added "extraclasspath" attribute, and "extraclasspathfileset" and "extraclasspathfilelist" nested elements, allowing users to optionally add external resources to the runtime classpath which will not be copied into the application bundle at build time. Removed some Java 1.4 requirements to allow building the sources under Java 1.3. Clarified the documentation.
Added Ant property setters for "bundleid" and "developmentregion". Bundleid has no default, and is optional. Developmentregion defaults to "English", and is also optional. Fixed documentation on the website.
Fixed several minor bugs, and improved BuildException messages. Jarfilesets and execfilesets now preserve directory structure when copying. Thanks to Trevor Harmon for pointing out bugs and enhancements.
"execs" and "jars" can now be set using embedded FileSets or FileLists. Added a "verbose" flag, which currently sees limited use. Added "chmod" attribute, which can be used to point to a non-standard 'chmod' command (not normally needed!) Increased error checking. Hopefully, the code is now robust enough for widespread production use!
Added setter to properly support the "vmoptions" parameter. (Change submitted by Alok Saldanha)
Please contact Will Gilbert if you have bugs to report, patches to the code, ideas for enhancements, or any other suggestions! I can be reached at gilbert@informagen.com
The Jar Bundler Ant Task is Copyright © 2002 - 2004, Seth J. Morabito. All rights reserved.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.