生成 Windows EXE 啟動器
打包時可以為受保護的應用生成一個原生 Windows 啟動程式。它是純 Win32 執行檔,雙擊即可執行應用,不需要使用者先安裝 Java,也不需要使用者看到 run.bat。
EXE 是可選項,預設不生成。啟用後,生成的包裡同時保留原有的 run.sh / run.command / run.bat,兩種啟動方式使用完全相同的歸檔、類路徑、主類和 JVM 引數。
1. 適用範圍
| 專案 | 支援情況 |
|---|---|
| 應用型別 | Java Application、Spring Boot(三種佈局均可)、Tomcat |
| 目標平臺 | windows-x64、windows-x86、windows-aarch64 |
| 不支援 | Library Encryption(單個 .p4jx 歸檔沒有可啟動的應用目錄) |
必須至少選擇一個 Windows 目標平臺。同時選擇 Linux 或 macOS 平臺不會導致任務失敗:這些平臺的子包照常生成,只是沒有 EXE,仍使用原有啟動指令碼。所有目標平臺都不是 Windows 時,任務會直接報錯。
2. GUI 操作
- 在選擇輸入檔案和目標平臺的頁面上勾選 生成 Windows 應用 EXE(x64/x86/ARM64),並至少選擇一個 Windows 目標平臺。
- 這個開關位於簡單模式和高階模式的分叉之前,因此兩種模式都可以生成 EXE。
- 勾選後會多出一個 Windows EXE 啟動器 頁面,用於填寫檔名、啟動器模式、圖示和 Windows 版本資訊。不勾選則直接進入最終確認頁。
- 啟用 EXE 後,JVM 啟動引數 輸入框只出現在這個啟動器頁面上,避免同一項引數出現兩個入口。填寫的引數同時寫入 EXE 和啟動指令碼。
- 最終確認頁會列出實際會生成 EXE 的平臺,以及填寫過的啟動器欄位。
3. CLI 示例
最簡形式,只需 --windows-exe:
p4j --target-platform windows-x64 javaapp app.jar dist --windows-exe
指定檔名和視窗模式:
p4j --target-platform windows-x64 javaapp app.jar dist \
--windows-exe \
--exe-name MyApp.exe \
--exe-mode gui \
--exe-icon assets/app.ico
一次生成三種 Windows 架構,並填寫完整的版本資源:
p4j --target-platform windows-x64,windows-x86,windows-aarch64 \
springboot app.jar dist \
--windows-exe \
--exe-name MyService \
--exe-file-version 1.4.2.0 \
--exe-product-version 1.4.2.0 \
--exe-company 'Example Inc.' \
--exe-product 'Example Service' \
--exe-description 'Example background service' \
--exe-copyright 'Copyright (C) 2026 Example Inc.'
Tomcat 包同樣支援,生成的 EXE 以前臺方式啟動內嵌 Tomcat:
p4j --target-platform windows-x64 tomcat app.war dist --context /demo --windows-exe
4. 引數說明
| 選項 | 說明 |
|---|---|
--windows-exe | 啟用 EXE 生成 |
--exe-name <name> | EXE 檔名;留空則使用輸入檔名,Tomcat 使用 tomcat |
--exe-mode <mode> | console(預設)或 gui |
--exe-icon <ico> | Windows 圖示檔案,.ico 格式,可選 |
--exe-file-version <a.b.c.d> | PE 檔案版本 |
--exe-product-version <a.b.c.d> | PE 產品版本 |
--exe-company <text> | 公司名稱 |
--exe-product <text> | 產品名稱 |
--exe-description <text> | 檔案說明,顯示在工作管理員和檔案屬性中 |
--exe-copyright <text> | 版權宣告 |
任意一個 --exe-* 選項都會自動啟用 EXE 生成,不必額外再寫 --windows-exe。
檔名只能是檔名,不能包含 /、\ 或目錄部分;沒有 .exe 字尾時自動補上。
兩個版本號欄位的規則相同:1 到 4 段用英文句點分隔的數字,每段取值 0 到 65535,例如 1.0.0.1。Windows 把每段存成 16 位無符號整數,所以不接受 v1.0、1.0-beta 這類帶字母或空格的寫法。留空表示 0.0.0.0。這兩個欄位在打包開始前校驗,不會等到打包中途才失敗。
5. 輸出結構
以 Java Application 為例,EXE 與啟動指令碼並列在包根目錄:
dist/
├── MyApp.exe # 新增的 Windows 啟動器
├── app.p4jx
├── vlxjre/
├── lib/
├── run.sh
├── run.command
├── run.bat
└── README.md
包內的 README.md 會列出生成的 EXE 檔名,並附上程式碼簽名提示。
6. 執行行為
EXE 所在目錄就是應用根目錄。啟動器只接受根目錄以內的執行時、歸檔、類路徑和工作目錄;指向包外的路徑、以及用符號連結或聯接點替換過的路徑都會被拒絕,程序不會啟動。這意味著可以整包移動或改名,但不能把 EXE 單獨複製出來使用。
| 行為 | 說明 |
|---|---|
| 執行時 | 固定使用包內 vlxjre\bin\java.exe,不使用系統 Java,也不讀取 JAVA_HOME |
| 命令列引數 | 傳給 EXE 的引數原樣追加到應用引數之後 |
| 控制台模式 | 繼承當前控制台的標準輸入輸出,等待應用結束並返回應用的退出碼 |
| GUI 模式 | 不建立控制台視窗,適合桌面應用 |
| 環境變數 | 啟動前清除 JAVA_TOOL_OPTIONS、_JAVA_OPTIONS、JDK_JAVA_OPTIONS 和 CLASSPATH,避免外部注入改變啟動引數 |
EXE 的 JVM 引數在打包時固化並隨引數塊一起簽名,執行時校驗,不能在部署後修改。APP_JAVA_OPTS 只對 run.bat 有效,EXE 不讀取它。需要改動 EXE 的 JVM 引數時,請重新打包。
出於同樣的原因,-javaagent、-agentlib、-agentpath、-Xbootclasspath 和 --patch-module 不允許寫入 EXE 的啟動引數。用 --jvm-option 傳入這些引數時,打包會直接失敗。
7. 程式碼簽名
Protector4J 不為生成的 EXE 附加發布者簽名,也不接觸任何 Authenticode 憑據。圖示、版本資源和啟動引數等所有 PE 修改都在打包階段完成,因此簽名步驟應放在最後:
- 完成打包,確認 EXE 能正常啟動應用。
- 用你自己的證書做 Authenticode 簽名,並加 RFC3161 時間戳。
- 用 Windows 的
/pa策略驗籤。
簽名完成後不要再修改這個 PE 檔案,任何改動都會使簽名失效。需要更換圖示或版本號時,請重新打包並重新簽名。
8. 任務檔案欄位
匯出的 p4j-task.yml 使用版本 2,啟用 EXE 時儲存以下欄位。版本 1 的任務檔案仍可正常讀取。
windowsExe: true
exeName: MyApp.exe
exeMode: console
exeIcon: assets/app.ico
exeFileVersion: 1.4.2.0
exeProductVersion: 1.4.2.0
exeCompany: Example Inc.
exeProduct: Example Service
exeDescription: Example background service
exeCopyright: Copyright (C) 2026 Example Inc.
9. 常見問題
| 現象 | 原因與處理 |
|---|---|
| 提示需要 Windows 目標平臺 | 啟用了 EXE 但沒有選擇任何 windows-x64、windows-x86 或 windows-aarch64 目標 |
| 提示版本號格式不正確 | 版本欄位含字母、空格或超過 4 段,或某段超出 0 到 65535 |
| 提示 EXE 名稱只能是檔名 | 檔名裡帶了路徑分隔符,改成不含目錄的名字 |
| 提示找不到圖示檔案 | --exe-icon 指向的 .ico 不存在,檢查路徑 |
| 雙擊後閃退且沒有視窗 | 用的是 GUI 模式而應用啟動失敗,改用控制台模式重新打包即可看到錯誤輸出 |
| 單獨複製出來的 EXE 無法執行 | 啟動器要求執行時和歸檔位於同一個包目錄內,請複製整個輸出目錄 |