无法生成跨平台的JavaFX应用程序。

6

我似乎无法生成一个跨平台的JavaFX应用程序。

当我在IntelliJ中运行它时,它正常工作,如果通过maven打包,我也可以在Linux上运行生成的jar文件。

问题出现在我尝试在Mac上运行jar文件时,似乎没有包含JavaFX库,然后我会得到这个堆栈跟踪:

Graphics Device initialization failed for : es2, 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:244)
    at com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:261)
    at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:267)
    at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:158)
    at com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:658)
    at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:678)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
    at java.base/java.lang.Thread.run(Thread.java:832)
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 “main” java.lang.RuntimeException: No toolkit found
    at com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:273)
    at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:267)
    at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:158)
    at com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:658)
    at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:678)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
    at java.base/java.lang.Thread.run(Thread.java:832)

我正在使用Java 15编译为11以及JavaFX11。

我还使用maven配置文件来生成特定版本,并使用shade插件将所有依赖项打包成一个fat jar文件。

此外,还有一个启动器,它是清单指向的位置,在实际的FX应用程序之前运行。

这是pom文件的样子。

<profiles>
    <profile>
        <id>linux</id>
        <dependencies>
            <dependency>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-controls</artifactId>
                <version>11</version>
                <classifier>linux</classifier>
            </dependency>
            <dependency>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-fxml</artifactId>
                <version>11</version>
                <classifier>linux</classifier>
            </dependency>
        </dependencies>
    </profile>
    <profile>
        <id>mac</id>
        <dependencies>
            <dependency>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-controls</artifactId>
                <version>11</version>
                <classifier>mac</classifier>
            </dependency>
            <dependency>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-fxml</artifactId>
                <version>11</version>
                <classifier>mac</classifier>
            </dependency>
        </dependencies>
    </profile>
    <profile>
        <id>win</id>
        <dependencies>
            <dependency>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-controls</artifactId>
                <version>11</version>
                <classifier>win</classifier>
            </dependency>
            <dependency>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-fxml</artifactId>
                <version>11</version>
                <classifier>win</classifier>
            </dependency>
        </dependencies>
    </profile>
</profiles>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.0</version>
            <configuration>
                <release>11</release>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.0.0</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <transformers>
                            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <manifestEntries>
                                    <Main-Class>org.log.Launcher</Main-Class>
                                </manifestEntries>
                            </transformer>
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

我还注意到无论我选择哪个配置文件,它总是生成Linux版本,并且我可以看到这个Maven日志:

[WARNING] javafx-controls-11-win.jar, javafx-graphics-11-linux.jar, javafx-fxml-11-linux.jar, LogAnalyzer-1.0-SNAPSHOT.jar, javafx-base-11-linux.jar, javafx-controls-11-linux.jar, javafx-fxml-11-win.jar define 1 overlapping classes: 
[WARNING]   - module-info
[WARNING] javafx-controls-11-win.jar, javafx-controls-11-linux.jar define 1216 overlapping classes: 
[WARNING]   - com.sun.javafx.scene.control.TableColumnBaseHelper$TableColumnBaseAccessor
[WARNING]   - javafx.scene.control.ComboBoxBase
[WARNING]   - javafx.scene.control.skin.ColorPickerSkin$StyleableProperties$2
[WARNING]   - com.sun.javafx.scene.control.inputmap.InputMap$KeyMappingInterceptor
[WARNING]   - javafx.scene.control.cell.ChoiceBoxTreeTableCell
[WARNING]   - javafx.scene.control.TableCell$3
[WARNING]   - javafx.scene.control.skin.ProgressBarSkin$StyleableProperties$1
[WARNING]   - javafx.scene.control.DialogPane$2
[WARNING]   - javafx.scene.control.skin.ToolBarSkin$4
[WARNING]   - javafx.scene.control.skin.ColorPickerSkin$3
[WARNING]   - 1206 more...
[WARNING] javafx-fxml-11-linux.jar, javafx-fxml-11-win.jar define 80 overlapping classes: 
[WARNING]   - com.sun.javafx.fxml.expression.ExpressionValue$KeyPathMonitor
[WARNING]   - javafx.fxml.FXMLLoader$RootElement
[WARNING]   - com.sun.javafx.fxml.expression.Expression$Parser$TokenType
[WARNING]   - javafx.fxml.FXMLLoader$DefineElement
[WARNING]   - javafx.fxml.Initializable
[WARNING]   - javafx.fxml.FXMLLoader$ControllerMethodEventHandler
[WARNING]   - com.sun.javafx.fxml.BeanAdapter
[WARNING]   - javafx.fxml.FXMLLoader$ControllerAccessor$1
[WARNING]   - javafx.fxml.JavaFXBuilderFactory$ObjectBuilderWrapper$ObjectBuilder
[WARNING]   - javafx.fxml.FXML
[WARNING]   - 70 more...
[WARNING] maven-shade-plugin has detected that some class files are
[WARNING] present in two or more JARs. When this happens, only one
[WARNING] single version of the class is copied to the uber jar.
[WARNING] Usually this is not harmful and you can skip these warnings,
[WARNING] otherwise try to manually exclude artifacts based on
[WARNING] mvn dependency:tree -Ddetail=true and the above output.
[WARNING] See http://maven.apache.org/plugins/maven-shade-plugin/

