web-dev-qa-db-ja.com

非モジュラーJavaFXアプリケーションをパッケージ化する

私はJava 8アプリケーションで、JavaFXを使用し、メインクラスが拡張されているjavafx.application.Applicationです。現在、 、私はそれをファットjarとして配信し、Oracleで正常に動作しますJava 8。

OpenJDK 11で実行できるようになりました。JavaFXを追加するために、org.openjfxからのアーティファクトをクラスパスに追加し、ファットjarに含めています。コマンドラインからjarを起動すると、

Error: JavaFX runtime components are missing, and are required to run this
application

この問題を回避する方法が2つありました。

  1. 汚いもの:アプリケーションを拡張せず、モジュールチェックを回避する特別なランチャーを作成します。 を参照してくださいhttp://mail.openjdk.Java.net/pipermail/openjfx-dev/2018-June/021977.html
  2. クリーンなもの:--module-pathと--add-modulesをコマンドラインに追加します。このソリューションの問題は、エンドユーザーがアプリケーションをダブルクリックするだけで起動できるようにすることです。

回避策として1.を使用することもできますが、モジュール化されていないJavaFXアプリケーションの実行可能ファットjarをビルド/配信するための現在の方法(OpenJDK 11)は何なのでしょうか。誰か助けてもらえますか?

15
taranion

(モジュール化されていない)JavaFX 11エンドアプリケーションをパッケージ化/配布するためのいくつかのオプションがあります。それらのほとんどは公式のOpenJFX docs で説明されています。

このサンプル を参照として使用します。 Gradleも使用します。 Maven(異なるプラグイン)でも、ビルドツールなしでも同様のことができます(ただし、これはお勧めしません...)。ビルドツールは今日では必須です。

ファットジャー

これはまだ有効なオプションですが、モジュール式の設計を壊し、すべてをまとめてバンドルするため、推奨されるオプションではありません。また、注意しない限り、クロスプラットフォームではありません。

このサンプルでは、​​次のようなbuild.gradleファイルがあります。

plugins {
    id 'application'
    id 'org.openjfx.javafxplugin' version '0.0.5'
}

repositories {
    mavenCentral()
}

dependencies {
}

javafx {
    modules = [ 'javafx.controls' ]
}

mainClassName = 'hellofx.HelloFX'

jar {
    manifest {
        attributes 'Main-Class': 'hellofx.Launcher'
    }
    from {
        configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
    }
}

Launcherクラスの使用に注意してください。 OPで言及または説明されているように here 、ファットjarを作成するには、Applicationから拡張されていないランチャークラスが必要です。

./gradlew jarを実行すると、JavaFXクラスとyour現在のプラットフォームのネイティブライブラリを含むファットjar(約8 MB)が生成されます。

Java -jar build/libs/hellofx.jarは通常どおり実行できますが、同じプラットフォームでのみ実行できます。

OpenJFXドキュメントまたは here で説明されているように、クロスプラットフォームjarを作成できます。

この場合、3つのグラフィックjarを含めることができます。これらは、プラットフォームに依存するコードとライブラリを持つものです。ベース、コントロール、およびfxmlモジュールは、プラットフォームに依存しません。

dependencies {
    compile "org.openjfx:javafx-graphics:11.0.1:win"
    compile "org.openjfx:javafx-graphics:11.0.1:linux"
    compile "org.openjfx:javafx-graphics:11.0.1:mac"
}

./gradlew jarは、これら3つのプラットフォームに配布できるファットjar(19 MB)を生成します。

(メモメディアとWebには、プラットフォームに依存するコード/ネイティブライブラリもあります)。

したがって、これはJava 8で使用したときと同じように機能します。しかし、前に述べたように、モジュールの機能を壊し、最近のライブラリやアプリの配布方法に合わせていません。

これらのjarのユーザーがJREをインストールする必要があることを忘れないでください。

jlink

では、プロジェクトにカスタムイメージを配布する場合はどうでしょうか。これには、ネイティブJREとランチャーがすでに含まれています。

モジュール化されていないプロジェクトがある場合、それは機能しないと言うでしょう。そうだね。しかし、jpackageについて話す前に、ここで2つのオプションを調べてみましょう。

ランタイムプラグイン

badass-runtime-plugin は、非モジュールプロジェクトからランタイムイメージを作成するGradleプラグインです。

このbuild.gradleの場合:

plugins {
    id 'org.openjfx.javafxplugin' version '0.0.5'
    id 'org.beryx.runtime' version '1.0.0'
    id "com.github.johnrengelman.shadow" version "4.0.3"
}

