2024年11月4日 星期一

📝 JavaFX 筆記

最近接手與 Java FX 相關的專案

以下是編譯該專案的一些筆記

專案架構

專案資料夾架構如下

│  .classpath
│  .project
│  pom.xml
│
├─src
│  └─main
│      ├─java
│      │  │ Main.java 
│      │  │
│      │  └─com
│      │      └─example
│      │          └─fxtest
│      │                  App.java
│      └─resources
└─target

App.java 繼承 javafx.application.ApplicationMain.java 則是專案的 main class

POM 則如下:
pom.xml

為了方便,只留和 Java FX 、mvn package 相關的內容

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<dependencies>
		<dependency>
			<groupId>org.openjfx</groupId>
			<artifactId>javafx-controls</artifactId>
			<version>11</version>
		</dependency>
	</dependencies><build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<version>${version.maven-jar-plugin}</version>
				<configuration>
					<archive>
						<manifest><mainClass>Main</mainClass>
						</manifest>
						
					</archive>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.openjfx</groupId>
				<artifactId>javafx-maven-plugin</artifactId>
				<version>0.0.8</version>
				<executions>
					<execution>
						<id>default-cli</id>
						<configuration>
							<mainClass>Main</mainClass>
						</configuration>
					</execution>
				</executions>
			</plugin></plugins>
	</build>
</project>


錯誤: 遺漏執行此應用程式所需的 JavaFX 程式實際執行元件

我專案編譯時(mvn package),生出來的 .jar 檔執行時會出現

錯誤: 遺漏執行此應用程式所需的 JavaFX 程式實際執行元件

這問題是因為 JavaFX 的 libraries 不在 .jar 檔之中。

要修正的話,可以在 pom 把 org.apache.maven.plugins:maven-jar-plugin 改成 org.apache.maven.plugins:maven-shade-plugin 來解決。

maven-shade-plugin 能將所有使用到的 libraries 都加入至編譯好的 .jar ,這樣就不會出現 .jar 不包含 JavaFX 相關 libraries 的問題了。

maven-shade-plugin plugin 的內容
<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-shade-plugin</artifactId>
	<version>3.2.4</version>
	<executions>
		<execution>
		<phase>package</phase>
		<goals>
			<goal>shade</goal>
		</goals>
		<configuration>
			<transformers>
			<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
				<mainClass>Main</mainClass>
			</transformer>
			</transformers>
		</configuration>
		</execution>
	</executions>
</plugin>
更改後的 pom.xml
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<dependencies>
		<dependency>
			<groupId>org.openjfx</groupId>
			<artifactId>javafx-controls</artifactId>
			<version>11</version>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<!-- Maven Shade Plugin for creating a fat JAR -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-shade-plugin</artifactId>
				<version>3.2.4</version>
				<executions>
					<execution>
						<phase>package</phase>
						<goals>
							<goal>shade</goal>
						</goals>
						<configuration>
							<transformers>
								<transformer
									implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
									<mainClass>Main</mainClass>
								</transformer>
							</transformers>
						</configuration>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.openjfx</groupId>
				<artifactId>javafx-maven-plugin</artifactId>
				<version>0.0.8</version>
				<executions>
					<execution>
						<id>default-cli</id>
						<configuration>
							<mainClass>Main</mainClass>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>


建立安裝檔

若今天我是 java14(含)以上,可以使用 JDK 內建的 jpackage 來處理。

在那之前,需要先修改 pom,將自己專案所引用的 libraries 都複製到 target

複製 libraries

首先加上以下 plugin

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-dependency-plugin</artifactId>
	<version>3.1.2</version>
	<executions>
		<execution>
			<id>copy-dependencies</id>
			<phase>package</phase>
			<goals>
				<goal>copy-dependencies</goal>
			</goals>
			<configuration>
				<outputDirectory>${project.build.directory}</outputDirectory>
			</configuration>
		</execution>
	</executions>
</plugin>

<outputDirectory>的值是 libraries 的 .jar 檔複製的位置。可以根據自己的需求修改。我這邊是複製到專案的 target 資料夾。

增加完 plugin 後,執行 mvn clean package,target 資料夾除了先前專案的 jar外,還會多其他的 libraries 的 jar 檔。

jpackage

確認有複製libraries後,以我的專案為例,執行以下指令:

cd 專案資料夾
jpackage --name FXText --input target --main-jar myapp.jar --main-class Main --type msi

註:因為我的 main class 在 default package 資料夾,所以 --main-class 直接為 Main

就會在專案資料夾出現 FXText.msi 了。

Can not find WiX tools

jpackage 執行時,可能出現以下錯誤

[09:26:34.180] Can not find WiX tools (light.exe, candle.exe)
[09:26:34.180] Download WiX 3.0 or later from https://wixtoolset.org and add it to the PATH.
Error: Invalid or unsupported type: [exe]

雖然 log 建議你去 wixtoolset,但 wixtoolset 官網給的說明不會幫你下載 light.exe, candle.exe,而是直接安裝一個 wix.exe。

