繁体   English   中英

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

[英]How to create a standalone .exe in Java (that runs without an installer and a JRE)

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

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

所以,如果我理解正确,这两个都不会帮助我。 我发现了这个这个帖子,但它们没有涵盖我的具体情况。 对不起,如果我问一个愚蠢的问题,这是我第一次使用 Java GUI。

解决方案

使用warp-packerjlink创建的图像和应用程序启动器中创建一个exe

第一的:

  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%

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

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

相关答案

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

教程

如果需要更多信息,以下是完整的教程示例。

解决方案说明

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

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

关键是“OH GOD SPIDERS”评论中的建议,使用“warp”工具进行打包,以及其他建议与jlink接口的评论。

我尝试尽可能多地使用Maven构建工具,所以这个解决方案就是面向这个的。 如果您愿意,可以将解决方案调整到另一个工具链。

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

限制

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

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

高级步骤

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

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

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

程序

  1. 安装 JDK 17 (不需要包含 JavaFX 的版本)。
  2. 安装 Maven
  3. 创建如下所示的项目文件。
  4. 将 warp 安装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 .
Folder PATH listing for volume Local Disk
Volume serial number is 00000086 C034:A84E
C:\DEV\HELLOWARP
|   pom.xml
|
+---src
|   \---main
|       +---java
|       |   |   module-info.java
|       |   |
|       |   \---com
|       |       \---example
|       |           \---hellowarp
|       |                   HelloController.java
|       |                   HelloWarp.java
|       |
|       \---resources
|           \---com
|               \---example
|                   \---hellowarp
|                           hello-view.fxml
|
\---tools
        warp-packer.exe

获取和安装warp

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

从以下位置下载 Warp:

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

\tools\warp-packer.exe

文件

pom.xml

马文项目。

<?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>

模块信息.java

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

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

    opens com.example.hellowarp to javafx.fxml;
    exports com.example.hellowarp;
}

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();
    }
}

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!");
    }
}

你好-view.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>

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

你好截图

常问问题

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

这是“胖罐”的替代分发方法吗?

是的,我想是这样。

这适合什么?

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

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

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

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

这取决于你在做什么。

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

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

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

或者,如果它只是 Windows,这种打包为“exe”的解决方案可能会很好地工作。

JavaFX 开发不支持“fat jar”配置 我不推荐它。 你可以让它工作(当前),它有时会很方便,但你需要决定这样做所涉及的权衡是否值得。

如果您正在构建商业或流行的开源桌面产品,请使用jpackage (或商业或开源替代品之一)等工具以适合您的目标平台的格式(例如 windows 的 msi 或 exe,rpm)创建打包的安装程序和 deb 用于 linux,dmg 用于 mac)。 您可以选择将这些打包格式部署到 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。

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

生成 exe 的绝对要求不是正确的做法,但如果必须这样做,那么https://docs.gluonhq.com/是唯一合理的方法。 否则,您应该结合 jlink 来查看 jpackage。 忘记所有关于肥罐和其他选择的讨论。 这不是如今构建 JavaFX 应用程序的方式。

为此,您必须生成一个 fat jar(如果您的 java 应用程序具有依赖项),如果它没有依赖项,请保持原样,然后使用 launch4j。 要创建一个胖罐子,请执行以下操作:

  1. 在 build.xml 文件中添加这组代码:

     <property name="store.jar.name" value="Master Data App"/> <property name="store.dir" value="store"/> <property name="store.jar" value="${store.dir}/${store.jar.name}.jar"/> <echo message="Packaging ${application.title} into a single JAR at ${store.jar}"/> <delete dir="${store.dir}"/> <mkdir dir="${store.dir}"/> <jar destfile="${store.dir}/temp_final.jar" filesetmanifest="skip"> <zipgroupfileset dir="dist" includes="*.jar"/> <zipgroupfileset dir="dist/lib" includes="*.jar"/> <manifest> <attribute name="Main-Class" value="sheetupdown.SheetUpDown"/> </manifest> </jar> <zip destfile="${store.jar}"> <zipfileset src="${store.dir}/temp_final.jar" excludes="META-INF/*.SF, META-INF/*.DSA, META-INF/*.RSA"/> </zip> <delete file="${store.dir}/temp_final.jar"/>
  2. 在您的 java IDE 中,右键单击 build.xml -> Run Target -> Other Targets -> package for store

  3. 你会在 store 文件夹中的项目中找到你的 fat jar。

  4. 打开launch4j

  5. 指定输出文件(以 .exe 结尾)

  6. 指定你的胖罐子在哪里

  7. (根据需要添加其他选项,例如:图标、jre 版本....)-可选-

  8. 单击构建包装器

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM