如何为我的跨平台Jar调用特定于OS X的方法



我有一个编译的可执行JAR文件,它在Windows平台上失败了。

这是因为我想正确地集成某些特定于OS X的属性,例如关于窗口

尽管我特别使用了一个条件来阻止代码,但JAR仍然在执行的第一行就崩溃了,出现了NoClassDefFoundError

if (isOSX()) {
com.apple.eawt.Application application = com.apple.eawt.Application.getApplication();
application.setAboutHandler(new com.apple.eawt.AboutHandler() {
@Override
public void handleAbout(com.apple.eawt.AppEvent.AboutEvent ae) {
new AboutWindow();
}
});
application.setDefaultMenuBar(MenuSystem.createMenu());
}

有没有可能在我的JAR文件中包含这些代码,这样我就可以有一个一致的代码库?

以Brian的回答为基础,我能够使用以下代码使用OSX特定的方法设置Mac dock图标图像。与其他答案不同,此答案包含一个完整的示例,并且不存在将对象强制转换为特定于OSX的类对象的问题。

代码的作用:

  1. 此代码使用Class.forName(String)获取与OS X特定类关联的Class对象,而不是导入OS X特定库。在本例中,com.apple.eawt.Application库用于设置停靠图标图像
  2. 然后使用反射来调用OSX特定类中的方法。getClass()用于获取Application对象,getMethod().invoke()用于调用getApplication()setDockIconImage()方法

我包含了一些注释,显示了通常在OSX独占程序中使用的代码,以明确反射代码正在替换什么。(如果您正在创建一个只需要在Mac上运行的程序,请参阅如何更改Java程序的Dock图标?以获取设置Dock图标图像所需的代码。)

// Retrieve the Image object from the locally stored image file
// "frame" is the name of my JFrame variable, and "filename" is the name of the image file
Image image = Toolkit.getDefaultToolkit().getImage(frame.getClass().getResource(fileName));
try {
// Replace: import com.apple.eawt.Application
String className = "com.apple.eawt.Application";
Class<?> cls = Class.forName(className);
// Replace: Application application = Application.getApplication();
Object application = cls.newInstance().getClass().getMethod("getApplication")
.invoke(null);
// Replace: application.setDockIconImage(image);
application.getClass().getMethod("setDockIconImage", java.awt.Image.class)
.invoke(application, image);
}
catch (ClassNotFoundException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException
| InstantiationException e) {
e.printStackTrace();
}

尽管此代码有效,但此方法似乎仍然是一个混乱的解决方法,如果有人对如何在Mac和Windows上使用的程序中包含特定于OS X的代码有任何其他建议,那就太好了

您是否尝试过使用class.forName动态加载周围的类?

Class.forName("com.myproject.ClassContainingApple");

通过这种方式,您可以在一个类中引用所有特定于Apple的类,并将其动态加载到isOSX()分支中。你必须这样做,因为你无法加载引用其他不可用类的类-你必须确定你是否在OSX中,然后加载任何引用OSX的类。

如果您有更多特定于操作系统的要求,一种可扩展的方法是以操作系统命名类,然后根据检测到的操作系统加载类名。例如,将你的类称为WindowsExtensionsOSXExtensionsLinuxExtensions等(你必须查找合适的名称——我只是提供示例)

例如,这里有一个用法示例:

String className = ""java.util.ArrayList";
Class cls = Class.forName(className);
List list = (List)cls.newInstance();

这是不可能的,因为java正在加载类在实例化过程中可能使用的所有类,所以命名的类不可用。

您可以尝试将代码放在项目中的另一个类中,并且只有当您在OSX上运行时才能实例化这个类。

如果这不起作用,您就必须使用反射,因为只有当您通过反射加载此类时,VM才能检测到它。

HTH-

最新更新