创建跨平台的Java SWT应用程序创建跨平台的Java SWT应用程序(Create cross

2019-05-10 10:02发布

我一直在使用SWT编写的Java图形用户界面。 我包使用ANT脚本(下面片段)应用程序。

<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>

这将产生一个jar其在Windows上我就可以双击运行我的GUI。 缺点是,我不得不到Windows SWT包明确打包成我的罐子。

我想能够运行我在其他平台上(主要是Linux和OS X)应用程序。 做到这一点最简单的方法是创建其相应的SWT文件打包成独立的JAR平台特定的罐子。

有一个更好的方法吗? 是否有可能创造条件,在多个平台上运行单个JAR?

Answer 1:

我刚刚遇到了同样的问题。 我还没有尝试过,但我计划包括的版本swt.jar所有平台,并在开始动态加载正确的一个main方法。

更新:它的工作。 build.xml包括所有罐子:

<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"/>

我的main方法开始调用此:

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);
    }
}

[编辑]对于那些寻找“JAR-在-JAR的类加载器”:它包含在Eclipse的JDT(在Java IDE基于Eclipse)。 打开org.eclipse.jdt.ui_*version_number*.jar与归档,你会发现一个文件jar-in-jar-loader.zip内。



Answer 2:

我现在从引用的工作实现SWT FAQ 。

这种方法是现在作为一个Ant任务使用: SWTJar

[编辑] SWTJar现已更新为使用阿列克谢罗曼诺夫溶液如上所述。

build.xml文件

首先,我建立一个包含所有我的应用程序类的罐子。

<!-- UI (Stage 1) -->   
<jarjar jarfile="./build/tmp/intrace-ui-wrapper.jar">
  <fileset dir="./build/classes" includes="**/shared/*.class" />
  <fileset dir="./build/classes" includes="**/client/gui/**/*.class" />
  <zipfileset excludes="META-INF/*.MF" src="lib/miglayout-3.7.3.1-swt.jar"/>
</jarjar>

接下来,我建立一个罐子来包含所有的以下内容:

  • JAR文件
    • 我刚刚生成JAR
    • 所有SWT罐子
    • 在“将罐在-JAR”类加载器类
    • 一个特殊的装载机类 - 见下文

下面是build.xml中的片段。

<!-- UI (Stage 2) -->
<jarjar jarfile="./build/jars/intrace-ui.jar">
  <manifest>
    <attribute name="Main-Class" value="org.intrace.client.loader.TraceClientLoader" />
    <attribute name="Class-Path" value="." />
  </manifest>
  <fileset dir="./build/classes" includes="**/client/loader/*.class" />
  <fileset dir="./build/tmp" includes="intrace-ui-wrapper.jar" />
  <fileset dir="./lib" includes="swt-*.jar" />
  <zipfileset excludes="META-INF/*.MF" src="lib/jar-in-jar-loader.jar"/>
</jarjar>

TraceClientLoader.java

这个加载类使用的jar-在-JAR加载器来创建它从两个罐子加载类一个ClassLoader。

  • 正确的SWT JAR
  • 该应用程序包装罐子

一旦我们有了这个类加载器,我们可以使用反射推出实际的应用主要方法。

public class TraceClientLoader
{
  public static void main(String[] args) throws Throwable
  {    
    ClassLoader cl = getSWTClassloader();
    Thread.currentThread().setContextClassLoader(cl);    
    try
    {
      try
      {
        System.err.println("Launching InTrace UI ...");
        Class<?> c = Class.forName("org.intrace.client.gui.TraceClient", true, cl);
        Method main = c.getMethod("main", new Class[]{args.getClass()});
        main.invoke((Object)null, new Object[]{args});
      }
      catch (InvocationTargetException ex)
      {
        if (ex.getCause() instanceof UnsatisfiedLinkError)
        {
          System.err.println("Launch failed: (UnsatisfiedLinkError)");
          String arch = getArch();
          if ("32".equals(arch))
          {
            System.err.println("Try adding '-d64' to your command line arguments");
          }
          else if ("64".equals(arch))
          {
            System.err.println("Try adding '-d32' to your command line arguments");
          }
        }
        else
        {
          throw ex;
        }
      }
    }
    catch (ClassNotFoundException ex)
    {
      System.err.println("Launch failed: Failed to find main class - org.intrace.client.gui.TraceClient");
    }
    catch (NoSuchMethodException ex)
    {
      System.err.println("Launch failed: Failed to find main method");
    }
    catch (InvocationTargetException ex)
    {
      Throwable th = ex.getCause();
      if ((th.getMessage() != null) &&
          th.getMessage().toLowerCase().contains("invalid thread access"))
      {
        System.err.println("Launch failed: (SWTException: Invalid thread access)");
        System.err.println("Try adding '-XstartOnFirstThread' to your command line arguments");
      }
      else
      {
        throw th;
      }
    }
  }

