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

时间:2012-11-15 15:38:56

标签: java windows macos cross-platform

我有一个已编译的可执行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文件中包含此代码,以便我可以拥有一个一致的代码库?

3 个答案:

答案 0 :(得分:8)

使用Brian's answer作为基础,我能够使用以下代码使用OS X特定方法设置Mac停靠图标图像。与其他答案不同,这个答案包含一个完整的示例,并没有尝试将对象转换为OS X特定类对象的问题。

代码的作用:

  1. 此代码使用Class.forName(String)来获取与OS X特定类关联的Class对象,而不是导入OS X特定库。在此示例中,com.apple.eawt.Application库用于设置停靠图标图像。
  2. 然后使用
  3. Reflection从OS X特定类调用方法。 getClass()用于获取Application对象,getMethod().invoke()用于调用getApplication()setDockIconImage()方法。
  4. 我收录的评论显示了通常在OS X独占程序中使用的代码,以明确反映代码正在替换的内容。 (如果您要创建只需要在Mac上运行的程序,请参阅How do you change the Dock Icon of a Java program?以获取设置停靠图标图像所需的代码。)

    // 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特定代码提出任何其他建议,那将会很棒。< /子>

答案 1 :(得分:4)

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

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

这样,您可以在一个类中引用所有Apple特定的类,并在isOSX()分支中动态加载它。你必须这样做,因为你无法加载引用其他不可用类的类 - 你必须确定你是否在OSX中,而只有加载任何东西指的是仅限OSX的类。

如果您有更多特定于操作系统的要求,那么可扩展的方法是在操作系统之后命名您的类,然后根据检测到的操作系统加载类名。例如给你的课程WindowsExtensionsOSXExtensionsLinuxExtensions等打电话(你必须查找相应的名字 - 我只是提供例子)

e.g。这是一个使用示例:

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

答案 2 :(得分:0)

这是不可能的,因为java正在加载类(可能)在类的实例化期间使用的所有类,因此命名类不可用。

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

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

HTH