如何在 Java 中创建独立的 .exe(无需安装程序和 JRE 即可运行)

Dan*_*hev 21 java exe javafx

如何在没有程序安装程序的情况下.exe为我的项目(我在 IntelliJ IDEA 中编写)制作独立的 Windows 可执行文件( )JavaFX?我希望用户下载该.exe文件并开箱即用,无需安装程序,即使他们的计算机上没有 JRE。这可能吗?到目前为止,我已经阅读了一些有关以下选项的内容:

  • launch4j - 似乎将所需的 JRE文件.exe
  • install4j - 它创建一个安装程序,一旦运行,就会创建.exe文件。

所以,如果我理解正确的话,这两者都不会帮助我。我找到了这个这个帖子,但它们不涵盖我的具体案例。对不起,如果我问了一个愚蠢的问题,这是我的第一个 Java GUI。

jew*_*sea 24

解决方案

用于warp-packer创建exe由 所创建的图像和应用程序启动器jlink

第一的:

  1. 下载warp-packer。
  2. 使用 jlink 为您的应用程序生成图像。

然后,创建单个文件应用程序可执行文件。这可以通过一个命令来完成(在一行上运行它并使用您的值而不是变量%%):

 %WARP_DIR%\warp-packer 
   --arch windows-x64 
   --input_dir %APP_JLINK_IMAGE_DIR% 
   --exec %APP_JLINK_LAUNCHER_BAT_FILE% 
   --output %APP_SINGLE_EXECUTABLE_FILE_NAME%
Run Code Online (Sandbox Code Playgroud)

该命令可以从命令行手动运行,也可以通过适当的构建工具插件自动运行。

可以使用最适合您的构建环境的方式调用 jlink;例如:maven 插件、gradle 插件、命令行实用程序、jpackage实用程序或 jpackage 构建工具插件等之一。

相关答案

这个想法不是我的,是在这里提出的:

教程

如果需要更多信息,请参阅完整的教程示例。

解决方案描述

这个答案很长,因为它试图提供一个完整的示例以及额外的上下文建议。它可以更简洁。它的风格更接近于教程或博客文章风格的帖子,而不是 StackOverflow 的答案。希望这个长度不会令人生畏,并且很容易复制结果。

我对此很好奇,所以我想尝试一下。令我惊讶的是,我能够让它发挥作用。所以我在这里记录了如何复制它。

关键是“OH GOD SPIDERS”评论中的建议,即使用“warp”工具进行打包,并结合其他建议与jlink进行交互的评论。

我尝试使用Maven构建工具做尽可能多的事情,所以这个解决方案就是面向于此的。如果您愿意,您可以将该解决方案改编为另一个工具链。

该解决方案示例使用 FXML 构建 JavaFX 应用程序。如果不包含 FXML,该示例可能会更简单、更小,但我认为展示资源如何与此解决方案配合使用非常重要,这就是包含 FXML 的原因。

局限性

  • 根据设计,这是一个仅限 Windows 的构建解决方案,必须在构建时以及部署和运行时在 Windows 计算机上运行。

  • 它仅适用于依赖具有module-info.java定义的 Java 模块的应用程序。例如,除非它是完全模块化的,否则它不适用于 Spring 或 SpringBoot 应用程序。直到发布具有完整 Java 平台模块支持的Spring 6 或 SpringBoot 3为止。

高级步骤

  1. 将应用程序构建为Java 平台模块化应用程序

    • 应用程序必须没有自动依赖项(应用程序本身及其依赖的所有传递依赖项必须定义为具有正确定义的 module-info.java 文件的 Java 模块)。
  2. 链接应用程序以使用启动脚本创建运行时映像。

  3. 将带有启动脚本的运行时映像转换为 exe。

程序

  1. 安装 JDK 17(不需要包含 JavaFX 的版本)。
  2. 安装 Maven
  3. 创建如下所示的项目文件。
  4. 安装扭曲tools\warp-packer.exe.
  5. 构建并打包项目 ( mvn package)。
  6. 运行应用程序 exe ( target/hellowarp.exe) 进行测试。
  7. 将应用程序 exe 送给使用 Windows 机器的朋友。
  8. 朋友将能够从命令行或通过双击 exe 来运行 exe。

无需安装应用程序,无需提取或解压缩任何档案,无需安装 Java 运行时,也无需其他额外安装。所需要做的就是将 exe 文件复制到 Windows 计算机(例如,单击网络上的下载链接或从邮件附件中复制 exe),然后双击 exe 文件即可立即运行您的应用程序。