repositories {
    mavenCentral()
}

dependencies {
}

javafx {
    modules = [ 'javafx.controls' ]
}

mainClassName = 'hellofx.Launcher'

runtime {
    options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
}

./gradlew runtimeを実行すると、ランチャーを含むランタイムが作成されるため、次のコマンドを実行できます。

cd build/image/hellofx/bin
./hellofx

これはシャドウプラグインに依存しており、Launcherクラスも必要です。

./gradlew runtimeZipを実行すると、約32.5 MBのこのカスタムイメージのZipを取得できます。

このZipを同じプラットフォームの任意のユーザーに配布できますが、JREをインストールする必要はありません。

他のプラットフォーム用のイメージのビルドについては targetPlatform を参照してください。

モジュラー化

私たちは非モジュール式のプロジェクトがあり、それを変更することはできないと考え続けています...しかし、それを変更するとどうなりますか?

モジュラー化することは大きな変更ではありません:module-info.Java記述子を追加し、必要なモジュールを含めますモジュール化されていないjar(自動名に基づく)。

同じサンプルに基づいて、記述子を追加します。

module hellofx {
    requires javafx.controls;

    exports hellofx;
}

そして今、私はコマンドラインでjlinkを使うか、それのためのプラグインを使うことができます。 badass-gradle-plugin は、前述の著者と同じ作者によるGradleプラグインであり、カスタムランタイムを作成できます。

このビルドファイルで:

plugins {
    id 'org.openjfx.javafxplugin' version '0.0.5'
    id 'org.beryx.jlink' version '2.3.0'
}

repositories {
    mavenCentral()
}

dependencies {
}

javafx {
    modules = [ 'javafx.controls' ]
}

mainClassName = 'hellofx/hellofx.HelloFX'

今すぐ実行できます:

./gradlew jlink
cd build/image/bin/hellofx
./hellofx

または./gradlew jlinkZipは、JREがインストールされていない場合でも、同じプラットフォームのマシンで配布および実行できるzipバージョン(31 MB)です。

ご覧のとおり、シャドウプラグインやLauncherクラスは必要ありません。 question のように、他のプラットフォームをターゲットにしたり、モジュール以外の依存関係を含めたりすることもできます。

jpackage

最後に、アプリケーションの配布に使用できる実行可能インストーラーを作成するための新しいツールがあります。

これまでのところGAのバージョンはまだありません(おそらくJava 13まで待たなければならないでしょう)が、現在Javaで使用するには2つのオプションがあります。 11または12:

Java/JavaFX 11では、Java 12のJPackagerでの最初の作業からのバックポートがあり、 here を見つけることができます。それを使用することについての素晴らしい記事 ここ とそれを使用するgradleプロジェクト ここ があります。

Java/JavaFX 12では、Java 13で使用できるjpackageツールの build 0バージョン がすでに存在します。

これはツールの非常に予備的な使用です:

plugins {
    id 'org.openjfx.javafxplugin' version '0.0.5'
}

repositories {
    mavenCentral()
}

dependencies {
}

javafx {
    version = "12-ea+5"
    modules = [ 'javafx.controls' ]
}

mainClassName = 'hellofx/hellofx.HelloFX'

def Java_home = '/Users/<user>/Downloads/jdk-12.jdk/Contents/Home'
def installer = 'build/installer'
def appName = 'HelloFXApp'

task copyDependencies(type: Copy) {
    dependsOn 'build'
    from configurations.runtime
    into "${buildDir}/libs"
}

task jpackage(type: Exec) {
    dependsOn 'clean'
    dependsOn 'copyDependencies'

    commandLine "${Java_home}/bin/jpackage", 'create-installer', "dmg",
            '--output', "${installer}", "--name", "${appName}",
            '--verbose', '--echo-mode', '--module-path', 'build/libs',
            '--add-modules', "${moduleName}", '--input', 'builds/libraries',
            '--class', "${mainClassName}", '--module', "${mainClassName}"
}

ここで./gradlew jpackageを実行すると、dmg(65 MB)が生成されます。これを配布してインストールできます。

installer

結論

従来の太いjarを使用することもできますが、Java 11以降に移行する場合、すべてがモジュール化されているはずです。 IDEサポートを含む、新しい(間もなく)利用可能なツールとプラグインは、この移行中に役立ちます。

私はここで最も単純なユースケースを提示したことを知っています。より複雑な実際のケースを試す場合、いくつかの問題があるでしょう...しかし、古いソリューションを使い続けるのではなく、それらの問題の解決に取り組むべきです。

29
José Pereda