Due to the implementation mechanism of SWT, different swt*.jar must be referenced under different platforms. Because of this bottleneck, we want to compile different versions for different platforms. But this can be avoided. This is what this article will discuss.
I have Google to 3 kinds of solution:
1, use Swtjar.jar.
http://mchr3k.github.io/swtjar/
Its homepage is described in detail. But it seems that the download link is invalid, and one way to download it is to find a project that references it from GitHub, such as https://github.com/mchr3k/org.intrace/tree/ 3a1debcbb831f802219b341fb5e37467b365d443/org.intrace/lib
The principle of swtjar.jar seems to be achieved by replacing the default ClassLoader.
According to my test, using the Swtjar.jar scheme, if referenced to JFace, there is no way to successfully load JFace classes. Cause I'll talk about it later.
2, http://sourceblogger.googlecode.com/svn/trunk/multiplatform-swt-loader/src/main/java/com/github/jendap/ Multiplatformswt/loader/multiplatformswthelper.java
I've read the code, but I haven't tried it, it looks complicated, but it seems to be very functional and interesting to read.
3,http://stackoverflow.com/questions/2706222/create-cross-platform-java-swt-application
This program is the simplest and most obvious, this article mainly introduces this program
In fact, the 3 scenarios are essentially the same, swt*.jar all the platforms into the program and then dynamically load the corresponding Swt*.jar based on the OS and CPU architecture information
The Third kind of solution
The third kind of solution that we want to introduce is, in the Load class phase, not load Swt*.jar. Instead, defer to the main function execution phase, and then "manually" load the correct swt*.jar based on the OS and CPU architecture
1) First add the following methods
Private Static void Loadswtjar () {
String swtfilename= "";
Try {
String osname = System. GetProperty ("Os.name"). toLowerCase ();
String Osarch = System. GetProperty ("Os.arch"). toLowerCase ();
Final ClassLoader Parentclassloader = Thread. CurrentThread (). Getcontextclassloader ();
Method Addurlmethod = URLClassLoader. class. Getdeclaredmethod ("Addurl", URL. Class);
Addurlmethod.setaccessible (true);
String Swtfilenameospart =
Osname.contains ("Win")? "Win32.win32":
Osname.contains ("Mac")? "Cocoa.macosx":
Osname.contains ("Linux") | | Osname.contains ("Nix")? "Gtk.linux":
""; throw new RuntimeException ("Unknown OS Name:" +osname)
String Swtfilenamearchpart = Osarch.contains ("64")? "x86_64": "x86";
Swtfilename = "ORG.ECLIPSE.SWT." +Swtfilenameospart+ "." +swtfilenamearchpart+ " -4.4.jar";
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 (Parentclassloader, Swtfileurl);
}
Catch (Exception e) {
System. out. println ("Unable to add the SWT jar to the class path:" +swtfilename);
E.printstacktrace ();
}
}
The function is to "manually" load the correct Swt*.jar file according to the OS and CPU architecture information.
(The above code in the debugging environment may not be able to run correctly, you need to add a sentence at the beginning:
Url.seturlstreamhandlerfactory (New Rsrcurlstreamhandlerfactory (Parentclassloader));
But when you compile with ant, you have to remove the sentence. Because Ant compiles the code, Rsrcurlstreamhandlerfactory has been set to the URL, and the duplicate settings will be out of the ordinary. I'm not going to go into it for specific reasons.)
2) Add Jar-in-jar-loader.jar Reference.
Find Org.eclipse.jdt.ui_*version_number*.jar in Eclipse's plugins directory, unzip it, Discover Jar-in-jar-loader.zip, Rename to Jar-in-jar-loader.jar. Put it in the project's Lib directory and refer to it.
The reason to add this jar is that the Loadswtjar method implicitly uses the Jarrsrcloader.class and related classes in it.
3) Add the Loadswtjar () call at the beginning of the main function.
4) Modify the Build.xml file.
Yes, you need a build.xml file, and if not, build one with Eclipse's export jar feature. There are 2 main purposes for modifying the Build.xml file: 1 is to remove Swt*.jar from the default load list, and 2 to put the Swt*.jar of all the platforms in the package list. One plus one minus. Give an example:
<?xml version= "1.0" encoding= "UTF-8" standalone= "no"?>
<project default= "Create_run_jar" name= "Create Runnable jar for Project Swtguiexample with Jar-in-jar Loader" >
<!--This file is created by Eclipse Runnable JAR Export wizard-->
<!--ANT 1.7 is required
-
<target name= "Create_run_jar" >
<jar destfile= "/home/binhua/desktop/bin/swtguiexample.jar" >
<manifest>
<attribute name= "Main-class" value= "Org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader"/>
<attribute name= "Rsrc-main-class" value= "swtguiexample. Main "/>
<attribute name= "Class-path" value= "." />
<attribute name= "Rsrc-class-path" value= "./Jar-in-jar-loader.jar Org.eclipse.equinox.common-3.6.100.v20120522-1841.jar Org.eclipse.core.commands-3.6.1.v20120521-2329.jar Org.eclipse.osgi-3.8.0.v20120529-1548.jar "/>
</manifest>
<zipfileset src= "Lib/jar-in-jar-loader.jar"/>
<fileset dir= "/home/binhua/desktop/code/swtexample/src/swtguiexample/target/classes"/>
<zipfileset dir= "/home/binhua/.m2/repository/org/eclipse/swt/org.eclipse.swt.gtk.linux.x86_64/4.4" includes= " Org.eclipse.swt.gtk.linux.x86_64-4.4.jar "/>
<zipfileset dir= "/home/binhua/.m2/repository/org/eclipse/swt/org.eclipse.swt.gtk.linux.x86/4.4" includes= " Org.eclipse.swt.gtk.linux.x86-4.4.jar "/>
<zipfileset dir= "/home/binhua/.m2/repository/org/eclipse/swt/org.eclipse.swt.cocoa.macosx.x86_64/4.4" includes= "Org.eclipse.swt.cocoa.macosx.x86_64-4.4.jar"/>
<zipfileset dir= "/home/binhua/.m2/repository/org/eclipse/swt/org.eclipse.swt.win32.win32.x86_64/4.4" includes = "Org.eclipse.swt.win32.win32.x86_64-4.4.jar"/>
<zipfileset dir= "/home/binhua/.m2/repository/org/eclipse/swt/org.eclipse.swt.win32.win32.x86/4.4" includes= " Org.eclipse.swt.win32.win32.x86-4.4.jar "/>
<zipfileset dir= "/home/binhua/.m2/repository/org/eclipse/equinox/org.eclipse.equinox.common/3.6.100. v20120522-1841 "includes=" Org.eclipse.equinox.common-3.6.100.v20120522-1841.jar "/>
<zipfileset dir= "/home/binhua/.m2/repository/org/eclipse/core/org.eclipse.core.commands/3.6.1.v20120521-2329 "includes=" Org.eclipse.core.commands-3.6.1.v20120521-2329.jar "/>
<zipfileset dir= "/home/binhua/.m2/repository/org/eclipse/osgi/org.eclipse.osgi/3.8.0.v20120529-1548" includes = "Org.eclipse.osgi-3.8.0.v20120529-1548.jar"/>
</jar>
</target>
</project>
Above: 1, in Rsrc<attribute name= "Rsrc-class-path", remove the swt*.jar,2, add all the platform Swt*.jar to the Zipfileset node.
5) Well, build it with Ant.
Trouble Shooter
The following trouble shooter is in fact the key to success or failure:
#1
If the code refers to the Jface*.jar, then the above solution will be reported ClassNotFoundException, said that the jface under a class is not found, this is because JFace load failed, why.
Because Jface*.jar is still loaded by default, JFace relies on Swt*.jar,swt*.jar already delayed loading, naturally, Jface*.jar cannot load successfully.
The workaround is to let the jface also delay loading:
1, in the Build.xml rsrc<attribute name= "Rsrc-class-path", the Jface*.jar also removed
2, add the last line in Loadswtjar ()
Private Static void Loadswtjar () {
...
Addurlmethod.invoke (Parentclassloader, New URL ("Rsrc:org.eclipse.jface-3.8.0.v20120521-2329.jar"));
}
*
If you have the following code
public class Myapplicationwindow extends Applicationwindow implements iexceptionhandler{
...
Public Static void Main (string[] args)
{
Loadswtjar ();
...
}
}
will also report ClassNotFoundException, why?
Because Applicationwindow and Iexceptionhandler are all classes under JFace, the main function is placed in Myapplicationwindow, and to execute the main function, the first thing to do is to load Applicationwindow And Iexceptionhandler, and this time, JFace hasn't been loaded yet, remember, it was delayed loading.
The solution is simple, just move the main function to the right place.
3#
If you perform an error under Mac OS X, you must add a parameter:
Java-xstartonfirstthread-jar *.jar
Well, don't ask me why.
Enable Swt/jface to support cross-platform