'How to generate a jar and native bundle (dmg, exe, etc) from the same code in JavaFX

I have a JavaFX app setup in IntelliJ. This app can run from the command line and as a gui from the jar. In addition to the two modes from the jar, I want to also publish a native bundle (for mac in my case, so dmg). I want to do this by just creating an if statement in main() that takes instructions to start the gui or not. This is my class.

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("dummy.fxml"));
        primaryStage.setTitle("TODO");
        primaryStage.setScene(new Scene(root, 400, 400));
        primaryStage.show();
    }


    public static void main(String[] args) {
        if (args[0].equals("user_interface")) {
            //launch gui version
            launch(args);
        } else {
            //Run command line version of the app
            //TODO
        }
    }
}

I created two build artifacts in my intellij project. One for a jar and one for a javafx application to generate the dmg.

The jar works perfectly. It runs in cli and it starts the javafx app, but I don't know how to pass arguments when creating the native bundle so that I can pass in "user_interface". Does anyone know how to pass args when creating a native bundle artifact?

If there is a better way of doing this? The are only two requirements.

  1. There should be two artifacts. A jar and a dmg.
  2. The jar can run in cli or gui mode.


Solution 1:[1]

You could create 2 Main classes:

  • Console App --> hide the UI
  • UI App --> show the UI

Then you can create 2 artifacts: console artifact, ui artifact. Then use of of your main classes.

Or you could define "Application Parameters" within the Java FX tab in the JavaFx Application Artifact:JavaFX Application Parameters

It's a simple properties file with "key=value" or only a "key". One entry per line. Then you could get this parameters in your start method:

    @Override
    public void start(Stage primaryStage) throws Exception {
        Parameters parameters = getParameters();

        List<String> unnamed = parameters.getUnnamed();
        for (String s : unnamed) {
            System.out.println(s + " (unnamed)");
            Alert al = new Alert(Alert.AlertType.INFORMATION);
            al.setContentText(s + " (unnamed)");
            al.show();
        }

        List<String> raw = parameters.getRaw();
        for (String s : raw) {
            System.out.println(s + " (raw)");
            Alert al = new Alert(Alert.AlertType.INFORMATION);
            al.setContentText(s + " (raw)");
            al.show();
        }
}

Solution 2:[2]

What I typically do in this case is sniff around the System properties to see if there is anything I can use as a proxy to determine if the app is running inside an app bundle. E.g. System.out.println(System.getProperties())

Compare this when running in an app bundle vs running in CLI, and something should jump out. E.g. The launcher probably adds some system properties that you can key on.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 steve hannah