Java 12 и JavaFX 12 - создайте исполняемый jar и пользовательский JRE - PullRequest
3 голосов
/ 26 июня 2019

Я пытаюсь адаптировать мою программу для работы с Java 12. В настоящее время она работает с Java 8 и имеет некоторые компоненты JavaFX (несколько диалогов). Это не модульно. Моя IDE - это Eclipse, а файлы JAR JavaFX включены в путь сборки в виде пользовательской библиотеки. Я хотел бы создать исполняемый файл jar и либо связать файлы javafx внутри, либо добавить их в пользовательский JRE, чтобы я мог распространять его, не требуя от конечного пользователя установки Java12 или JavaFX отдельно.

Для начала я решил поэкспериментировать с простой HelloFX программой, модифицированной так, чтобы она больше напоминала мою программу.

public class HelloFX2 {

    public HelloFX2() {
        startToolkit();

        // have to wait a second for the JavaFX thread to actually start, or else the Platform.runLater throws an exception
        try
        {
            Thread.sleep(1000);
        }
        catch(InterruptedException ex)
        {
            Thread.currentThread().interrupt();
        }

        // create the scene and display
        Platform.runLater(() -> {
            Scene theScene = createTheScene();
            final Stage stage = new Stage();
            stage.setScene(theScene);
            stage.show();
        });

    }

    public Scene createTheScene() {
        String javaVersion = System.getProperty("java.version");
        String javafxVersion = System.getProperty("javafx.version");
        Label l = new Label("Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + ".");
        Scene scene = new Scene(new StackPane(l), 640, 480);
        return scene;
    }

    public void startToolkit () {
        // we can only create a Scene in a JavaFX thread
        SwingUtilities.invokeLater(() -> {

            // Initialize FX Toolkit, so that we can use the Java FX objects
            new JFXPanel();
        });
    }

}

Я также использовал для запуска класс Main согласно этому предложению . Я не думаю, что мне это нужно в моем случае, потому что HelloFX2 не расширяет Application, но опять же, это ближе к тому, как выглядит моя настоящая программа.

public class Main2 {
    public static void main(String[] args) {
        HelloFX2 theApp = new HelloFX2();
    }
}

Программа отлично работает в Eclipse. Я экспортирую как исполняемый файл JAR с опцией «Извлечь библиотеки», а затем использую jdeps и jlink для создания пользовательского JRE:

D:\Work\Java12>"C:\Program Files\Java\jdk-12.0.1\bin\jdeps" --ignore-missing-deps --print-module-deps HelloFX2.jar
java.base,java.desktop

D:\Work\Java12>"C:\Program Files\Java\jdk-12.0.1\bin\jlink" --no-header-files --no-man-pages  --add-modules java.base,java.desktop --output java-runtime

Но когда я пытаюсь запустить его, я получаю эту ошибку:

D:\Work\Java12>"java-runtime\bin\java" -jar HelloFX2.jar
Graphics Device initialization failed for :  d3d, sw
Error initializing QuantumRenderer: no suitable pipeline found
java.lang.RuntimeException: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found
        at com.sun.javafx.tk.quantum.QuantumRenderer.getInstance(QuantumRenderer.java:280)
        at com.sun.javafx.tk.quantum.QuantumToolkit.init(QuantumToolkit.java:243)
        at com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:260)
        at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:267)
        at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:158)
        at javafx.embed.swing.JFXPanel.lambda$initFx$1(JFXPanel.java:224)
        at java.base/java.lang.Thread.run(Thread.java:835)
Caused by: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found
        at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init(QuantumRenderer.java:94)
        at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:124)
        ... 1 more
Exception in thread "AWT-EventQueue-0" java.lang.RuntimeException: No toolkit found
        at com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:272)
        at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:267)
        at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:158)
        at javafx.embed.swing.JFXPanel.lambda$initFx$1(JFXPanel.java:224)
        at java.base/java.lang.Thread.run(Thread.java:835)

Это та же ошибка, что и в исходной программе HelloFX, когда вы не добавляете ключ --module-path в командную строку, но мне это не нужно, потому что я не расширяю Application.

JavaFX не найден? Все файлы классов JavaFX включены в jar, но я не уверен, как на них указывать.

1 Ответ

2 голосов
/ 26 июня 2019

Используя JavaFX SDK, есть папка lib с банками, такими как javafx.base.jar или javafx.controls.jar, но также есть собственные библиотеки, такие как libglass.so (Linux), libglass.dylib (Mac). В Windows собственные dll, например glass.dll, находятся в папке bin.

При упаковке этих классов в толстую банку вы также должны учитывать необходимые нативные библиотеки.

Это означает, что вам нужно упаковать нативные библиотеки для javafx.graphics, но вам не нужно включать библиотеку webkit (которая добавляет около 80 МБ), если вы не используете модуль javafx.web.

Обратите внимание, что эти библиотеки зависят от платформы (и даже от jar-файлов). Если вы хотите распространить jar-файл на другие платформы, вы также можете упаковать классы и нативные библиотеки с этих платформ, просто загрузив для них SDK.

Все это подробно объясняется в https://openjfx.io/openjfx-docs/#modular, разделе Немодульный проект - Командная строка.

Для модульных проектов jlink является рекомендуемым инструментом. В обоих случаях использование инструментов сборки (Gradle / Maven) действительно помогает справиться с зависимостями JavaFX: вам не понадобится JavaFX SDK, поскольку вы получите зависимости от Maven Central, и они уже объединяют с ними собственные библиотеки. Опять же, стоит прочитать весь документ https://openjfx.io/openjfx-docs/#modular.

...