前几天写了两篇关于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
便可跨平台运行。