Creating a Java launcher to enable dark mode

To run a Java application in dark mode from the command line currently requires using a Java launcher (typically, a program whose name is java) that itself opts-in to dark mode. Because any application launched by this launcher will run in dark mode when the system is configured to use dark mode, it is best to have a separate launcher used only for launching dark mode aware applications.

A Java launcher can opt-in to dark mode by being built against the macOS 10.14 SDK. If rebuilding the launcher is not possible or not convenient, an alternative described here is patching the existing launcher to make it look like it was linked against the 10.14 SDK. Again, the recommendation is to make a copy of the launcher executable for this purpose. It may be most convenient to make a copy of the entire JDK containing the patched launcher, for programs like IntelliJ IDEA that allow a project to choose the JDK used to execute a program.

Patching a Java launcher requires a hex editor, such as Hex Fiend. The file to edit is Contents/Home/bin/java in an Oracle JDK. Again, be sure to copy this file before modifying it.

The modification involves changing a field in the executable that represents the SDK version. The existing SDK version is probably 10.9, and the goal is to change that to 10.14. The field is a two byte field, but only the byte corresponding to the minor version needs to be changed.

The first step is to find the field. Use the otool program to dump the loader defined fields in the executable:

otool -l java
The output will include something like this:
Load command 8
     cmd LC_UUID
 cmdsize 24
    uuid B8D1A98A-FDA3-388D-B1A3-90E83666847B
Load command 9
      cmd LC_VERSION_MIN_MACOSX
  cmdsize 16
  version 10.7
      sdk 10.9
The SDK in this executable is 10.9. It needs to be 10.14. Also note the UUID in Load Command 8.

Next, open the file in a hex editor and search for the UUID. The UUID is distinctive. Searching for the first four hex digits is probably sufficient.

Hex Fiend screen shot

Approximately 16 bytes after the UUID is the SDK field. The SDK version is represented as two bytes, in this case, 09 and 0A, hex for 9 and 10, corresponding to 10.9.

Select the 09 byte and alter it to 0E (14).

Save the file. Then run otool again to make sure it now says SDK 10.14. On some macOS releases, it may be necessary to code sign the executable to permit it to be run.