JFX11+Maven+IDEA 發佈跨平臺應用的完美解決方案

1 概述

前幾天寫了兩篇關於JFX+IDEA打包跨平臺應用的文章,這篇是使用IDEA自帶功能打包的,這篇是使用Maven進行打包的,但是效果不太滿意,因爲從JDK9開始實現模塊化,同時JFX部分從JDK中獨立出來了,也就是說需要默認JDK不再自帶JFX。這意味着外部依賴需要手動處理module-info.java,這是一件非常麻煩的事情。

1.1 不使用Maven

其實不使用Maven也能打包發佈跨平臺JFX應用,但是沒有使用Maven的話,雖然打包出來能直接運行無需jre環境,但是,管理依賴確實麻煩,在使用jlink打包一些外部的jar時,對於一些比較簡單的jar還是比較舒服的,參照這裏
在這裏插入圖片描述
首先去下載jar,接着生成module-info.java,然後使用jdeps檢查依賴,添加對應的jar到路徑中,編譯生成module-info.java接着更新原來的jar即可。看起來簡單,但是筆者碰到了okhttp這種jar,依賴簡直環環相扣導致筆者放棄了這種方式。

1.2 使用Maven

使用Maven可以完美解決依賴問題,多虧與強大的pom.xml,幾行<dependency>就可以解決依賴問題,但是,還是需要手動處理module-info.java,而且IDEA文檔明確表明僅支持Java8的打包爲jar:
在這裏插入圖片描述
因此,這篇文章採取一種最簡單的方式利用Maven打包發佈JFX11應用。

2 新建Maven工程

在這裏插入圖片描述
默認即可,問題不大。
在這裏插入圖片描述

3 添加依賴

<dependencies>
	<dependency>
	    <groupId>org.openjfx</groupId>
	    <artifactId>javafx-base</artifactId>
	    <version>11</version>
	    <classifier>linux</classifier>
	</dependency>
	<dependency>
	    <groupId>org.openjfx</groupId>
	    <artifactId>javafx-base</artifactId>
	    <version>11</version>
	    <classifier>win</classifier>
	</dependency>
	<dependency>
	    <groupId>org.openjfx</groupId>
	    <artifactId>javafx-controls</artifactId>
	    <version>11</version>
	    <classifier>linux</classifier>
	</dependency>
	<dependency>
	    <groupId>org.openjfx</groupId>
	    <artifactId>javafx-controls</artifactId>
	    <version>11</version>
	    <classifier>win</classifier>
	</dependency>
	<dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-fxml</artifactId>
        <version>11</version>
        <classifier>linux</classifier>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-fxml</artifactId>
        <version>11</version>
        <classifier>win</classifier>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-graphics</artifactId>
        <version>11</version>
        <classifier>linux</classifier>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-graphics</artifactId>
        <version>11</version>
        <classifier>win</classifier>
    </dependency>
</dependencies>

需要再哪個平臺在classifier中指定即可。這裏是linux與win。mac的話直接“mac”。
同時指定編碼與JDK:

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
</properties>

否則會如此報錯:
在這裏插入圖片描述

4 新建Main

新建一個包再新建Main.java,Launcher.java以及Main.fxml:
在這裏插入圖片描述
Main.java:

package com.test;

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

public class Main extends Application {
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("/Main.fxml"));
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.setTitle("Hello World");
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Launcher.java:

package com.test;

public class Launcher {
    public static void main(String[] args) {
        Main.main(args);
    }
}

Main.fxml:

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

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>


<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/10.0.2-internal"
            xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.test.Main">
   <Label layoutX="228.0" layoutY="185.0" text="Hello World">
      <font>
         <Font size="25.0"/>
      </font>
   </Label>
</AnchorPane>

注意getResource中的fxml路徑,Main.fxml文件放在resources下,直接通過根路徑讀取:

getResource("/Main.fxml");

5 添加運行配置

此時應該是沒有運行配置的狀態,點擊Add Configuration:
在這裏插入圖片描述
添加Application:
在這裏插入圖片描述
添加Launcher類作爲Main class:
在這裏插入圖片描述
這時候run就沒問題了:
在這裏插入圖片描述

6 使用默認Maven打包

雖然現在可以run了,但是,如果直接使用默認的Maven打包的話:
在這裏插入圖片描述
在target下有一個jar,直接右鍵運行:
在這裏插入圖片描述
會提示no main manifest attribute:
在這裏插入圖片描述
也就是找不到Manifest中入口類。
jar實際上是一個class的壓縮包,與zip的區別是jar包含了一個MANIFEST.MF,MANIFEST.MF在META-INF下,一個示例文件如下:
在這裏插入圖片描述
有點類似與鍵值對的格式,MANIFEST.MF包含了jar文件的內容描述,並在運行時向JVM提供應用程序信息。注意該文件有嚴格的格式限制,比如第一行不能爲空,行與行之間不能存在空行。
一個暴力的解決辦法是直接解壓jar並修改裏面的MANIFEST.MF,添加

Main-Class: com.test.Launcher

但是這樣會報找不到Application類的異常:
在這裏插入圖片描述

7 添加新的打包插件

理論上來說,只需要jar包內的相同目錄下提供了javafx的jar或者class文件就不會拋出異常了,但是,如果依賴很多需要一個一個添加,這是一個痛苦的過程。
所以,爲了優雅地解決這個問題,引入一個叫maven-shade-plugin的插件即可:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.2.2</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <transformers>
                            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <mainClass>com.test.Launcher</mainClass>
                            </transformer>
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

最新版本請到官方github查看,使用時只需要修改:

<mainClass>xxx.xxx.xxx</mainClass>

修改爲程序入口類。

8 打包

此時再從右側欄打包選中Maven,package即可:
在這裏插入圖片描述
但是會有警告:
在這裏插入圖片描述
因爲一些class文件重複了,但是也提到了通常來說這是沒有危害的並且可以跳過警告,或者修改pom.xml去手動排除某些依賴。

9 運行

直接在IDEA中右鍵運行或者-jar運行,可以看到沒有異常了:
在這裏插入圖片描述
相比起原來自帶的Maven打包插件,主要是多了javafx的一些class以及對應平臺所需要的一些動態庫文件等,比如win上的.dll與linux上的.so文件。
在這裏插入圖片描述
這樣一個跨平臺的JFX jar包就製作好了,只需

java -jar

即可跨平臺運行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章