文件树

C:\dev\hellowarp>tree /a /f 。
卷本地磁盘的文件夹路径列表
卷序列号为 00000086 C034:A84E
C:\DEV\HELLOWARP
| pom.xml
|
+---源代码
| \ - -主要的
| +---java
| | | 模块信息.java
| | |
| | \---com
| | \ - -例子
| | \---hellowarp
| | HelloController.java
| | HelloWarp.java
| |
| \ - -资源
| \---com
| \ - -例子
| \---hellowarp
| 你好视图.fxml
|
\ - -工具
        warp-packer.exe

获取并安装warp

\tools在项目的根目录中创建一个新目录。

从以下位置下载扭曲:

并将 warp 可执行文件复制(重命名)到以下位置:

\tools\warp-packer.exe
Run Code Online (Sandbox Code Playgroud)

文件

pom.xml

Maven 项目。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>hellowarp</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>17</java.version>
        <javafx.version>17.0.1</javafx.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>${javafx.version}</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-fxml</artifactId>
            <version>${javafx.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!--compile-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
             <!--create linked image-->
            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>0.0.8</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>jlink</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <mainClass>com.example.hellowarp/com.example.hellowarp.HelloWarp</mainClass>
                    <compress>2</compress>
                    <noManPages>true</noManPages>
                    <noHeaderFiles>true</noHeaderFiles>
                    <stripDebug>true</stripDebug>
                    <launcher>${project.artifactId}</launcher>
                </configuration>
            </plugin>
            <!--package image as an exe-->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>3.0.0</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>exec</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <!-- obtain warp-packer.exe from: "https://github.com/dgiagio/warp/releases/download/v0.3.0/windows-x64.warp-packer.exe" -->
                    <executable>${project.basedir}\tools\warp-packer.exe</executable>
                    <arguments>
                        <argument>--arch</argument>
                        <argument>windows-x64</argument>

                        <argument>--input_dir</argument>
                        <argument>${project.build.directory}\image</argument>

                        <argument>--exec</argument>
                        <argument>bin\${project.artifactId}.bat</argument>

                        <argument>--output</argument>
                        <argument>${project.build.directory}\${project.artifactId}.exe</argument>
                    </arguments>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
Run Code Online (Sandbox Code Playgroud)

模块信息.java

应用程序的 Java 平台模块定义。

module com.example.hellowarp {
    requires javafx.controls;
    requires javafx.fxml;

    opens com.example.hellowarp to javafx.fxml;
    exports com.example.hellowarp;
}
Run Code Online (Sandbox Code Playgroud)

HelloWarp.java

JavaFX 应用程序。

package com.example.hellowarp;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;

public class HelloWarp extends Application {
    @Override
    public void start(Stage stage) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(
                HelloWarp.class.getResource(
                        "hello-view.fxml"
                )
        );

        Scene scene = new Scene(fxmlLoader.load());

        stage.setTitle("Hello!");
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch();
    }
}
Run Code Online (Sandbox Code Playgroud)

HelloController.java

JavaFX FXML 控制器类。

package com.example.hellowarp;

import javafx.fxml.FXML;
import javafx.scene.control.Label;

public class HelloController {
    @FXML
    private Label welcomeText;

    @FXML
    protected void onHelloButtonClick() {
        welcomeText.setText("Welcome to my JavaFX Application!");
    }
}
Run Code Online (Sandbox Code Playgroud)

你好视图.fxml

UI 视图定义文件。

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>

<?import javafx.scene.control.Button?>
<VBox alignment="CENTER" spacing="20.0" prefWidth="250" xmlns:fx="http://javafx.com/fxml"
      fx:controller="com.example.hellowarp.HelloController">
    <padding>
        <Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
    </padding>

    <Label fx:id="welcomeText"/>
    <Button text="Hello!" onAction="#onHelloButtonClick"/>
</VBox>
Run Code Online (Sandbox Code Playgroud)

hellowarp.exe正在运行的应用程序的屏幕截图

你好屏幕截图

常问问题

常见问题解答部分仅提供上下文信息。如果您已经知道此信息或者不需要它,则可以忽略此部分。

这是“fat jar”的替代分发方法吗?

是的,我想是这样。

这适合什么用途?

