前言
使用JavaFX可以非常方便的开发桌面,本篇主要讲解在对JavaFX打包成windows、Linux、MacOS运行包对应的步骤以及遇到的问题解决办法。
正文
打包步骤
这里直接给出我试过,成功的打包步骤,后面再说其他步骤遇到的一些问题。
我使用的开发工具时IDEA,打包用的是Java的jpackage命令。
java版本是21.0.7。
javafx版本也是21.0.7。
准备
Java及JavaFX环境自行准备,网上资料很多,不多赘述。
windows下使用package命令时需要安装一个wix工具,3.xx版本的。
https://pan.baidu.com/s/1U0HcqU5jDAGPofxNU-bskg?pwd=3ihg
通过网盘分享的文件:wix311.exe
链接: https://pan.baidu.com/s/1U0HcqU5jDAGPofxNU-bskg?pwd=3ihg 提取码: 3ihg
安装完成后,使用小黑窗口,执行命令,看一下是否被添加到了环境变量中。
candle.exe
出现以下,说明成功。
否则自己添加到环境变量一下,默认的安装目录为:
C:\Program Files (x86)\WiX Toolset v3.11
1、打包所需的Maven依赖
注意:需要修改一些对应的启动类。
其中jar-with-dependencies表示会打出一个所有依赖都在一起的jar包。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<encoding>UTF-8</encoding>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.comleader.evaluation.HelloApplication</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
2、打Maven包
正常执行clean package
打包结果:
3、打基础运行环境包
这一步,是将启动java程序所以来的环境打包成一个运行时环境包,包括所需的java环境。
打开项目路径下的cmd窗口,执行以下命令,注意修改jar包名称、javafx下的lib地址。
jlink --add-modules java.base,java.desktop,javafx.controls,javafx.fxml,java.logging --output target/jre --module-path "D:\env\java21\jdk\jmods;D:\env\java21\javafx\javafx-sdk-21.0.7\lib"
!!!!!注意!!!!!!
生成运行时镜像后,需要将javafx下的bin目录下的所有dll文件,复制到你生成的jre运行时环境中,否则在没有java环境的电脑上执行会因为环境缺失而报错(linux下是将javafx/lib下的所有.so文件复制)。
copy D:\env\java21\javafx\javafx-sdk-21.0.7\bin\*.dll target\jre\bin\
cp /opt/javafx/lib/*.so target/jre/lib/
完成
4、使用Jpackage打包
在项目下写一个pkg.txt,作为jpackage命令的参数
type 有几种可选类型:
app-image:免安装的exe程序
exe:安装包
rpm:linux下安装包
dmg:macos下安装包
这里以windows下的exe为例:
--name "EvalutionClient"
--type exe
--input target
--main-jar evaluation-1.0-SNAPSHOT-jar-with-dependencies.jar
--main-class com.comleader.evaluation.HelloApplication
--module-path "D:/env/java21/javafx/javafx-sdk-21.0.7/lib"
--runtime-image target/jre
--dest dist
--win-shortcut # 添加桌面快捷方式
--win-menu # 添加 "开始" 菜单快捷方式
--win-dir-chooser # 添加一个对话框,使用户能够选择安装产品的目录
还有一些其他的参数,可以支持不使用运行时环境打包等,具体可以自己查找一下参数资料。
–java-options “-Dfile.encoding=GBK” 可以添加启动jar包的参数。
Linux下:
--name "MyApp"
--type rpm
--input target
--main-jar MyApp.jar
--main-class org.springframework.boot.loader.JarLauncher
--module-path "D:/DevTools/JavaFX/javafx-jmods-21.0.7"
--add-modules javafx.controls,javafx.fxml
--module-path "D:/DevTools/Java/jdk-21/jmods"
--add-modules ALL-MODULE-PATH
--dest dist
--linux-shortcut # 为应用程序创建一个快捷方式
Mac下:
--name "MyApp"
--type dmg
--input target
--main-jar MyApp.jar
--main-class org.springframework.boot.loader.JarLauncher
--module-path "D:/DevTools/JavaFX/javafx-jmods-21.0.7"
--add-modules javafx.controls,javafx.fxml
--module-path "D:/DevTools/Java/jdk-21/jmods"
--add-modules ALL-MODULE-PATH
--dest dist
--mac-package-identifier com.example.myapp # macOS 应用程序的标识符
--mac-sign # 对软件包或预定义的应用程序镜像进行签名
在项目和pkg.txt的目录下执行打包命令:
jpackage @pkg.txt
等待打包完成:
5、运行程序,安装验证
执行这个exe,进行安装,然后启动安装好的程序,检测是否能够启动成功。
启动成功:
6、遇到闪退失败的问题
遇到闪退失败,大多数是因为打包时少添加了环境信息。
排查步骤:
1、先检查maven打好的jar包可否正常启动。
java -Dfile.encoding=GBK --module-path D:\env\java21\javafx\javafx-sdk-21.0.7\lib --add-modules javafx.controls,javafx.fxml -jar evaluation-1.0-SNAPSHOT-jar-with-dependencies.jar
2、如果jar包可以正常启动,使用以下命令,用小黑窗口执行exe程序,输出错误信息到info.log,然后将错误信息提交给人工智能,询问一下怎么解决。
EvalutionClient.exe > info.log 2>&1
我这里遇到了报错:
Exception in Application start method
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:118)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at javafx.graphics@21.0.7/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
at javafx.graphics@21.0.7/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:364)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1149)
Caused by: java.lang.RuntimeException: Exception in Application start method
at javafx.graphics@21.0.7/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:893)
at javafx.graphics@21.0.7/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:196)
at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: javafx.fxml.LoadException:
file:/E:/IdeaWorkSpace/evaluation/EvalutionClient/app/evaluation-1.0-SNAPSHOT-jar-with-dependencies.jar!/fxml/SettingsView.fxml
at javafx.fxml@21.0.7/javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2722)
at javafx.fxml@21.0.7/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2692)
是少添加了–add-modules java.base,java.desktop,javafx.controls,javafx.fxml,java.logging参数。
仔细的看一下其中的日志信息,然后提交给人工智能,通常都可以解决。
7、一只大坑
最一开始我打包的时候,使用的是jlink打包,命令如下:
mvn javafx:jlink
但是因为我依赖了非模块化的jna,所以导致一直报错:
一直报错
错误: 自动模块不能用于来自 file:///D:/env/java21/javafx/javafx-sdk-21.0.7/lib/xxxx
搞了两天,也没有找到合适的解决方法,费了很大劲,最终整理出了以上的打包步骤,验证可行。
不要在费无用功啦~这个解决起来非常麻烦,而且会有很多坑。。。
8、两只大坑
报错:
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 javafx.graphics@21.0.7/com.sun.javafx.tk.quantum.QuantumRenderer.getInstance(QuantumRenderer.java:283)
at javafx.graphics@21.0.7/com.sun.javafx.tk.quantum.QuantumToolkit.init(QuantumToolkit.java:253)
at javafx.graphics@21.0.7/com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:263)
at javafx.graphics@21.0.7/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:290)
at javafx.graphics@21.0.7/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:162)
at javafx.graphics@21.0.7/com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:651)
at javafx.graphics@21.0.7/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:409)
at javafx.graphics@21.0.7/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:364)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1149)
Caused by: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found
at javafx.graphics@21.0.7/com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init(QuantumRenderer.java:95)
at javafx.graphics@21.0.7/com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125)
at java.base/java.lang.Thread.run(Thread.java:1583)
Exception in thread "main" java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:118)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1149)
Caused by: java.lang.RuntimeException: No toolkit found
at javafx.graphics@21.0.7/com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:275)
at javafx.graphics@21.0.7/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:290)
at javafx.graphics@21.0.7/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:162)
at javafx.graphics@21.0.7/com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:651)
at javafx.graphics@21.0.7/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:409)
at javafx.graphics@21.0.7/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:364)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
... 2 more
Failed to launch JVM
参见第三步的注意事项