簡體   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