Mchr3k - SWTJar

Home

SWTJar is a tool for easily packaging SWT Java applications into a single cross platform Jar.

Download swtjar.jar

The Problem

SWT is a Java widget toolkit that provides access to native UI elements. This presents a problem when it comes to packaging an application as you need to include a different SWT jar for each platform (Windows/Linux/OSX)/(32/64bit). To support all of these standard platforms you have to build and distribute 6 different packages which isn't really in the spirit of Java's write once, run anywhere.

Assuming you use ant to build your code, here is what the traditional solution looks like (showing only 32/64 bit Windows build commands).

<!-- 32 bit windows UI -->
<jar jarfile="./build/jars/ui-win32.jar">
  <fileset dir="./build/classes" includes="**/*.class" />
  <zipfileset excludes="META-INF/*.MF" src="lib/miglayout-3.7.3.1-swt.jar"/>
  <fileset dir="./lib" includes="swt-win32-3.6.2.jar" />
</jar>
<!-- 64 bit windows UI -->
<jar jarfile="./build/jars/ui-win32.jar">
  <fileset dir="./build/classes" includes="**/*.class" />
  <zipfileset excludes="META-INF/*.MF" src="lib/miglayout-3.7.3.1-swt.jar"/>
  <fileset dir="./lib" includes="swt-win64-3.6.2.jar" />
</jar>

This is really verbose and leaves you with more files to manage and distribute - Surely there is a better way?

The Solution

SWTJar is an ant task which allows you to build a single jar which loads the correct SWT classes at runtime allowing you to distribute a single jar which works across (Windows/Linux/OSX)/(32/64bit).

Lets take a look at what this looks like in your ant built script.

First you need to declare the new ant task at the top of your build.xml file.

<taskdef name="swtjar" classname="org.swtjar.ant.SWTJarTask"
                       classpath="./lib/swtjar.jar"/>

Here is an example of using swtjar.

<!-- Package cross platform SWT Jar -->
<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-3.7.3.1-swt.jar"/>
  
  <!-- SWT Jars -->
  <fileset dir="./lib" includes="swt-*-3.6.2.jar" />
</swtjar>

There are a few things to note about the swtjar task.

  • targetmainclass - this should be the class with the public static void main(String[] args) entry point
  • swtversion - all the SWT jars you are using must have filenames of the format swt-<platform><bitness>-<version>.jar
    • <platform> - Must be one of win/linux/osx.
    • <bitness> - Must be one of 32/64.
    • <version> - Any string - must match the swtversion param used in the swtjar command.

How It Works

The key problem which the SWT library presents is that it requires a platform specific classpath. SWTJar implements this by including a standard loader class which performs platform detection and then constructs a Classloader which will load the correct SWT classes.

Limitations

On Windows, jar files can normally be launched by double clicking them but this may not work if another application has been installed which has registered itself as the default handler for jar files. In this case the user will have to launch the jar explicitly using the following command.

java -jar ui.jar

On Linux, jar files can normally be launched by double clicking them.

On OSX an SWT UI requires an extra command line argument to launch correctly. The user must start the UI from the command line using the following command.

java -XstartOnFirstThread -jar ui.jar

To work around this issue you can perform some further OSX specific packaging as described on this page: Packaging SWT for OSX

Credits

Alexey Romanov came up with the approach used by this tool. The details of his approach are described in his StackOverFlow answer.

Ferenc Hechler created the Jar in Jar Classloader which is packaged in this tool. See this Eclipse bug for the original details about this addition.