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.