程序员老鬼

做了个Java打包工具,可双击启动了!

咱们的Java打包工具,终于能让写的Java程序也能像双击桌面上的应用一样,直接运行了,不用用户去安装什么JRE之类的依赖,像普通应用程序一样——直接双击!😎 作为一个Java开发者,咱们用Java写桌面应用程序,心里其实一直有个小心愿: 能不能让这些Java程序双击就运行呢? 日常开发里,我比较喜欢搞些小工具,比如用Swing来做一些实用工具,帮助自己和同事提升工作效率。 可一直有个槽点,那就是Java程序运行起来太“挑剔”了,没JRE不行不说,还得让用户自己去安装,这个使用门槛很高啊。 而且,对于用户来说,直接运行程序的体验才是王道!所以我一直想着能不能把Java程序搞成直接运行的格式,不需要JRE,能双击启动,操作更简单直接。那就来做个工具呗! 既然想搞打包,先看看现有的方案都有什么:

方案一:GraalVM

GraalVM可以把Java程序编译成原生可执行文件,省去了JRE的依赖,而且启动速度也快。 GraalVM的确有它的优势, 性能好,而且编译出来的文件跑起来是真流畅。 但它的缺点也不少,比如 构建过程复杂,对反射支持有限,写代码还得规避反射类的用法, 这对一些大项目来说真心麻烦。 再说了,如果代码调试都变得困难,那我还怎么愉快地修bug呢?😅

方案二:JLink

JLink这个工具可以生成自定义的JRE,将应用与JRE一起打包成二进制文件。对Java 9+的项目还挺方便,构建出来的文件基本不用担心兼容问题。 然而,JLink的构建也不算简单, 生成的文件体积还挺大,对小工具来说有些过重了, 压缩之后的体积比不上一个简简单单的EXE。

方案三:Exe4J

Exe4J则更偏向于创建一个EXE启动器,将Jar包与JRE打包在一起,提供了“近乎原生”的体验。 但Exe4J依赖JRE,如果JRE的版本不对,运行效果会打折扣,而且体积上也不够小巧精致。

方案四:批处理和压缩软件的结合

在一些情况下,我们会用批处理文件和压缩软件,生成一个自解压包,启动时调用批处理文件来检查并执行Java程序。 这个方案倒是灵活,调试起来也方便,但它依赖JRE而且不美观,尤其当我们希望应用显得“高大上”时,批处理窗口一闪,体验上就有点low了。

方案五:直接分发Jar包

这种方式最简单,直接把Jar包甩给用户。但这样操作的前提是用户已经安装了JRE,还得让用户手动打开命令行或者右键选择Java运行程序。用起来不够“便捷”,让用户有些无奈,尤其是非开发人员。 综上所述,这些方案各有优缺点,可就是没有一个能够在体验、便捷和性能上都达到“完美”。于是,就有了自己动手“造轮子”的念头!💡

3. 新方案:自制的打包工具登场!

于是我决定开发一个自用的打包工具,把各种方案的优点结合起来,同时规避它们的缺点。这个工具需要什么功能呢?核心需求就是能让Java程序打包成双击就能运行的EXE文件,不需要用户去配置环境、安装JRE之类的繁琐操作。

技术栈选择

为了实现这个目标,我选择了WinForm来开发前端界面。 WinForm相对简单易用,可以快速做出一个用户友好的图形界面,还能提供选项给用户配置一些细节。通过它的图形化界面,可以方便地完成打包操作,真正做到“一键打包”。

4. 示例代码

说干就干!下面我就用一个简单的Swing项目给大家展示一下项目结构和代码配置。

项目结构

这是一个简单的Swing应用项目,主要文件有 pom.xml 和核心代码 HelloSwing.java 。

pom.xml文件

这个文件里包含了Maven的基本配置和一些打包插件的设置。比如, maven-assembly-plugin 用于将依赖和代码打包成一个“胖Jar”,这样可以确保打包后的Jar包含所有依赖,运行时不用再额外配置。
<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>JavaPackageTool</artifactId>
  <version>1.0</version>
  <dependencies>
    <dependency>
      <groupId>com.formdev</groupId>
      <artifactId>flatlaf</artifactId>
      <version>1.1.2</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.1.0</version>
        <configuration>
          <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>
    </plugins>
  </build>
</project>

HelloSwing.java

这是应用的主入口。为了让界面看起来更现代,我用了FlatLaf这款美化库。这个小程序会显示一个窗口和一段简单的欢迎消息:
import javax.swing.*;
import com.formdev.flatlaf.FlatLightLaf;

public class HelloSwing {
    public static void main(String[] args) {
        FlatLightLaf.install();
        JFrame frame = new JFrame("Hello Swing");
        frame.setSize(400, 200);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        JLabel label = new JLabel("Hello, this is a Java desktop app!", SwingConstants.CENTER);
        frame.add(label);
        frame.setVisible(true);
    }
}

5. 使用步骤

打包流程

具体的打包流程如下:
  1. 使用Maven将项目打包成“胖Jar”。有了胖Jar,所有依赖都在同一个文件中,避免了运行时的依赖缺失问题。
  2. 使用JLink导出一个精简版的JRE,确保包含Java程序运行所需的基础模块,这样就不需要额外的JRE环境了。
  3. 使用自制的工具将胖Jar和精简版JRE打包成EXE文件。
最终的效果就是,一个EXE文件里包含了Java应用和JRE,用户只需要双击EXE文件就能运行Java程序。

效果展示

打包好的EXE文件运行起来就像普通的Windows应用,双击即可打开,再也不用为用户操作卡在“怎么安装Java”而担心了。

经过这番改造,我们的小工具终于变成了真正的“傻瓜式”应用,流畅、直接,用户体验up!

最后

这个Java打包工具让分发Java桌面应用变得更加便捷,算是用兴趣来解决了一个实际问题吧。Java写的工具也能变成双击运行的“原生”体验啦!
-END - ok,今天先说到这,老规矩,看完文章记得右下角给何老师点赞。 最后送给大家一个福利,我这里有一份搞副业的教程,这份教程里有 100+个搞钱小项目 : 网盘拉新核心玩法、公众号运营变现、 小红书虚拟资料引流 等,现在扫码加我微信,即可领取这份副业教程。 添加时备注: 副业