要下載 light.exe, candle.exe,建議直接去 wixtoolset的 github下載。

現在我去的時候,最新的版本是 WiX Toolset v3.14.1,進去後,下載 wix314-binaries.zip, 將之解壓縮,並把解壓縮後的位置加入 PATH 環境變數。

之後重新執行 jpackage 指令,應該就可以編譯了。

使用 pom plugin 來建置安裝檔

jpackage 的動作也可以加入至 pom 之中。

在 pom 加上以下 plugin:

plugin
<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>
			<configuration>
				<executable>${java.home}/bin/jpackage</executable>
				<arguments>
					<!-- 以下參數都和先前的 jpackage 相同 -->
					
					<argument>--name</argument>
					<argument>FXText</argument>
					<argument>--input</argument>
					<argument>target</argument>
					<argument>--main-jar</argument>
					<argument>myapp.jar</argument>
					<argument>--main-class</argument>
					<argument>Main</argument>
					<argument>--type</argument>
					<argument>exe</argument> <!-- 根據需求,也可以換成 msi  -->
				</arguments>
			</configuration>
		</execution>
	</executions>
</plugin>

如此一來,執行 mvn package 就能夠生成 FXText.exe 了


指定 Java 版本

jpackage 是 Java 14 才有的。

若我希望可以測試時,可以直接用 Java 11 編譯,但是最終要出正式版時,才用到 Java 14 的 jpackage,可以把 exec-maven-plugin plugin 放在單獨的 profile:

profile
<profiles>
	<profile>
		<id>package</id>
		<activation>
			<jdk>[14</jdk>
		</activation>
		<build>
			<plugins>
				<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>
							<configuration>
								<executable>${java.home}/bin/jpackage</executable>
								<arguments>
									<argument>--name</argument>
									<argument>FXText</argument>
									<argument>--input</argument>
									<argument>target</argument>
									<argument>--main-jar</argument>
									<argument>myapp.jar</argument>
									<argument>--main-class</argument>
									<argument>Main</argument>
									<argument>--type</argument>
									<argument>msi</argument>
								</arguments>
							</configuration>
						</execution>
					</executions>
				</plugin>
			</plugins>
		</build>
	</profile> 
</profiles>

這樣子,若使用 java 11 來編譯,就不會處理 jpackage;java 14 (含)以上才會

pom

最終我的 pom 如下

pom.xml
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<dependencies>
		<dependency>
			<groupId>org.openjfx</groupId>
			<artifactId>javafx-controls</artifactId>
			<version>11</version>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<!-- package 時,讓所有 libraries 都加入 .jar -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-shade-plugin</artifactId>
				<version>3.2.4</version>
				<executions>
					<execution>
						<phase>package</phase>
						<goals>
							<goal>shade</goal>
						</goals>
						<configuration>
							<transformers>
								<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
									<mainClass>Main</mainClass>
								</transformer>
							</transformers>
						</configuration>
					</execution>
				</executions>
			</plugin>
			<!-- mvn javafx:run 可以直接執行專案 -->
			<plugin>
				<groupId>org.openjfx</groupId>
				<artifactId>javafx-maven-plugin</artifactId>
				<version>0.0.8</version>
				<executions>
					<execution>
						<id>default-cli</id>
						<configuration>
							<mainClass>Main</mainClass>
						</configuration>
					</execution>
				</executions>
			</plugin>
			<!-- 複製所有的 library jar files 至 ${project.build.directory} -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-dependency-plugin</artifactId>
				<version>3.1.2</version>
				<executions>
					<execution>
						<id>copy-dependencies</id>
						<phase>package</phase>
						<goals>
							<goal>copy-dependencies</goal>
						</goals>
						<configuration>
							<outputDirectory>${project.build.directory}</outputDirectory>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
	<profiles>
		<!-- 
			使用 java14(含)以上進行 mvn package 時,自動生成安裝用的 msi 檔 
			如果專案本身就已經確定要使用 java14(含)以上的話,直接把這 profile 的 plugin 放在 project > build > plugins 就可以了
		 -->
		<profile>
			<id>package</id>
			<activation>
				<jdk>[14</jdk>
			</activation>
			<build>
				<plugins>
					<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>
								<configuration>
									<executable>${java.home}/bin/jpackage</executable>
									<arguments>
										<argument>--name</argument>
										<argument>FXText</argument>
										<argument>--input</argument>
										<argument>target</argument>
										<argument>--main-jar</argument>
										<argument>myapp.jar</argument>
										<argument>--main-class</argument>
										<argument>Main</argument>
										<argument>--type</argument>
										<argument>msi</argument>
									</arguments>
								</configuration>
							</execution>
						</executions>
					</plugin>
				</plugins>
			</build>
		</profile>
	</profiles>
</project>

參考資料

广告位招租!><!! (2024, April 16).WIX下载教程. CSDN. https://blog.csdn.net/m0_64776123/article/details/137831429

沒有留言:

張貼留言