分布在您知道用户正在运行 Windows 的环境中的小型应用程序。

我还可以将我的应用程序打包为 MSI 安装程序吗?

是的。我使用akman jpackage-maven-plugin做到了这一点,效果很好。为了限制大小和范围,我不会在此答案中记录这一点。

使用“git repo”、“fat jar”、exe、打包安装程序或“压缩”映像会更好吗?

这取决于你在做什么。

如果您的目标是其他开发人员,请在 github 上建立一个帐户,将您的项目放在那里,并为开发人员提供一个 Maven 或 gradle 构建文件,以便开发人员在其环境中从源代码构建应用程序。只需将应用程序打包为标准 jar 文件(无 fat jar)就可以了。您创建的任何 jar 都可以部署到 Maven 中心。使用 module-info.java 作为 jar,以便可以通过 jlink 将其链接到打包的应用程序中。

如果是学校项目。这取决于学校的录取偏好。也许他们只是想要 git 中的代码源,而这就是你所需要的。或者,也许您可​​以创建您提供的(薄)jar 文件(或包含 jar 及其依赖项的 zip),因为您知道标准学校系统上已安装了所有相关的 Java/JavaFX 软件。

或者它可能是已知的操作系统环境,例如 Windows、Mac 或 Linux,您可以使用它jpackage为其中一个(或两个)环境构建可安装包。

或者,如果只是 Windows,这种打包为“exe”进行分发的解决方案可能会很有效。

JavaFX 开发不支持“fat jar”配置。我不推荐它。您可以让它工作(目前),有时它会很方便,但您需要决定为此进行的权衡是否值得。

如果您正在构建商业或流行的开源桌面产品,请使用适合jpackage您的目标平台的工具(或商业或开源替代品之一)创建打包安装程序(例如,适用于 Windows 的 msi 或 exe、rpm 和Linux 为 deb,Mac 为 dmg)。您可以选择将这些打包格式部署到 Windows 或 Mac 应用商店或 Linux yum/apt 存储库。

如果是移动部署,请使用gluon mobile

我可以使用 Apache jlink Maven 插件而不是 OpenJFX Maven 插件吗?

OpenJFX JavaFX Maven 插件akman jpackage-maven-plugin此时将生成正确的图像。

目前,Apache jlink Maven 插件将失败(使用 JavaFX 17.0.1 和 Apache jlink 插件 3.1.0)。

当我尝试使用 Apache jlink Maven 插件时,它对 JavaFX 平台模块定义感到困惑。Apache jlink 插件开始使用奇怪的虚拟模块名称,例如javafx.graphicsEmpty它被视为自动模块并传递给 jlink,因此 jlink 拒绝链接它们。我找不到解决这个问题的方法。

当我双击该 exe 时,exe除了我的应用程序窗口之外,还会出现标题栏中带有该名称的空白窗口。

是的。根据应用程序的不同,这可能是一个小麻烦,也可能是一个阻碍。

双击时显示黑屏正是此解决方案(如此处所示)的工作方式。

可能有办法规避这个问题,但我还没有对此进行大量调查。您可以查看此处提供的信息(其中讨论了在 MS Windows 中隐藏或最小化应用程序启动器窗口的各种方法),看看它是否对您有帮助:

如果您不是双击应用程序,而是通过在命令控制台中键入 exe 名称来运行应用程序,则不会出现其他屏幕,因为您正在输入的现有控制台已经存在。

我可以使用此技术为其他操作系统创建单个文件可执行文件吗?

是的,我相信是这样。

目前,我还没有尝试将此解决方案用于除 Windows 可执行文件之外的任何内容。

warp-packer是,能够为各种操作系统生成可执行文件。

要打包非 Windows 机器,您需要将jlink目标操作系统的适当图像输出输入到 warp-packer,然后运行适当的 warp-packer 实用程序(我相信在目标操作系统上)以生成单个可执行文件在该目标操作系统上执行。

如果有兴趣,请参阅 warp-packer 和 jlink 文档。

生成的可执行文件的大小是多少?

对于示例应用程序,我生成的应用程序可执行文件大小为 34 MB。

启动时间是多少?

我没有测量它,但启动时间(双击 exe 后显示应用程序 GUI 窗口的时间)似乎约为一秒。

我可以为非模块化 Java 项目创建一个 exe 吗?

可能是的,但这超出了我准备在这里讨论的范围,并且该方法将与这里描述的方法不同。