我一直在阅读其他帖子和观看一些视频,发现其他人也遇到了这个问题,但对我来说似乎有点奇怪。另外奇怪的是,当我生成Windows版本时,在生成的jar文件中看不到任何.dll文件。

有人知道如何生成跨平台的FX jar包吗?

-------- 编辑 --------

正如其他帖子中建议的那样,我有一个启动器类(Launcher class),它调用扩展Application类的实际类:

public class Launcher {
    public static void main(String[] args) {
        App.main(args);
    }
}

还有JavaFX类:

public class App extends Application {

    public static void main(String[] args) {
        Application.launch();
    }
        
    @Override
    public void start(Stage stage) throws IOException {
        ...
    }
}

我现在已经从pom文件中移除了配置文件,所以在编译时,maven应该会使用所有依赖项(mac、linux和win),但是似乎仍然只生成了linux的依赖项(我正在Linux系统下运行,这可能与此有关),因为如果我打开jar文件,我看不到任何.dll文件,并且它仍然无法在mac上运行。以下是我的完整pom文件:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.log</groupId>
    <artifactId>LogAnalyzer</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-controls</artifactId>
        <version>11</version>
        <classifier>linux</classifier>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-fxml</artifactId>
        <version>11</version>
        <classifier>linux</classifier>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-controls</artifactId>
        <version>11</version>
        <classifier>mac</classifier>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-fxml</artifactId>
        <version>11</version>
        <classifier>mac</classifier>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-controls</artifactId>
        <version>11</version>
        <classifier>win</classifier>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-fxml</artifactId>
        <version>11</version>
        <classifier>win</classifier>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-csv</artifactId>
        <version>1.6</version>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.7.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.hamcrest</groupId>
        <artifactId>hamcrest</artifactId>
        <version>2.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.0</version>
            <configuration>
                <release>11</release>
            </configuration>
        </plugin>
        
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.0.0</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <transformers>
                            <transformer
                                    implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <manifestEntries>
                                    <Main-Class>org.log.Launcher</Main-Class>
                                </manifestEntries>
                            </transformer>
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>

    </plugins>
</build>

1
我没有尝试过,但我认为这是可能的。在openjfx.io | Runtime images | Custom JDK+JFX Images | Cross-platform jar上有一定程度的文档记录。我认为问题中发布的maven文件可能大部分是正确的,只需要摆脱配置文件,以便将所有平台的所有jar文件放置在结果Jar中。 - jewelsea
我删除了配置文件并将每个依赖项添加了三次(win,linux和mac),但我仍然得到了之前的警告,基本上是说有重叠的类将被删除,生成的jar文件只能在linux上运行。最终无论我为linux、mac、win还是它们三个编译,生成的jar文件始终具有相同的大小,并且仅适用于linux。 - muilpp
关于重叠类的警告说明:“通常情况下这并不会造成问题,您可以忽略这些警告”,我认为此处也是如此。如果您的Maven项目正确,唯一的本地库将不会重叠,并且即使出现警告也应该被复制。如果它是跨平台的,则不应该为Linux、Mac或Windows编译。相反,您只需为所有三个平台编译一次,生成一个适用于所有平台的单个Jar。这个单一的Jar应该包括所有平台的本地库,以便Jar文件大小不因平台而异。 - jewelsea
另外请注意,我所提到的跨平台JAR文档中指出:“为了创建一个包含所有必需JavaFX依赖项的可运行JAR文件,您需要使用一个不继承自Application的启动器类。” 我从未这样做过,所以我没有关于它的建议,但这是我请求最小可重现示例的原因之一,这样至少有人可以看到您的启动器类是什么。 - jewelsea
也许这是一个重复的问题:Maven Shade JavaFX runtime components are missing,这里还有相关的补充材料:JavaFX 11 : Create a jar file with Gradle - jewelsea
显示剩余3条评论
2个回答

7
根据 @jewelsea 评论中提供的 其中一个链接 的建议,关键在于分别显式添加每个平台的图形模块。
<dependencies>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-controls</artifactId>
        <version>11</version>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-fxml</artifactId>
        <version>11</version>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-graphics</artifactId>
        <version>11</version>
        <classifier>win</classifier>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-graphics</artifactId>
        <version>11</version>
        <classifier>linux</classifier>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-graphics</artifactId>
        <version>11</version>
        <classifier>mac</classifier>
    </dependency>
</dependencies>

它生成了一个“胖”jar文件,我终于能看到其中的.dll文件。 在Linux和Mac上尝试过,两个平台都可以运行。


0

据我所知,现在已经不可能再为JavaFX应用程序创建跨平台JAR文件了。

但是,应该可以创建特定于平台的JAR文件。

我对Shade插件不是很熟悉,但根据文档,应该可以排除依赖项。

因此,例如对于Mac版本,请确保排除所有非Mac JavaFX依赖项。


我尝试排除与编译的操作系统无关的任何依赖项,但仍然得到相同的结果。即使我指定了mac或win,它也只能在linux上运行,并且生成的jar文件始终具有相同的大小,无论使用哪个配置文件。 - muilpp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接