OpenIndex / JavaMacLauncher

a native Java launcher for macOS application bundles (aka JavaApplicationStub)
https://openindex.de
Apache License 2.0
7 stars 2 forks source link
application-bundle application-stub go golang java launcher macos native stub

JavaMacLauncher 1.0.0

This application is a native Java application launcher written in Go, that is intended for integration into a macOS application bundle.

In times of Java 6, when Apple provided a Java Runtime Environment for macOS, there was a similar solution called JavaApplicationStub, which is unfortunately not usable with recent Java versions. Up to macOS 10.15 (Catalina) a binary was not necessary anymore to start a Java application from an application bundle. A simple Bash script like universalJavaApplicationStub could do the job.

Apple made some changes with macOS 11 (Big Sur). It is indeed still possible to use a Bash script for the task, but it has some downsides regarding security. If the application needs further permissions from the operating system (e.g. access to certain user folders or access to the screen), the user needs to grant permissions to Bash or /usr/bin/env — not to the Java application itself. Granting those permissions to those general utilities would undermine the system security and is also not intuitive for the user. This also might become a showstopper for publishing your application to the AppStore.

The universalJavaApplicationStub project addressed this issue by providing a compiled version of their Bash script. As they currently only provide binaries for Catalina and Big Sur we are not sure, if this approach also works with older versions of macOS — even if recent OpenJDK builds should work from macOS 10.9 (Mavericks) upwards.

Inspired by macstub we've decided to build our own native Java launcher to address these issues. As we are mostly developing on Linux systems this launcher is written in Go for easier development and testing. Cross compilation for macOS is currently not possible.

How to use

Assuming you have an application bundle called MyApplication.app, that provides its own Java Runtime Environment in this directory structure:

🗀 MyApplication.app
↳ 🗀 Contents
  ↳ Info.plist
  ↳ 🗀 MacOS
    ↳ JavaMacLauncher
  ↳ 🗀 Resources
    ↳ 🗀 bin
      ↳ java
    ↳ 🗀 conf
    ↳ 🗀 legal
    ↳ 🗀 lib
    ↳ 🗀 modules
    ↳ 🗀 share
      ↳ icon.icns
      ↳ splash.png

Things to consider:

In this scenario the application bundle descriptor Contents/Info.plist would look like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>CFBundleInfoDictionaryVersion</key>
        <string>6.0</string>

        <key>CFBundleIdentifier</key>
        <string>com.mycompany.myapplication</string>

        <key>CFBundleName</key>
        <string>MyApplication</string>

        <key>CFBundleDisplayName</key>
        <string>MyApplicationName</string>

        <key>CFBundleVersion</key>
        <string>1.2.3</string>

        <key>CFBundlePackageType</key>
        <string>APPL</string>

        <key>CFBundleExecutable</key>
        <string>JavaMacLauncher</string>

        <key>CFBundleIconFile</key>
        <string>share/icon.icns</string>

        <key>LSMinimumSystemVersion</key>
        <string>10.9</string>

        <!-- Configure JavaMacLauncher. -->
        <key>JavaMacLauncher</key>
        <dict>

            <!-- Set java home directory. -->
            <key>JavaHome</key>
            <string>Contents/Resources</string>

            <!-- Set java command explicitly. -->
            <key>JavaCommand</key>
            <string>Contents/Resources/bin/java</string>

            <!-- Set further java options. -->
            <key>JavaOptions</key>
            <array>
                <string>-Dfile.encoding=UTF-8</string>
            </array>

            <!-- Set java class path entries. -->
            <key>JavaClassPath</key>
            <array>
                <string></string>
            </array>

            <!-- Set java module path entries. -->
            <key>JavaModulePath</key>
            <array>
                <string>Contents/Resources/modules</string>
            </array>

            <!-- Set application working directory. -->
            <key>WorkingDirectory</key>
            <string></string>

            <!-- Set application command. -->
            <key>ApplicationCommand</key>
            <string>-m com.mycompany.myapplication/com.mycompany.myapplication.MyApplication</string>

            <!-- Set further application command line arguments. -->
            <key>ApplicationArguments</key>
            <array>
                <string></string>
            </array>

            <!-- Set minimum reserved heap space. -->
            <key>HeapMinimum</key>
            <string>32m</string>

            <!-- Set maximum used heap space. -->
            <key>HeapMaximum</key>
            <string>512m</string>

            <!-- Set application splash image. -->
            <key>SplashImage</key>
            <string>Contents/Resources/share/splash.png</string>

            <!-- Set application name shown in the menu bar. -->
            <key>DockName</key>
            <dict>
                <key>default</key>
                <string>My Application</string>
                <key>de</key>
                <string>Mein Programm</string>
                <key>es</key>
                <string>Mi Programa</string>
                <key>fr</key>
                <string>Mon Programme</string>
            </dict>

            <!-- Set application icon shown in dock and menu bar. -->
            <key>DockIcon</key>
            <string>Contents/Resources/share/icon.icns</string>

            <!-- Enable global menu bar. -->
            <key>UseScreenMenuBar</key>
            <true/>

            <!-- Launch application in foreground. -->
            <key>LaunchInForeground</key>
            <true/>

        </dict>
    </dict>
