7.3 Application Bundles
Native Mac OS X
applications are delivered in packages known as
application bundles. These
packages contain the application's executable code,
images, sounds, icons, localizable strings, and other resources. An
application, as shown in the Finder, is actually just a specific
directory structure with a few additional attributes.
These application bundles are displayed in the
Finder with a simple name (for
example, TextEdit). Users can double-click on these application
names, complete with colorful icons, and the system automatically
launches the application. Alternatively, users can drop documents on
the application, and the launched application will attempt to open
the selected document.
For a developer, however, an application bundle is a
directory with an
.app suffix and a specific
internal file structure. You can explore these bundles on your system
from the Finder by Control-clicking on an application and selecting
"Show Package Contents," as shown
in Figure 7-2.
7.3.1 Layout of an Application Bundle
Once you peel back the layers of an
application bundle, you'll find quite a few
directories, each with several files. Figure 7-3
shows the structure of a typical application bundle for a Java
application (in this case, the open source
Java application PCGen; for
more information on PCGen, visit http://sourceforge.net/projects/pcgen/).
 |
If you installed NetBeans according to the instructions in Chapter 2, you saw another example of an application
bundle.
|
|
The Info.plist
file in the Contents folder is probably the most
significant element of any Mac OS X application. For Java
applications, this file is used to specify information for the JVM
execution of the application.
Icons for the
Mac OS X Finder are placed in
the Resources folder. The
preferred format is the proprietary Mac OS X file type designated by
the .icns suffix, as this file type includes
support for different bit depths and icon sizes in a single file. Use
the
Icon Composer application
installed in /Developer/Applications to create icon files,
or investigate online for freeware and shareware tools that
accomplish the same task.
Your
Java code, in either JAR
or class files, is put into Resources/Java. A native executable file in
the MacOS folder launches the appropriate
classes. This native stub library, referenced by the Info.plist file, is the component that
actually launches the application.
While understanding all of these
steps is useful (especially in an automated build environment), a
couple of different tools allow you to set up and work with
application bundles without having to work through these details
manually. One tool, MRJAppBuilder, is included with
Apple's tool set. This chapter covers this tool in
more detail later.
7.3.2 Property List Attributes for Java Applications
Before digging into specific tools,
though, you need to understand the Info.plist file that keeps coming up. In
fact, by browsing through applications and various configuration
directories on Mac OS X, you'll notice the frequent
use of XML files with a .plist extension. These files are called
property lists, and can be edited easily with the bundled
Mac OS X Property List Editor (as shown
in Figure 7-4).
The Info.plist file in a
Mac OS X application's
Contents folder is no different
from these other property lists. While you can use tools to generate
these files, try to understand what was created for you and how to
modify the auto-generated files.
 |
Since the various .plist files
are in XML, you can modify them with any text
editor. The Property List Editor is generally a better option,
though, as it ensures that you maintain well-formed XML.
|
|
Example 7-2 shows an example property list for the SimpleEdit application created in
Chapter 4.
Example 7-2. Info.plist for SimpleEdit
<?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>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>text</string>
<string>txt</string>
<string>*</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>text/plain</string>
</array>
<key>CFBundleTypeName</key>
<string>Text File</string>
<key>CFBundleTypeOSTypes</key>
<array>
<string>****</string>
</array>
<key>CFBundleTypeRole</key>
<string>Editor</string>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>SimpleEdit</string>
<key>CFBundleIconFile</key>
<string>JavaApp.icns</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>0.1</string>
<key>Java</key>
<dict>
<key>Arguments</key>
<string>com.wiverson.macosbook.plugin.AquaPLAFPlugin
com.wiverson.plugin.BeepPlugin
com.wiverson.macosbook.plugin.FinderIntegrationPlugin
com.wiverson.macosbook.plugin.SystemPropsPlugin</string>
<key>ClassPath</key>
<string>$JAVAROOT/SimpleEdit.jar</string>
<key>MainClass</key>
<string>com.wiverson.macosbook.SimpleEdit</string>
<key>Properties</key>
<dict>
<key>com.apple.macos.use-file-dialog-packages</key>
<string>true</string>
<key>com.apple.macos.useScreenMenuBar</key>
<string>true</string>
<key>com.apple.macos.useSmallTabs</key>
<string>true</string>
<key>com.apple.mrj.application.apple.menu.about.name</key>
<string>SimpleEdit</string>
</dict>
</dict>
</dict>
</plist>
7.3.2.1 About dictionaries
This
property
list is divided into hierarchical dictionaries.
The top-level dictionary contains the information that the
operating system needs to launch
the application. The keys in this section are prefixed by
CFBundle and are more or less self-explanatory.
One exception is
CFBundleDocumentTypes
, which tells the system that this particular
application will open any file as a text document by default.
Identifying files
in this manner lets users drag and drop files on your
application's icon, either in the Finder or the
Dock. You'll want to create a new file type and
extension if you want to handle custom data file types. Finally, you
should set the proper options for the Java
dictionary.
7.3.2.2 CFBundle dictionary keys
Per Apple's
documentation (installed
at /Developer/Documentation/Essentials/SystemOverview/PropertyListKeys/Bundle_Keys.html),
the keys in Table 7-1 are used to build Java
applications. The comments shown below are based on
Apple's documentation. Keys not used by Java
applications have been omitted.
Table 7-1. CFBundle dictionary keys
|
CFBundleDevelopmentRegion
|
String
|
No
|
The native region for the bundle. Usually corresponds to the
author's native language.
|
|
CFBundleDisplayName
|
String
|
No
|
The bundle's localized display name.
|
|
CFBundleDocumentTypes
|
Array
|
No
|
An array of dictionaries describing the document types supported by
the bundle. For more information, see the next section.
|
|
CFBundleExecutable
|
String
|
Yes
|
Name of the bundle's executable file.
|
|
CFBundleGetInfoHTML
|
String
|
No
|
A string for displaying richer (HTML) content in the
Finder's "Get
Info" panel.
|
|
CFBundleGetInfoString
|
String
|
No
|
A string for display in the Finder's
"Get Info" panel.
|
|
CFBundleIconFile
|
String
|
Yes
|
The filename for an icon image file.
|
|
CFBundleIdentifier
|
String
|
Yes
|
A unique identifier string for the bundle. This string should be in
the form of a Java package name, such as
com.apple.myapp.
|
|
CFBundleInfoDictionaryVersion
|
String
|
Yes
|
Version information for the Info.plist format.
|
|
CFBundleName
|
String
|
Yes
|
The short display name of the bundle. Should be less than 16
characters.
|
|
CFBundlePackageType
|
String
|
Yes
|
The four-letter code identifying the bundle type. For applications
(including Java applications) you should set this value to
"AAPL".
|
|
CFBundleShortVersionString
|
String
|
Yes
|
The marketing-style version string for the bundle
|
|
CFBundleSignature
|
String
|
Yes
|
The four-letter code identifying the bundlecreator.
|
|
CFBundleVersion
|
String
|
Yes
|
The executable's build number.
|
7.3.2.3 CFBundleDocumentTypes dictionary keys
Per Apple's
documentation (installed at /Developer/Documentation/Essentials/SystemOverview/PropertyListKeys/Bundle_Keys.html),
the keys in Table 7-2 describe the kinds of
documents that your application supports.
Table 7-2. CFBundleDocumentTypes dictionary keys
|
CFBundleTypeExtensions
|
Array
|
This key contains an array of filename extensions that map to this
type. To open documents with any extension, specify an extension with
a single asterisk (*). This key is required.
|
|
CFBundleTypeIconFile
|
String
|
This key specifies the name of the icon file to be used when
displaying documents of this type. The icon filename can have an
extension or be without one. If it is without an extension, the
system appends an extension appropriate to the platform (for example,
.icns in Mac OS 9).
|
|
CFBundleTypeName
|
String
|
This key contains the abstract name for the document type and is used
to refer to the type. This key is required and can be localized by
including it in the corresponding InfoPlist.strings files. This value is the
main way to refer to a type, and it is recommended that you use a
Java-style package identifier to ensure its uniqueness. If the type
is a common Clipboard type supported by the system, you can use one
of the standard types listed in the NSPasteboard
class description.
|
|
CFBundleTypeOSTypes
|
Array
|
This key contains an array of four-letter type codes that map to this
type. To open documents of any type, specify the four-letter type
code `****'. This key is required.
|
|
CFBundleTypeRole
|
String
|
This key specifies the application's role with
respect to the type. The value can be Editor, Viewer, Printer, Shell,
or None. This key is required.
|
Generally, most Mac OS X Java applications work with
document types based on file
extension (as opposed to the four-letter creator codes), as file
extensions survive cross-platform exchange. Therefore, to support a
launch of your application types, register the
file extensions that your
application supports (for example, .txt, .gif, .jpg, and .jpeg). It's usually best to
err on the side of supporting a larger variety of document file
extensions and file types for the purposes of receiving Finder
notifications (relying on the wildcard options above). Then you
should perform error checking on the data files from within your
application.
 |
For more information on how your Java application is notified of
opening files, see Chapter 5.
|
|
7.3.2.4 Java dictionary keys
At the end of the
CFBundle keys, a Java key
designates the beginning of the Java dictionary. Two top-level keys
in the Java dictionary are required in the property list of a Java
application bundle:
- MainClass
-
This key
value should be set to the fully qualified class name of the
application's main entry method. The value of this
key can be retrieved at runtime by querying the
com.apple.mrj.application.main system property.
- ClassPath
-
This key
lets you set the classpath for your application. The string value for
this key should specify the fully qualified path to the directories
where your class files are, or to your JAR files.
You'll note the use of the
$JAVAROOT variable to point to the Resources/Java directory. If your application
bundles third-party JAR files, you'll want to
include them here and reference them with the
$JAVAROOT variable. You can discover this value by
querying the
com.apple.mrj.application.classpath system property.
In addition to these required keys, you may wish to specify
additional keys in the Java dictionary:
- Arguments
-
This value is tokenized into a
String array, and passed into the
application's main(
) method. This can be a
convenient way to package applications that expect specific
command-line arguments. This value can be introspected through the
com.apple.mrj.application.parameters system property.
- WorkingDirectory
-
When an application is launched,
this key sets the working directory. By default, the current working
directory is set to the application bundle's parent
directory. You can use the
$APP_PACKAGE variable to refer to the root of the
application bundle. The value of this key is available via
introspection through the
com.apple.mrj.application.workingdirectory system property.
 |
You may prefer to use the standard Java
APIs for determining the user's home and working
directory. This has the added flexibility of adapting to changes the
user makes to the working directory while the application is running.
|
|
- VMOptions
-
The space-delimited value of the
VMOptions key can set the JVM options normally referred to
by the -X and -XX options. The
typical use of this key is to set the minimum and maximum heap size
for the JVM launching the application. Your application can read this
value by looking at the
com.apple.mrj.application.vm.options system
property.
- JVMVersion
-
This can be used to specify either a
specific version of the JVM to use (e.g.,
"1.3.1" or
"1.4.1") or the latest version in a
series (e.g., "1.3+" or
"1.4+"). Note that even if the user
has installed JDK 1.4.1, your application will default to the latest
JDK 1.3 JVM.
 |
This means that if you are building an application that requires JDK
1.4.1 or later, be sure to include the JVMVersion key!
|
|
7.3.2.5 The Properties dictionary
The keys in the Properties dictionary
include both Mac OS X-specific options and general Java options. Mac
OS X-specific keys and values that you may add to this dictionary of
the property list include:
-
com.apple.hwaccel
-
This property defaults to
true. It turns on hardware graphics acceleration
for the video cards not commented out of the /Library/Java/Home/lib/hwexclude.properties
file. If it is set to false, hardware acceleration
is turned off. You can use it in conjunction with the
com.apple.hwaccelexclude property.
- com.apple.hwexclude
-
This
property
defaults to none. When specific video card
designation strings are passed in with this property, hardware
graphics acceleration is not turned on for the
specified video cards. When this property is set, /Library/Java/Home/lib/hwexclude.properties
is ignored.
 |
This property is useful when you know that specific video cards
(hopefully just one or two) cause problems with your application when
hardware acceleration is turned on. You are testing for this, right?
|
|
- com.apple.macos.use-file-dialog-packages
-
This property defaults to
false. When set to true, it
causes
java.awt.FileDialog to
show application packages (with both .app and .pkg extensions) as if they were files,
prohibiting the user from selecting specific files inside the
application bundle. This option is not available for use on JDK
1.4.1.
- com.apple.macos.useScreenMenuBar
-
This
property defaults to false. Setting it to
true causes Swing menus that use the Aqua look and
feel to appear in the global application menu bar at the top of the screen
(instead of inside the window). This is the proper behavior for Mac
OS X applications, but may require some testing before your
application supports it properly. Note that
JMenuBars in JDialogs are
not moved to the Mac OS X menu bar. Under JDK
1.4.1, use
apple.laf.useScreenMenuBar instead. Note that you can include
both properties with no ill effects.
- com.apple.macos.smallTabs
-
This
property
is not defined by default. If defined and set to
true, tab controls in Swing applications more
closely resemble the Metal look and feel (which can be very helpful
if your application expects smaller tabs). If the property is set to
false, the tabs assume a larger size that is
similar to the default Aqua controls. This option is not available
for use on JDK 1.4.1.
- com.apple.macosx.AntiAliasedTextOn
-
This
property
defaults to true. When rendering text, it tells
the application to use anti-aliasing. Occasionally you might want to
switch this value to false. If your application
draws text to the same location twice, it can look blurry, as each
application of the text to the screen is incrementally darker.
Conversely, if your application expects to erase text by drawing the
background color over previously rendered text, anti-aliasing
artifacts can be left over. Under
JDK 1.4.1, use
apple.awt.textantialiasing instead (as described
in the next section). Note that you can include both properties with
no ill effects.
- com.apple.macosx.AntiAliasedGraphicsOn
-
This
property
also defaults to true. Like the potential issues
around anti-aliased text, the default Mac OS X rendering of graphics
can lead to blurry graphics. You may see a small performance increase
by setting this property to false.
- com.apple.mrj.application.apple.menu.about.name
-
If
defined, this property adds an "About"
command to the top of the application menu. Your application can be
notified when the user selects this menu item by registering a
com.apple.mrj.AboutHandler,
as described in Chapter 5.
- com.apple.mrj.application.growbox.intrudes
-
This
property defaults to true and causes a
growbox (a
resizing control) to intrude into AWT frames. For certain
applications, this growbox can obscure other important GUI features,
such as scrollbars. If turned off (by setting the value to
false), the bottom of the window is pushed down 15
pixels. Setting this value to false is appropriate
only as an intermediate stopgap梱ou are strongly encouraged to
rework your application's user interface so the
growbox control looks natural and doesn't block
other important controls. Under JDK 1.4.1, use
apple.awt.showGrowBox instead. Note that you can
include both properties with no ill effects.
- com.apple.mrj.application.live-resize
-
This
property defaults to
false, but setting it to true
enables
live resizing of windows. You should test
this property on a variety of machines (and perhaps make it a
user-configurable preference), as the performance of live window
resizing for your application can vary dramatically between different
systems and JVMs. This option is not available for use on JDK 1.4.1.
- apple.awt.brushMetalLook
-
Allows
you to specify that your main application window should use the
brushed Metal appearance, similar to that
used by Apple applications such as iTunes and Safari. This is set to
false by default. It is available only on JDK 1.4.1.
7.3.2.6 JDK 1.4.1 rendering
JDK 1.4.1 introduces more sophisticated
control over rendering via Java 2D. For more information on
Java 2D, examine the
standard Java documentation on
java.awt.Graphics2D
. In the section below,
references are made to various rendering hints via settings such as
KEY_ANTIALIASING and
KEY_TEXT_ANTIALIASING梩hese are references
to the Java 2D APIs.
The following properties are available only when using JDK 1.4.1 or a
later JVM.
-
apple.awt.antialiasing
-
Specifies that standard
graphic primitives (such as line, arc, rectangle, etc.) are drawn
anti-aliased. By default, text will also take this setting, but you
can override that using
apple.awt.textantialiasing. You can override this
setting via the KEY_ANTIALIASING rendering hint
for specific objects. By default this is set to false for Metal
applications, and to true for Aqua applications. Even if it is set to
false, standard Aqua user interface components will still be drawn
anti-aliased.
- apple.awt.textantialiasing
-
Sets the default Java 2D rendering
hint for KEY_TEXT_ANTIALIASING. Although this
inherits the same setting as
apple.awt.antialiasing, you can override that
setting explicitly. The default value is false unless you are using
the Aqua look and feel.
-
apple.awt.rendering
-
Determines whether Graphics 2D objects
prioritize speed or quality. It sets the Java 2D hint
KEY_RENDERING so that it accepts either
VALUE_RENDER_SPEED or
VALUE_RENDER_QUALITY as an argument.
- apple.awt.interpolation
-
Allows you to set the Java 2D
KEY_INTERPOLATION rendering hint to determine
which algorithm is used in image transformations. Options include
VALUE_INTERPOLATION_NEAREST_NEIGHBOR,
VALUE_INTERPOLATION_BILINEAR, and
VALUE_NTERPOLATION_BICUBIC.
-
apple.awt.fractionalmetrics
-
Allows you to specify that the Java 2D
KEY_FRACTIONALMETRICS hint should use
floating-point font metrics instead of the default integer metrics.
Options include VALUE_FRACTIONALMETRICS_ON and
VALUE_FRACTIONALMETRICS_OFF.
7.3.2.7 JDK 1.4 full screen display
JDK 1.4 introduces the ability
to run your application in "full
screen" mode, where the application takes over the
entire screen, hiding default user interface elements such as the
menu bar. This can be particularly useful for such applications as
kiosk displays and games.
- apple.awt.fakefullscreen
-
This flag causes full screen
applications to be displayed in a window. You may wish to make this a
user preference, or use it to assist with debugging. The default
value is false.
- apple.awt.fullscreencapturealldisplays
-
When
you have multiple displays, entering
full screen mode darkens any secondary screens that might be attached
to the system. Setting this to false overrides this default behavior
so that secondary screens are not darkened (allowing you to still see
the content displayed, such as debugging output or logs). The default
value is true.
- apple.awt.fullscreenhidecursor
-
Hides the mouse cursor when in full
screen mode. Many entertainment applications, such as games, may wish
to hide the mouse. The default value is true.
- apple.awt.fullscreenusefade
-
Mac
OS X automatically provides a
"fade" effect when changing screen
resolutions. You may find it more aesthetically pleasing to see this
fade effect whenever you switch to full screen mode, even if you
don't initiate a resolution change. To do this, set
this property to true instead of the default value of false.
7.3.2.8 JDK 1.4 window positioning
In the
JDK 1.4 release, Apple provides
additional functionality to assist with window positioning. This is
particularly useful for when you store the current window position,
and the user changes the screen to a smaller resolution梩he
window may no longer appear on screen! This functionality is
controlled via the following properties:
-
apple.awt.window.position.forceSafeCreation
-
New
windows are always created on screen, not outside the desktop where
users would not be able to access them. The default value is false.
- apple.awt.window.position.forceSafeUserPositioning
-
This
option disallows users from moving windows into a position where they
would no longer be able to access them. The default value is false.
You can test any of these options from the command line by using the
-D option to the
java
command. For example, if you want to run an application with standard
Aqua menu styles and the name
"SimpleEdit", you could pass in two
keys, com.apple.macos.usescreenmenubar and
com.apple.mrj.application.apple.menu.about.name,
as shown here:
java -Dcom.apple.macos.useScreenMenuBar=true
-Dcom.apple.mrj.application.apple.menu.about.name=SimpleEdit
com.wiverson.macosbook.SimpleEdit
If you get the results that you expect, you can then add these two
properties into your Properties dictionary in the Info.plist file. Using the
-D option allows you to test options quickly
before editing your property lists.
7.3.3 Why Use Application Bundles?
Using double-clickable JAR files is easy,
so why bother with application bundles? Bundles require a lot of
properties to be set, and it takes time to get used to property
lists. However, you can benefit from packaging your application as a
Mac OS X application bundle:
The application launches on a double-click (as a JAR file would).
The application becomes a single, self-contained structure that is
portable across different filesystems.
You can optionally specify a custom icon to appear in the Dock and
the Finder.
You can set specific system properties to more closely emulate the
behavior of a native application.
You can bind specific document types to the application. The Finder
keeps track of which applications can open which documents and
document types, which lets users double-click on a document in the
Finder to open your application, drag and drop a document on your
application, or use the "Open With"
command in the Finder.
 |
To take full advantage of document type bindings, implement the
document event handlers in your application as described in Chapter 5.
|
|
You can set specific configuration and runtime details that would
otherwise require the user to enter a complex command-line command
(such as memory configuration or default file encoding).
|