Create cross platform Java SWT Application

mchr picture mchr · Apr 24, 2010 · Viewed 28.3k times · Source

I have written a Java GUI using SWT. I package the application using an ANT script (fragment below).

<jar destfile="./build/jars/swtgui.jar" filesetmanifest="mergewithoutmain">
  <manifest>
    <attribute name="Main-Class" value="org.swtgui.MainGui" />
    <attribute name="Class-Path" value="." />
  </manifest>
  <fileset dir="./build/classes" includes="**/*.class" />
  <zipfileset excludes="META-INF/*.SF" src="lib/org.eclipse.swt.win32.win32.x86_3.5.2.v3557f.jar" />
</jar>

This produces a single jar which on Windows I can just double click to run my GUI. The downside is that I have had to explicitly package the windows SWT package into my jar.

I would like to be able to run my application on other platforms (primarily Linux and OS X). The simplest way to do it would be to create platform specific jars which packaged the appropriate SWT files into separate JARs.

Is there a better way to do this? Is it possible to create a single JAR which would run on multiple platforms?

Answer

Alexey Romanov picture Alexey Romanov · Jul 8, 2010

I've just run into the same problem. I haven't tried it yet, but I plan to include versions of swt.jar for all platforms and load the correct one dynamically in the start of the main method.

UPDATE: It worked. build.xml includes all jars:

<zipfileset dir="/home/aromanov/workspace/foo/lib" includes="swt_linux_gtk_x86.jar"/>
<zipfileset dir="/home/aromanov/workspace/foo/lib" includes="swt_macosx_x86.jar"/>
<zipfileset dir="/home/aromanov/workspace/foo/lib" includes="swt_win32_x86.jar"/>
<zipfileset dir="/home/aromanov/workspace/foo/lib" includes="swt_linux_gtk_x64.jar"/>
<zipfileset dir="/home/aromanov/workspace/foo/lib" includes="swt_macosx_x64.jar"/>
<zipfileset dir="/home/aromanov/workspace/foo/lib" includes="swt_win32_x64.jar"/>

and my main method starts with calling this:

private void loadSwtJar() {
    String osName = System.getProperty("os.name").toLowerCase();
    String osArch = System.getProperty("os.arch").toLowerCase();
    String swtFileNameOsPart = 
        osName.contains("win") ? "win32" :
        osName.contains("mac") ? "macosx" :
        osName.contains("linux") || osName.contains("nix") ? "linux_gtk" :
        ""; // throw new RuntimeException("Unknown OS name: "+osName)

    String swtFileNameArchPart = osArch.contains("64") ? "x64" : "x86";
    String swtFileName = "swt_"+swtFileNameOsPart+"_"+swtFileNameArchPart+".jar";

    try {
        URLClassLoader classLoader = (URLClassLoader) getClass().getClassLoader();
        Method addUrlMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
        addUrlMethod.setAccessible(true);

        URL swtFileUrl = new URL("rsrc:"+swtFileName); // I am using Jar-in-Jar class loader which understands this URL; adjust accordingly if you don't
        addUrlMethod.invoke(classLoader, swtFileUrl);
    }
    catch(Exception e) {
        throw new RuntimeException("Unable to add the SWT jar to the class path: "+swtFileName, e);
    }
}

[EDIT] For those looking for the "jar-in-jar classloader": It's included in Eclipse's JDT (the Java IDE built on Eclipse). Open org.eclipse.jdt.ui_*version_number*.jar with an archiver and you will find a file jar-in-jar-loader.zip inside.