使用NSIS进行JavaFX程序打包
- 软件版本
- IDEA不支持JDK11+平台上打包JavaFX程序
- 解决方案
- 1. 创建JAR包
- 2. 生成JRE运行环境
- 3. 打包生成EXE
- 附件
软件版本
编辑器:IDEA 2020.2
JDK: OpenJDK 14.02
JavaFX: OpenJFX 11.02
NSIS: nsis-3.06.1
IDEA不支持JDK11+平台上打包JavaFX程序
由于JDK11+平台上没有JavaFX packager和javapackager,IDEA不支持通过fx:deploy打包JavaFX程序生成exe。
在IDEA 2020.2中使用Artifacts打包JavaFX程序(File->Project Structure->Artifacts->±>JavaFX Application->From module ‘HelloFX’),出现错误:
Java FX Packager: Can’t build artifact - fx:deploy is not available in this JDK。
解决方案
1. 创建JAR包
通过顺次点击File->Project Structure->Artifacts->±>JAR->From module with dependencies!打开创建JAR包对话框:
依次设置Main Class 和META-INF目录,点击OK:
依次点击Build->Build Artifacts->HelloFX:jar->Build就可以生成相应的JAR包了:
2. 生成JRE运行环境
转到HelloFX\out\artifacts\HelloFX_jar路径下。注意生成的JAR包在*_jar路径之下。
2.1 获取依赖项
使用jdeps将依赖项导入到depends.txt中:
jdeps --list-deps --ignore-missing-deps --module-path "D:\Program Files\java\openjfx-11_windows-x64_bin-sdk\javafx-jmods-11;D:\Program Files\java\openjfx-11_windows-x64_bin-sdk\javafx-sdk-11\lib;D:\Program Files\java\openjdk-14.0.2_windows-x64_bin\jdk-14.0.2\jmods" --add-modules javafx.controls,javafx.fxml HelloFX.jar > depends.txt
其中的路径包括jdk和javafx库路径和jmods路径,注意需要添加javafx.controls等modules。
生成的depends.txt内容为:
java.base
java.desktop
java.scripting
java.xml
javafx.base/com.sun.javafx
javafx.base/com.sun.javafx.beans
javafx.base/com.sun.javafx.binding
javafx.base/com.sun.javafx.collections
javafx.base/com.sun.javafx.event
javafx.base/com.sun.javafx.logging
javafx.base/com.sun.javafx.property
javafx.base/com.sun.javafx.reflect
javafx.controls/com.sun.javafx.scene.control
javafx.controls/com.sun.javafx.scene.control.behavior
javafx.controls/com.sun.javafx.scene.control.inputmap
javafx.controls/com.sun.javafx.scene.control.skin
javafx.graphics/com.sun.glass.ui
javafx.graphics/com.sun.glass.utils
javafx.graphics/com.sun.javafx.application
javafx.graphics/com.sun.javafx.css
javafx.graphics/com.sun.javafx.font
javafx.graphics/com.sun.javafx.geom
javafx.graphics/com.sun.javafx.geom.transform
javafx.graphics/com.sun.javafx.iio
javafx.graphics/com.sun.javafx.menu
javafx.graphics/com.sun.javafx.scene
javafx.graphics/com.sun.javafx.scene.input
javafx.graphics/com.sun.javafx.scene.layout
javafx.graphics/com.sun.javafx.scene.text
javafx.graphics/com.sun.javafx.scene.traversal
javafx.graphics/com.sun.javafx.sg.prism
javafx.graphics/com.sun.javafx.stage
javafx.graphics/com.sun.javafx.text
javafx.graphics/com.sun.javafx.tk
javafx.graphics/com.sun.javafx.util
javafx.graphics/com.sun.prism
javafx.graphics/com.sun.prism.image
javafx.graphics/com.sun.prism.paint
javafx.graphics/com.sun.scenario.effect
javafx.graphics/com.sun.scenario.effect.impl
javafx.graphics/com.sun.scenario.effect.impl.prism
javafx.media/com.sun.javafx.media
javafx.media/com.sun.media.jfxmedia
javafx.media/com.sun.media.jfxmedia.control
javafx.media/com.sun.media.jfxmedia.events
javafx.media/com.sun.media.jfxmedia.locator
javafx.media/com.sun.media.jfxmedia.track
jdk.jsobject
jdk.xml.dom
2.2 使用jlink生成jre
将depends.txt中的依赖项以及原有的javafx依赖项(javafx.fxml)放在jlink命令中,生成jre-14.0.2运行环境文件夹:
jlink --module-path "D:\Program Files\java\openjfx-11_windows-x64_bin-sdk\javafx-jmods-11;D:/Program Files/java/openjfx-14.0.2.1_windows-x64_bin-sdk/javafx-sdk-14.0.2.1/lib;D:\Program Files\java\openjdk-14.0.2_windows-x64_bin\jdk-14.0.2\jmods" --add-modules java.base,java.desktop,java.scripting,java.xml,javafx.base,javafx.controls,javafx.graphics,javafx.media,jdk.jsobject,jdk.xml.dom,javafx.fxml --output jre-14.0.2 --strip-debug --compress 2 --no-header-files --no-man-pages
在命令行中输入以下命令,如果能打开程序说明生成的jre可用:
"jre-14.0.2/bin/java.exe" -jar HelloFX.jar
3. 打包生成EXE
根据Creating a Windows Executable Bundled with Java OpenJDK上面的做法,制作NSIS脚本:
Unicode true
!include WinMessages.nsh
!include FileFunc.nsh
!addplugindir Plugins
SilentInstall silent
RequestExecutionLevel user
ShowInstDetails hide
OutFile "HelloFX.exe"
Icon "wind4.ico"
VIProductVersion 2.67.0.00000
VIAddVersionKey ProductName "HelloFX"
VIAddVersionKey LegalCopyright "Copyright (c) 2011-2018 Chris Mason"
VIAddVersionKey FileDescription "Dynamic Templating Tool"
VIAddVersionKey FileVersion 2.67.0.00000
VIAddVersionKey ProductVersion "2.67 / OpenJRE 14.0.2 (x64)"
VIAddVersionKey InternalName "HelloFX"
VIAddVersionKey OriginalFilename "HelloFX.exe"
Section
SetOverwrite off
SetOutPath "$TEMP\jre-14.0.2-HelloFX"
File /r "jre-14.0.2\*"
InitPluginsDir
SetOutPath $PluginsDir
File "HelloFX.jar"
SetOutPath $TEMP
${GetParameters} $R0
nsExec::Exec '"$TEMP\jre-14.0.2-HelloFX\bin\javaw.exe" -jar "$PluginsDir\HelloFX.jar" $R0'
RMDir /r $PluginsDir
SectionEnd
选择NSIS脚本,右键运行Compile NSIS Script就可以生成exe了。
最终运行效果如下:
注意:
- 使用javaw.exe运行jar不会出现控制台;
- NSIS打包生成的EXE会在运行时解压到C:\Users\dell\AppData\Local\Temp中,本例中生成jre-14.02路径。如果两次打包生成的jre不同,NSIS不会删除原有的jre可能造成软件运行出错。
- 为了区分不同软件及版本,可在
$TEMP\jre-14.0.2
后加入标识字符串,如本例中设置为$TEMP\jre-14.0.2-HelloFX
- 我在使用nsExec::Exec打包时发现窗口不显示,于是修改了nsis-3.06.1-src\Contrib\nsExec\nsExec.c的代码,生成了新的nsExec.dll,并将其放到NSIS插件路径NSIS\Plugins\x86-unicode下。
GetStartupInfo(&si); // Why?
si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
si.wShowWindow = TRUE; // 修改SW_HIDE为TRUE,否则不显示窗口了
si.hStdInput = newstdin;
si.hStdOutput = newstdout;
si.hStdError = newstdout;
为了生成nsExec.dll需要下载zlib开发环境,并编译NSIS:
设置zlib环境:
set ZLIB_W32=E:\programming\c++\zlib
编译NSIS
scons UNICODE=yes SKIPUTILS="NSIS Menu"
修改nsExec.c代码后,生成nsExec.dll
scons SKIPSTUBS=all SKIPUTILS=all SKIPMISC=all UNICODE=yes