To run SWT on OSX you must start the JVM with the command line argument -XstartOnFirstThread. However, there is no way to specify this argument from a JAR file. Instead, you must package your JAR as a proper OSX application. Some information about how to do this is available on other sites.
However, neither of these articles contained a complete working ant build file to automate the process and allow OSX packaging to be run on other operating systems. This article is intended to fill that gap.
We are going to do something special for OSX so the first step is to build separate jars for Windows/Linux and OSX.
<!-- Package cross platform SWT Jar (Windows/Linux) --> <swtjar jarfile="./build/jars/ui.jar" targetmainclass="org.project.gui.ProjectGUI" swtversion="3.6.2"> <!-- Application Classes --> <fileset dir="./build/classes" includes="**/*.class" /> <!-- Library Classes --> <zipfileset excludes="META-INF/*.MF" src="lib/miglayout-18.104.22.168-swt.jar"/> <!-- SWT Jars (Windows/Linux) --> <fileset dir="./lib" includes="swt-lin*-3.6.2.jar" /> <fileset dir="./lib" includes="swt-win*-3.6.2.jar" /> </swtjar> <!-- Package OSX SWT Jar --> <swtjar jarfile="./build/jars/ui-osx.jar" targetmainclass="org.project.gui.ProjectGUI" swtversion="3.6.2"> <!-- Application Classes --> <fileset dir="./build/classes" includes="**/*.class" /> <!-- Library Classes --> <zipfileset excludes="META-INF/*.MF" src="lib/miglayout-22.214.171.124-swt.jar"/> <!-- SWT Jars (OSX) --> <fileset dir="./lib" includes="swt-osx*-3.6.2.jar" /> </swtjar>
OSX applications are packaged into folders with names ending in ".app". The contents of the folder have a very particular structure and include an Info.plist file which is where the -XstartOnFirstThread argument can be specified.
Thankfully, there is a free ant task which automated the process of building the .app folder: JarBundler
To use this task, you need to add the following at the top of your build.xml file.
<taskdef name="jarbundler" classname="net.sourceforge.jarbundler.JarBundler" classpath="./lib/jarbundler-2.2.0.jar"/>
The task can then be invoked as follows.
<mkdir dir="./build/jar/UIApp/" /> <jarbundler dir="./build/jar/UIApp/" name="UI" mainclass="org.swtjar.SWTLoader" jar="./build/jars/ui-osx.jar" startOnMainThread="true" icon="./icons/ui128.icns" stubfile="./lib/JavaApplicationStub" />
There are several things to note about these parameters.
You now have a .app folder which could be used to correctly launch your SWT UI on OSX. However, it isn't very practical to distribute a folder so there is one more step to package this up.
The correct way to do this would be to package the .app folder as an OSX "Disk Image". However, I could not find a way of doing this packaging on any platform apart from OSX. Therefore, I chose to simply package the folder in a .tar file. Using tar instead of zip is a deliberate choice as tar files allow permissions to be stored to ensure the .app folder is executable after being untarred.
Here is the ant build.xml code.
<delete file="./build/jar/UIApp/UI.app/Contents/MacOS/JavaApplicationStub" /> <mkdir dir="./build/jar/UILauncher/UI.app/Contents/MacOS/" /> <copy file="./lib/JavaApplicationStub" todir="./build/jar/UILauncher/UI.app/Contents/MacOS/" /> <tar destfile="./build/jars/UI.app.tar"> <tarfileset dir="./build/jars/UIAppLauncher/" filemode="777" /> <tarfileset dir="./build/jars/UIApp/" /> </tar>
This is doing the following.
And thats it - you now have a single file UI.app.tar which can be distributed to OSX users.