前幾天寫了兩篇關於JFX+IDEA打包跨平臺應用的文章,這篇是使用IDEA自帶功能打包的,這篇是使用Maven進行打包的,可是效果不太滿意,由於從JDK9開始實現模塊化,同時JFX部分從JDK中獨立出來了,也就是說須要默認JDK再也不自帶JFX。這意味着外部依賴須要手動處理module-info.java,這是一件很是麻煩的事情。java
其實不使用Maven也能打包發佈跨平臺JFX應用,可是沒有使用Maven的話,雖然打包出來能直接運行無需jre環境,可是,管理依賴確實麻煩,在使用jlink打包一些外部的jar時,對於一些比較簡單的jar仍是比較舒服的,參照這裏: linux
首先去下載jar,接着生成module-info.java,而後使用jdeps檢查依賴,添加對應的jar到路徑中,編譯生成module-info.java接着更新原來的jar便可。看起來簡單,可是筆者碰到了okhttp這種jar,依賴簡直環環相扣致使筆者放棄了這種方式。git
使用Maven能夠完美解決依賴問題,多虧與強大的pom.xml,幾行<dependency>就能夠解決依賴問題,可是,仍是須要手動處理module-info.java,並且IDEA文檔明確代表僅支持Java8的打包爲jar:github
所以,這篇文章採起一種最簡單的方式利用Maven打包發佈JFX11應用。apache
默認便可,問題不大。bash
<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」。app
同時指定編碼與JDK:maven
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties>
不然會如此報錯:模塊化
新建一個包再新建Main.java,Launcher.java以及Main.fxml:ui
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");
此時應該是沒有運行配置的狀態,點擊Add Configuration:
添加Application:
添加Launcher類做爲Main class:
這時候run就沒問題了:
雖然如今能夠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類的異常:
理論上來講,只須要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>
修改成程序入口類。
此時再從右側欄打包選中Maven,package便可:
可是會有警告:
由於一些class文件重複了,可是也提到了一般來講這是沒有危害的而且能夠跳過警告,或者修改pom.xml去手動排除某些依賴。
直接在IDEA中右鍵運行或者-jar運行,能夠看到沒有異常了:
相比起原來自帶的Maven打包插件,主要是多了javafx的一些class以及對應平臺所須要的一些動態庫文件等,好比win上的.dll與linux上的.so文件。
這樣一個跨平臺的JFX jar包就製做好了,只需
java -jar
便可跨平臺運行。