首次接触javafx,
打成exe的方式有很多种(注意是模块化项目,还是非模块化的。 jdk9的项目 支持模块化,项目中仅有一个module-info )官方写了很多,但实现起来,总有毛病。项目使用maven,只看了maven的,Gradle 不搞
- 打成jar,用exe4j 将环境打进exe
- jdk1.8的 Javapackage
- jdk14+的 jpackager (模块化/非模块化,本文实现的是非模块化的)
经多次尝试,最后试出来第三种 成功。
非模块化的,需要用一个类去启动,main-class不能是extends Application的文件
public class Launch {
public static void main(String[] args) {
Application.launch(Main.class, args);
}
}
最终效果
- 安装包
- 执行安装程序
- 添加到了桌面快捷
文件夹内容
使用maven插件maven-shade-plugin(生成与依赖包一起打的.jar包),jdk14+ jpackage(打成.exe)
1. clean,package 将依赖一起打包成 xx-shade.jar(名称pom里指定)部分代码在文章最后
这里包名,前缀包名+版本号(1.0.0)。程序更新后 将以这个格式修改.cfg中配置 (例如:xx-shade_1.0.0.jar)
.cfg 指定运行jar包。
.cfg 配置文件内容第一个版本的包名必须是程序中设定的格式 Upgrader.JAR_NAME_PREFIX,否则首次更新无法成功修改(根据整个包名 做替换,不是重写配置)
[Application] app.classpath=$APPDIRpeg-1.0-SNAPSHOT-shade_1.0.6.jar app.mainclass=org.dy.Launch [JavaOptions] java-options=-Djpackage.app-version=1.0
2. 将生成的jar,复制一份到lib文件夹(任意)下版本号:不能大于9,大于9的,自行进1。计算的版本号码方式是 去掉.的百分数(1.0.1 -> 101,1.1.2 -> 112)
3. 可设置exe图标,一并放在以上文件夹lib下,再添加命令 --icon lib图标.ico 4. 通过jdk14+ 带的工具jpackage进行打包。修改包名,与项目内设定的一致。后续更新jar包名也需一致
命令:jpackage --name peg --input lib --main-class org.dy.Launch --main-jar peg-1.0-SNAPSHOT-shade.jar --icon liblogo.ico --vendor dyjx --win-dir-chooser --win-shortcut --win-menu --win-menu-group "packaging" --name 安装exe的名称 --input 要打包的路径 --main-class 启动类 --icon exe图标,这里格式win得使用ico的文件,不然打不出来包。路径也得在input下。 --main-jar lib里面的jar,打包的时候也是指定的--main-class 所指的类 --vendor 安装后应用程序的作者,控制面板查看 --win-dir-chooser 安装时添加 “选择安装路路径" --win-shortcut 安装后自动在桌面添加快捷键 --win-menu 添加到系统菜单中 --win-menu-group "packaging" 如果没有–win-menu 会报 311 错误
更多,cmd 中使用 jpackage -h 查看命令操作(可以不使用安装程序,直接生成)
版本号计算方法,去掉.的百分数(1.0.1 -> 101,1.1.2 -> 112)
private static int versionToInt(String version) {
String[] items = version.split("\.");
int versionInt = 0;
for (String item : items) {
versionInt *= 10;
versionInt += Integer.parseInt(item.trim());
}
return versionInt;
}
修改配置
public void writeVersionInfo() {
String rootPath = JarUtil.getRootPath();
File file = new File(rootPath + "/xx.cfg");
List versionInfo = new ArrayList<>();
if (file.isFile() && file.exists()) {
try {
FileInputStream fileInputStream = new FileInputStream(file);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String text = "";
while ((text = bufferedReader.readLine()) != null) {
versionInfo.add(text);
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 写回去
FileWriter fw = null;
try {
fw = new FileWriter(file);
for (String s : versionInfo) {
if (s.indexOf("app.classpath=$APPDIR\" + Upgrader.JAR_NAME_PREFIX + Upgrader.CURRENT_VERSION +".jar") != -1) {
fw.write("app.classpath=$APPDIR\" + Upgrader.JAR_NAME_PREFIX + Upgrader.NEW_VERSION + ".jarn");
continue;
}
fw.write(s + "n");
}
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
JarUtil
public static String getRootPath() {
String path = JarUtil.class.getProtectionDomain().getCodeSource().getLocation().getPath();
if (!path.isBlank()) {
if (System.getProperty("os.name").contains("dows")) {
path = path.substring(1);
}
if (path.contains("jar")) {
path = path.substring(0, path.lastIndexOf("."));
return path.substring(0, path.lastIndexOf("/"));
}
}
return path.replace("target/classes/", "");
}
pom.xml
src/main/java ***.css src/main/resources org.apache.maven.plugins maven-compiler-plugin3.8.1 ${maven.compiler.release} org.apache.maven.plugins maven-shade-plugin3.0.0 package shade true project-classifier target/${project.artifactId}-${project.version}-shade.jar org.dy.Launch



