A Simple Hack for Distributing JLinked Java Projects for MacOS

The Java jlink utility allows you to make a customized (minimized) runtime for a self-contained project. The resulting file structure could simply be zipped and shipped. But before doing so, applying the following hack will make the project much easier to use.

The executable for a jlinked project is a bash script embedded in its /bin subfolder.

  1. Move the bash script to the top folder.

  2. Open the script with TextEdit and edit it as follows:
    Change the start of the last line from "$DIR/java " to "$DIR/bin/java "

  3. Rename (if needed) the bash script to the name that you wish to give the application.

  4. Rename the top folder to the same exact name as the bash script (case sensitive), but with “.app” extension added.

  5. When the MacOS system asks to verify that you wish to make this change, say yes.

At this point you will have converted the top-most file folder holding your application and resources into a manually constructed Bundle that will appear to the MacOS as a single-file .app, without having gone through the complications of conforming to the Bundle file structure or having to provide an Info.plist configuration file.

  1. Open the “Get Info” for the .app.

  2. If you have your own icon for the project, drag the .icns file over the existing default icon in the top left corner of the “Get Info” and drop. The .app file should now display your icon.

The resulting .app file can be zipped and shipped, but the following steps may also be helpful:

  1. Create a new folder and place the .app file in this folder.

  2. Create a ReadMe.txt file and add it to this top folder.

  3. Zip and ship the folder holding the .app and the ReadMe.txt files.

MacOS downloads arrive in the /Downloads folder. From there, the user can drag the .app to wherever they wish. But with a ReadMe, you can provide useful information such as suggestions for where to install, version info, and instructions for using the application.

Also, the ReadMe.txt can provide info on how to first run the program. This can be helpful if the user is unsure of how to run a program that has not been obtained from the App Store, and thus is blocked by a “safety” warning.

Following is some additional info that might be useful. I’ll try to keep this reply up to date via editing. (The tutorial itself cannot be edited due to our site software’s limitations.)

I wrote a tutorial that has a detailed description of making a jlinked application: Packaging Java as a Native Application with a Self-Contained, Custom Runtime: A Manual Walkthrough

This tutorial is quickly becoming outdated, in that it was written for Java 9, when JavaFX was still part of Java. If I get a revision up that makes use of OpenJDK11/OpenJFX11 (or newer), I will try to remember to post a link here. When I do, the plan is to show both Windows and MacOS command lines.

Meanwhile, for setting up to use OpenJFX11, the documentation at openjfx.io is quite good, though they don’t explicitly deal with the jlink utility, afaik. I didn’t find it hard to edit my command lines from the “manual walkthrough” tutorial to accommodate the JDK/JFX split once I had digested the openjfx.io information.

As an alternative way to distribute for MacOS, I think that the Packages tool is a good free option worth checking out. The main reason that I haven’t used it is that I wanted a way to install to a sub-directory of the user’s Home, which doesn’t work (for reasons pertaining to a known Apple bug, according to an email reply that I got a couple days ago from the Packages author). But it works perfectly fine for installing into folders such as /Applications or /Library. It supports pre-and post-install scripting, which I may need for future projects of my own (e.g., ones that require file association).

It occurs to me some might be asking, Bash script? What Bash script?

I was assuming that when running the jlink command, the “launcher” parameter was included. This generates a BASH script that will sit in the /bin subfolder and will run the program. One can also (instead of having the launcher build it) just write their own BASH script manually that will sit in the top folder and execute the program.