When you write a Java application, you’ll get a .jar file in the end. If you launch this file in macOS, you’ll end up having the default java icon in the Dock (depending on the application) and you are unable to save the application in the Dock. It just doesn’t feel right.

To solve this, you can either try to read oracle’s documentation and end up using broken search fields, navigating dead links and outdated stuff until you lay crying in the corner. Or you can just use a Maven plugin which does the work for you.

UPDATE: The Maven plugin I originally used is no longer maintained. I’ve updated the instructions to use another one I found working well.

Possible limitations

I read somewhere that you can’t use the com.apple.eawt package with this type of app, but it seems to work for me. For anyone interested, the com.apple.eawt package is a set of Java extensions for macOS specific applications like handlers for the “Preferences” shortcut and the menubar. Apple dropped support for this in Java 1.6 (as they stopped developing their own Java version due to security concerns) but there exists a community maintained package which can be used for builds on non-Apple OSes (Java for Mac still contains this package).

The Maven Plugin

You can use the Maven plugin like this:

<plugin>
    <groupId>de.perdian.maven.plugins</groupId>
    <artifactId>macosappbundler-maven-plugin</artifactId>
    <version>1.5.0</version>
    <configuration>
      <plist>
        <CFBundleIconFile>icons.icns</CFBundleIconFile>
        <CFBundleDisplayName>My cool app</CFBundleDisplayName>
        <CFBundleName>my-cool-app</CFBundleName>
        <JVMMainClassName>com.example.myapp.Main</JVMMainClassName>
      </plist>
      <dmg>
        <generate>true</generate>
        <autoFallback>true</autoFallback>
      </dmg>
      <jdk>
        <include>true</include>
        <location>/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk</location>
      </jdk>
    </configuration>
    <executions>
      <execution>
        <phase>package</phase>
      <goals>
        <goal>bundle</goal>
      </goals>
      </execution>
    </executions>
</plugin>

Remember to check if the version supplied above is the current one.

Here’s a quick overview of the config options I think are important:

  • JVMMainClassName
    • This option lets you specify the entrypoint of your application.
    • It should point to the class containing your psvm.
  • jdk > location
    • You might not really need this, but if you specify the path to your JRE here, the plugin will bundle it into your .app file.
    • Note that this blows up the application by ~170MB so consider if you really need it.
  • CFBundleDisplayName
    • This will be the name of your .app file.
    • This will also appear in the Info.plist.
  • CFBundleIconFile
    • This option should point to a .icns file that will be used for the app.
    • The path is relative to the location of the pom.xml so in the above example, icons.icns would be in the project root.
  • dmg > generate
    • This option will generate a .dmg file with your app.
    • Possible values are: true or false (default)

The macOS app can be built by running:

mvn clean package

For more information about this plugin and more documentation, go to its GitHub repo.