A Mac/Java javapackager example (getting the application bundle root directory)

UPDATE: The approach below worked with Java 8, and here is a link to the new solution for macOS and Java 14 and newer.

I wrote earlier about how to use the javapackager command to create a macOS application bundle from a Java application, so I won’t repeat all of that information here. Instead, in this article I just want to show how to display an image that’s stored in the Contents/Resources/Java directory of a Mac/Java application bundle.

A Java application to display an image

First, here’s the source code for a Java class that displays an image that should be in the Contents/Resources/Java directory of the macOS application bundle:

import java.awt.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;

public class ImageDemo
{
    public static void main(String[] args) throws Exception {
        new ImageDemo();
    }

    public ImageDemo() throws Exception {
    
        String basePath = com.apple.eio.FileManager.getPathToApplicationBundle();
        final String filename = basePath + "/Contents/Resources/Java/test.jpg";

        String debugFile = "/Users/al/tmp/ImageDemo.out";
        writeFile(debugFile, "\n");
        writeFile(debugFile, "basePath = " + basePath + "\n");
        writeFile(debugFile, "filename = " + filename + "\n");

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame editorFrame = new JFrame("Image Demo");
                editorFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

                BufferedImage image = null;
                try {
                    image = ImageIO.read(new File(filename));
                } catch (Exception e) {
                    e.printStackTrace();
                    System.exit(1);
                }
                ImageIcon imageIcon = new ImageIcon(image);
                JLabel jLabel = new JLabel();
                jLabel.setIcon(imageIcon);
                editorFrame.getContentPane().add(jLabel, BorderLayout.CENTER);

                editorFrame.pack();
                editorFrame.setLocationRelativeTo(null);
                editorFrame.setVisible(true);
            }
        });
    }

    public static void writeFile(String canonicalFilename, String text) 
    throws IOException {
        BufferedWriter out = new BufferedWriter(new FileWriter(new File(canonicalFilename), true));
        out.write(text);
        out.close();
    }

}

Getting the application bundle directory (“base path”)

Note that I also added some debug code to that class to help me verify that I was getting the root directory of the application bundle properly. I get that “base path” using this Mac/Java code:

String basePath = com.apple.eio.FileManager.getPathToApplicationBundle();

This line of code — showing how to get the base path of the application bundle installation directory — is one of the biggest differences between this article and my previous javapackager article. Everything else is fairly standard Java/Swing GUI code.

Compiling

Next, I have this two-line shell script I use to compile this class:

javac -classpath rt.jar ImageDemo.java
echo "compiled ImageDemo.java"

Creating a JAR file

Then I have this script to create a JAR file from the *.class files that are generated in the compile phase:

jar cmf manifest.txt ImageDemo.jar *class
echo "created ImageDemo.jar from ImageDemo.class and manifest"

The manifest file for that jar command contains this one line:

Main-Class: ImageDemo

The javapackager command

After I create the JAR file, I use this javapackager command to create the Mac application bundle from my Java code:

JAVA_HOME=`/usr/libexec/java_home -v 1.8`

javapackager \
    -deploy -Bruntime=${JAVA_HOME} \
    -native image \
    -outdir release \
    -outfile ImageDemo.app \
    -srcdir . \
    -srcfiles ImageDemo.jar \
    -appclass ImageDemo \
    -name "ImageDemo" \
    -title "Image Demo"

That javapackager command creates a macOS application bundle named ImageDemo.app under a directory named release/bundles. You can use this Mac/Java application bundle just like any other native Mac application.

One note: I manually copy the file test.jpg into the Contents/Resources/Java directory after I create the application bundle with the javapackager command.

More javapackager information

I don’t want to duplicate what I wrote in my earlier How to use javapackager to build a MacOS application bundle tutorial, so I’ll stop at this point. But if you needed to see a javapackager example, I hope these two articles are helpful.