javafx非模块化,打包exe安装文件,并后续替换jar实现更新。个人记录

前景:将javafx打包成exe应用程序,并可实现在线更新。个人记录

首次接触javafx,
打成exe的方式有很多种(注意是模块化项目,还是非模块化的。 jdk9的项目 支持模块化,项目中仅有一个module-info )官方写了很多,但实现起来,总有毛病。项目使用maven,只看了maven的,Gradle 不搞

  1. 打成jar,用exe4j 将环境打进exe
  2. jdk1.8的 Javapackage
  3. jdk14+的 jpackager (模块化/非模块化,本文实现的是非模块化的)
    经多次尝试,最后试出来第三种 成功。

非模块化的,需要用一个类去启动,main-class不能是extends Application的文件

/**
 * @Description: 非模块化程序,得采用这种方式去启动 主程序。 可以正常打出exe启动。
 * @since: 2021/10/23 10:38
 */
public class Launch {
    public static void main(String[] args) {
        Application.launch(Main.class, args);
    }
}

最终效果

  1. 安装包
    -
  2. 执行安装程序
    在这里插入图片描述
  3. 添加到了桌面快捷

在这里插入图片描述
文件夹内容
在这里插入图片描述

打包操作,先打成jar,再命令打成exe

使用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包。

第一个版本的包名必须是程序中设定的格式 Upgrader.JAR_NAME_PREFIX,否则首次更新无法成功修改(根据整个包名 做替换,不是重写配置)

.cfg 配置文件内容

   [Application]
   app.classpath=$APPDIR\peg-1.0-SNAPSHOT-shade_1.0.6.jar
   app.mainclass=org.dy.Launch
   
   [JavaOptions]
   java-options=-Djpackage.app-version=1.0

版本号:不能大于9,大于9的,自行进1。计算的版本号码方式是 去掉.的百分数(1.0.1 -> 101,1.1.2 -> 112)

2. 将生成的jar,复制一份到lib文件夹(任意)下

在这里插入图片描述

修改包名,与项目内设定的一致。后续更新jar包名也需一致

3. 可设置exe图标,一并放在以上文件夹lib下,再添加命令 --icon lib\图标.ico

4. 通过jdk14+ 带的工具jpackage进行打包。

命令:jpackage --name peg --input lib --main-class org.dy.Launch --main-jar peg-1.0-SNAPSHOT-shade.jar --icon lib\logo.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<String> 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 + ".jar\n");
                    continue;
                }
                fw.write(s + "\n");
            }
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

JarUtil

    /**
     * 获取项目根文件夹目录
     * @return
     */
    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

    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.fxml</include>
                    <include>**/*.css</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <release>${maven.compiler.release}</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>
                            <shadedArtifactAttached>true</shadedArtifactAttached>
                            <shadedClassifierName>project-classifier</shadedClassifierName>
                            <outputFile>target/${project.artifactId}-${project.version}-shade.jar</outputFile>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>org.dy.Launch</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值