Deploying a Java Application As a Native Mac
Articles —> Deploying a Java Application As a Native Mac
While java applications are renowned for being platform independent, there are many platform dependent intricacies not accounted for when deploying a packaged application. Deploying a runnable java application requires packaging the java application in an runnable jar. On an apple macintosh computer, these show up looking similar to files, often with a oracle java emblem indicating the java runtime environment is needed to run the jar. This prevents a java application from having not only a custom icon, but also several other mac specific look, feel, and operational items. These include receiving notifications from the OS when a user opens a file specific to your java application, apple macintosh specific user interface guidelines, and implementing standard menu items which are often apple specific (such as Preferences and About menu's).
Packaging your application
Native apple macintosh applications are packaged as 'bundles', which underneath the hood is simply a directory structure containing application specific code and preferences. Creating these bundles by hand can be time consuming, fortunately applications exist to do it for you. I have used Jarbundler with success. Applications such as these allow you to
- Associate an icon to your application
- Associate icons to files your application creates
- Pass command line arguments to your application
- Provide a help book
- And much more...
Apple macintosh OS notifications
Apple provides several default operating system features, such as custom preferences, help, and about menus, notifications to open files, etc...Responding to these notifications can be performed by using the classes and implemented methods in the com.apple.eawt package, which should come standard with mac java runtime environment installs. Some basic interfaces available include:
- OpenFileHander: Interface which receives notifications when a file associated with the application should be opened.
- PreferencesHandler: Notified when the preferences menu item has been selected.
- QuitHandler: Notified when the user has selected the Quit menu item.
Look and Feel
Apple defines several standard rules and guidelines which deployed applications should abide by but which at this time java standard deployments do not follow. These include menu bar placement (mac menu bars are placed at the top of the screen, whereas windows/java are at the top of a window), window growbox placement, etc...These features can be changed by setting specific system properties using the System.properties static method. Some of the most important features include:
- apple.laf.useScreenMenuBar: when set to true and operating on a mac operating system, the system places the menu bar at the top of the screen.
- com.apple.mrj.application.growbox.intrudes: when set to false, the window growbox allows a slight border around components placed at the bottom right edge of the window so the growbox does not intrude on these components
File Dialogs
The java swing JFileChooser has its own look and feel which differs quite a bit from the standard Mac open/save dialogs. However, the java AWT class FileDialog looks and feels just like a native file chooser dialog. Until the look and feel of the JFileChooser matches that of the native mac system, mac deployments are stuck using a FileDialog.
Commands
Commands - typically control-* - specify shortcuts to particular actions associated with the keystrokes. On Windows, the keystrokes can be set along with the InputEvent.CTRL_MASK value. On an apple macintosh this value is different: InputEvent.META_MASK. A more maintainable method to accomplish this is to use the Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() method.
Memory Management
I have run into memory issues on some versions of apple's OS X. Long work tracked these issues down to Swing components not being garbage collected. The fix I found was to manually remove all components when a JFrame is disposed.
@Override public void dispose(){ customDisassemble(getContentPane()); super.dispose(); } private void customDisassemble(Container c){ Component[] children = c.getComponents(); for ( Component co : children ){ if ( co instanceof Container ){ Container con = (Container)co; customDisassemble(con); } c.remove(co); } }
Knowing your OS
Some properties need to be programmatically set (for instance the apple.laf.useScreenMenuBar property discussed above) but are operating system dependent, so how do you determine if your software is currently running on an apple computer at runtime? The System class, in particular its getSystemProperty() method provides ways to access properties of the system. In particular, the 'os.name' property returns the name of the operating system. Simply check this value for the presence of the word 'mac' to see if the code is running on a mac computer. Useful to set mac specific properties at Runtime.
Useful links:
Oracle: packaging a Java App for Distribution on a Mac
Apple: Java development Guide for Mac
There are no comments on this article.