Creating a Mac OS .app from a runnable JAR file

Here we solve a problem that many developers face when bundling java applications into an .app. We are going to correctly set the current working path for your Java Application.

Mac OS applications (.app files) are basically packages with a specific folder structure. You can easily explore each app’s structure by clicking on it using right click in Finder and selecting “Show Package Contents”.

Screen Shot 2016-02-21 at 11.42.41

Screen Shot 2016-02-21 at 11.42.53

 

Creating a custom .app

Create a folder PROGRAM_NAME.app. The Finder will ask you the following, which you will answer as add.

Screen Shot 2016-02-21 at 11.46.37

Now, show contents of you app and inside it create a folder structure /Contents/MacOS. Also create a blank script file launcher.sh (in my case, I am using Sociogram as a program name).

Screen Shot 2016-02-21 at 12.49.45
This script needs to be an executable, so open Terminal and run a command like this:

chmod a+x Sociogram.app/Contents/MacOS/launcher.sh

Maybe you have noticed that your .app does not have an icon. Therefore you need an .icns icon. I used a web service (https://iconverticons.com/online/) to convert my PNG file to an appropriate ICNS file.

Now, create a folder Resources and copy your icon there:

Screen Shot 2016-02-21 at 12.51.25

 

The last step now is to create a config file Info.plist that will define, which is an executable file in your app and where is your .app icon:

Screen Shot 2016-02-21 at 12.54.14

After these steps, you should have prepared an .app file, which looks like as follows:

Screen Shot 2016-02-21 at 12.55.39

Creating a runnable script for a JAR

First, let use create a Java Application that will print out the current working directory and package it into a runnable JAR (sociogram.jar):

import javax.swing.*;
import java.awt.*;
 
/**
 * Created by slavkoz on 21/02/16.
 */
public class Runner {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
 
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        panel.add(new JTextField(System.getProperty("user.dir")), BorderLayout.CENTER);
        frame.setContentPane(panel);
 
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }
}

If we now just run that jar from a launcher script, the default working directory for Java would be “/”, so we may have problem accessing resources, that are packaged inside our .app.

Therefore, let us create an executable socioRunner script that will accept current working dir and run our java application from there. We put the script in the same directory as the launcher script.

#!/bin/sh
 
DIR=$1
APP_JAR="sociogram.jar"
APP_NAME="Sociogram 5.0"
 
cd "$DIR"
java -Xdock:name="$APP_NAME" -Xdock:icon="$DIR/../Resources/application.icns" -cp "$DIR;.;" -jar "$DIR/$APP_JAR"

Now, we can update the launcher script, which will detect the directory, where it resides and run the socioRunner script with a parameter:

#!/bin/sh
 
# Set the working directory
DIR=$(cd "$(dirname "$0")"; pwd)
 
# Run the application
exec "$DIR/socioRunner" $DIR

So, voila, now we get the following result when the .app application is run from Finder:

Screen Shot 2016-02-21 at 13.32.45

You can download the whole .app file from here: http://zitnik.si/wordpress/manual_upload/Sociogram.app.zip