  private static ClassLoader getSWTClassloader()
  {
    ClassLoader parent = TraceClientLoader.class.getClassLoader();    
    URL.setURLStreamHandlerFactory(new RsrcURLStreamHandlerFactory(parent));
    String swtFileName = getSwtJarName();      
    try
    {
      URL intraceFileUrl = new URL("rsrc:intrace-ui-wrapper.jar");
      URL swtFileUrl = new URL("rsrc:" + swtFileName);
      System.err.println("Using SWT Jar: " + swtFileName);
      ClassLoader cl = new URLClassLoader(new URL[] {intraceFileUrl, swtFileUrl}, parent);

      try
      {
        // Check we can now load the SWT class
        Class.forName("org.eclipse.swt.widgets.Layout", true, cl);
      }
      catch (ClassNotFoundException exx)
      {
        System.err.println("Launch failed: Failed to load SWT class from jar: " + swtFileName);
        throw new RuntimeException(exx);
      }

      return cl;
    }
    catch (MalformedURLException exx)
    {
      throw new RuntimeException(exx);
    }                   
  }

  private static String getSwtJarName()
  {
    // Detect OS
    String osName = System.getProperty("os.name").toLowerCase();    
    String swtFileNameOsPart = osName.contains("win") ? "win" : osName
        .contains("mac") ? "osx" : osName.contains("linux")
        || osName.contains("nix") ? "linux" : "";
    if ("".equals(swtFileNameOsPart))
    {
      throw new RuntimeException("Launch failed: Unknown OS name: " + osName);
    }

    // Detect 32bit vs 64 bit
    String swtFileNameArchPart = getArch();

    String swtFileName = "swt-" + swtFileNameOsPart + swtFileNameArchPart
        + "-3.6.2.jar";
    return swtFileName;
  }

  private static String getArch()
  {
    // Detect 32bit vs 64 bit
    String jvmArch = System.getProperty("os.arch").toLowerCase();
    String arch = (jvmArch.contains("64") ? "64" : "32");
    return arch;
  }
}

[编辑]如上所述,对于那些寻找“JAR-在-JAR的类加载器”:它包含在Eclipse的JDT(在Java IDE基于Eclipse)。 打开org.eclipse.jdt.ui_ * VERSION_NUMBER的* .jar与归档,你会发现里面一个文件jar-in-jar-loader.zip。 我改名这JAR-在-JAR-loader.jar。

intrace-ui.jar -这是我使用上述过程建立的广口瓶中。 你应该能够在任何的Win32 / 64,linux32镜像/ 64和osx32 / 64运行这个单一罐子。

[编辑]这个答案现在从引用的SWT FAQ 。



Answer 3:

如果你不希望一切都汇总到一个单一的jar文件和使用的jar-在-JAR,那么你也可以包括在您部署的应用程序的lib目录中每个目标平台命名为SWT罐子解决这个问题:

lib/swt_win_32.jar
lib/swt_win_64.jar
lib/swt_linux_32.jar
lib/swt_linux_64.jar

并通过检查Java系统属性动态地在运行时加载正确的"os.name""os.arch"在系统运行时System.getProperty(String name)创建正确的罐子文件名。

然后,您可以使用反射的略微调皮位(OO纯粹主义者,现在看远!)通过调用正常保护方法URLClassloader.addURL(URL url)需要第一SWT课前添加正确的罐子系统类加载器的类路径。

如果你能忍受的代码的气味,我已经把工作的例子在这里http://www.chrisnewland.com/select-correct-swt-jar-for-your-os-and-jvm-at-runtime-191



Answer 4:

这是非常奇怪的是,所有的答案在这里只是提醒所有的SWT JAR文件打包成巨单应用程序JAR文件。 恕我直言,这是严重违反SWT的目的:有每个平台的SWT库,所以它应该是只包每个平台的适当的SWT库。 这是很容易做到的,只是定义在Ant生成5个创建个人资料:Win32中,Win64的,linux32镜像,LINUX64和mac64(你可以做mac32为好,但所有现代的Mac电脑都是64位)。

无论如何,如果你想拥有良好的应用集成到操作系统,那么你就必须做一些特定的OS-东西,你又与创建个人资料。 对于桌面应用程序,它的不方便有一个应用程序包都为开发者和用户自己的所有平台。



Answer 5:

替换SRC =“LIB / org.eclipse.swt.win32.win32.x86_3.5.2.v3557f.jar”粗体所选文本与Linux指定SWT的jar文件



文章来源: Create cross platform Java SWT Application