</plist>

Configuration

JavaMacLauncher loads its configuration from the application bundle descriptor (Info.plist). All of its configurations are loaded from the JavaMacLauncher entry, which has to be <dict>:

<plist version="1.0">
    <dict>
        <!-- Typical configurations before as required by macOS. -->

        <key>JavaMacLauncher</key>
        <dict>
            <!-- Configurations for JavaMacLauncher. -->
        </dict>
    </dict>
</plist>

Set Java home & Java command

You need to tell JavaMacLauncher, where to find a Java Runtime Environment to start your application.

<key>JavaHome</key>
<string></string>

<key>JavaCommand</key>
<string></string>

In case you are providing your own Java Runtime Environment within the application bundle, you should either set JavaHome or JavaCommand value.

Set Java command line options

You might specify further options, that are passed to the Java Runtime Environment.

<key>JavaOptions</key>
<array>
    <string>-Dfile.encoding=UTF-8</string>
    <string>-Dcom.mycompany.myapplication.setting=example</string>
</array>

Set Java class path or module path

If your application uses the old class path approach, you can add as much class path entries you like:

<key>JavaClassPath</key>
<array>
    <string>Contents/Resources/jars/MyApplication.jar</string>
    <string>Contents/Resources/more-jars/*</string>
</array>

If your application uses the new module path approach, you can add as much module path entries you like:

<key>JavaModulePath</key>
<array>
    <string>Contents/Resources/modules</string>
    <string>Contents/Resources/more-modules</string>
</array>

Set working directory

You might configure a certain working directory. JavaMacLauncher changes to this directory before starting the Java application.

<key>WorkingDirectory</key>
<string></string>

Set Application start command

You need to tell JavaMacLauncher how to start your application. There are multiple possibilities:

Starting from class path

Just provide the class path of your application's main class:

<key>ApplicationCommand</key>
<string>com.mycompany.myapplication.MyApplication</string>

Starting from module path

Just provide the module and class path of your application's main class:

<key>ApplicationCommand</key>
<string>-m com.mycompany.myapplication/com.mycompany.myapplication.MyApplication</string>

Starting from jar file

Just provide the application's JAR file to load:

<key>ApplicationCommand</key>
<string>Contents/Resources/jars/MyApplication.jar</string>

Set Application command line arguments

You might add further command line arguments, that are passed to your application's main(String[] args) method:

<key>ApplicationArguments</key>
<array>
    <string>first argument</string>
    <string>second argument</string>
</array>

Set minimum & maximum heap size

You might provide a minimum and maximum heap size for the Java Runtime Environment.

<key>HeapMinimum</key>
<string>32m</string>

<key>HeapMaximum</key>
<string>512m</string>

Set application's splash image

You might specify the application's splash image:

<key>SplashImage</key>
<string>Contents/Resources/share/splash.png</string>

Set application's name in Dock & Menubar

You might specify the application's name shown in the Dock and Menubar:

<key>DockName</key>
<dict>
    <key>default</key>
    <string>My Application</string>
    <key>de</key>
    <string>Mein Programm</string>
    <key>es</key>
    <string>Mi Programa</string>
    <key>fr</key>
    <string>Mon Programme</string>
</dict>

Set application's icon in Dock

You might specify the application's icon shown in the Dock:

<key>DockIcon</key>
<string>Contents/Resources/share/icon.icns</string>

Enable global Menubar

You might enable the global Menubar for the application:

<key>UseScreenMenuBar</key>
<true/>

Launch application in foreground

You might force application startup in foreground:

<key>LaunchInForeground</key>
<true/>

Supported operating systems

License

This application is licensed under the terms of the Apache License 2.0. Take a look at LICENSE.txt for the license text.

Third party components

Further information