简体   繁体   中英

How to bundle a Java application to a Mac OS X *.app bundle?

I am trying to bundle my Java application to an Mac OS X .app bundle. I am currently using appbundler and I followed Oracle's guide . The Ant task works fine in Netbeans and the corresponding .app package is built correctly (on Windows). But when trying to execute the .app package to my MacBookPro (OS X 10.7.5), I get the following error in the log:

[0x0-0x72072].ch.lawsuite.core.Servitus: Error: Unable to access jarfile LawSuiteSE.jar

I already checked the permissions for the .jar file and the execution bits are set for the main-jar and all the jars in the lib-folder.

The application just runs fine when typing the following to the terminal:

java -jar /Applications/Servitus.app/Contents/Java/LawSuiteSE.jar --installer

For clarification, here's the final folder structure:

Servitus.app
    |_Contents
        |_Java
            |_LawSuiteSE.jar
            |_lib
                |_lib1.jar
                |_lib2.jar
                    |_subfolder1
                        |_lib3.jar
                    |_subfolder2
                        |_lib4.jar
                |_etc...
            |_MacOS
                |_JavaAppLauncher
            |_PlugIns
            |_Resources
                |_en.lproj
                    |_Localizable.strings
                |_kplus.icns
        |_Info.plist
        |_PkgInfo

By the way, my application has lots of external dependencies, all located in the "lib" folder which are properly linked by the class-path property within the MANIFEST.MF file of the executable main-jar file "LawSuiteSE.jar". Do I need to copy these libs within the appbundle-ant-task or is it okay to copy them subsequently by hand?

I also tried to build the application and the corresponding .app package on the MacBook Pro, but the same error message.

Here's my Ant-task:

<!-- Define the appbundler task -->
<taskdef name="bundleapp" classname="com.oracle.appbundler.AppBundlerTask"/>
<!-- Create the app bundle -->
<target name="bundle-macosx">
    <bundleapp outputdirectory="macosx"
        name="Servitus"
        displayname="Servitus"
        identifier="ch.lawsuite.core.Servitus"
        shortversion="1.0"
        applicationCategory="public.app-category.business"
        icon="src/ch/lawsuite/data/icons/gmbh/osx/kplus.icns"
        mainclassname="ch.lawsuite.core.Servitus">
        <classpath file="dist/LawSuiteSE.jar"/>
        <argument value="--installer"/>
    </bundleapp>
</target>

EDIT: I meanwhile replaced the JavaAppLauncher in Contents/MacOS with a small run script (start.sh):

#!/bin/bash
java -Xms256m -XX:PermSize=128m -jar /Users/salocinx/Workspace/LawSuiteSE.app/Contents/Java/LawSuiteSE.jar --installer

Then I also replaced the value for the key CFBundleExecutable in Info.plist from JavaAppLauncher to start.sh .

Now it works fine, but how can I use a relative path to the jar-executable? Something like "../Java/LawSuiteSE.jar" doesn't work and gives me the same error as before. Is there any constant pointing to the current app-folder, something like "$APP_ROOT" so that the script could look like:

#!/bin/bash
java -Xms256m -XX:PermSize=128m -jar $APP_ROOT/Contents/Java/LawSuiteSE.jar --installer

Any ideas?

Do I need to copy these libs within the appbundle-ant-task

Yes, you should mention all the required libraries in classpath elements. The bundler will then copy them all to the appropriate place inside the bundle (only JAR files that are directly under Contents/Java will go onto the classpath when the bundle is run, JARs in subdirectories are ignored). You should also use dots instead of slashes in the mainclassname.

<bundleapp outputdirectory="macosx"
    name="Servitus"
    displayname="Servitus"
    identifier="ch.lawsuite.core.Servitus"
    shortversion="1.0"
    applicationCategory="public.app-category.business"
    icon="src/ch/lawsuite/data/icons/gmbh/osx/kplus.icns"
    mainclassname="ch.lawsuite.core.Servitus">
    <classpath file="dist/LawSuiteSE.jar"/>
    <classpath dir="lib" includes="*.jar" />
    <argument value="--installer"/>
</bundleapp>

Edit

Now it works fine, but how can I use a relative path to the jar-executable

You can use dirname $0 to get the path to your bundle's Contents/MacOS , and take a relative path from there. You should probably also make an explicit reference to the public JRE rather than relying on java being on your PATH, as that will only work if the target machine has a JDK installed, not if it only has a JRE . Installing the JDK will install the public JRE as well, so it's safe in that case too.

#!/bin/bash

SCRIPT_DIR="`dirname $0`"
exec "/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java" \
  -Xms256m -XX:PermSize=128m -jar "$SCRIPT_DIR/../Java/LawSuiteSE.jar" --installer

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM