javafx-maven-plugin でネイティブ用アイコンを設定する

この記事は JavaFX Advent Calendar 2016 - Qiita の 13 日目です。

昨日は @boochnich さんの JavaFXのCanvasで拡大縮小と平行移動を行う(リベンジ編) - Qiita でした。明日は @y_q1m さんです。

はじめに

JavaFX の最大の魅力の一つはなんといってもクロスプラットフォームGUI アプリを作れることです。 jar 形式でなく、各プラットフォーム向けの実行ファイル形式にビルドする方法も提供されており、 Java がインストールされていない環境でも動作するアプリを作成することができます。

Java 開発といえば Maven や Gradle がデファクトになっていますが、 javafx-maven-plugin を使うと、 JavaFX 開発で Maven を使いつつプラットフォームネイティブな JavaFX アプリをビルドすることができます。 NetBeansJavaFX + Maven アプリケーションを作ると javapackager を直で使うような構成の pom が出来上がりますが、 javafx-maven-plugin の方がビルドが速いしパッケージングも楽なので、自分は専らこれを使っています。

javafx-maven-plugin を導入する際は、以下のページからぽちぽちオプションを選んでいくと pom 設定の雛形が自動生成されるので便利です。

前置きが長くなりましたが、せっかくネイティブなアプリができるのなら、アプリケーションのアイコンをデフォルトのじゃばじゃばしいやつじゃなくて、独自のものを設定したくなるものです。 Oracle の公式とかだと javapackager を ant から呼ぶみたいなサンプルしかなくて、今更 build.xml もちょっと・・・ということで、 Maven でどうやってアイコンを設定するのか調べてみました。

環境

環境は以下のとおりです。

結論

まず結論から。最低限以下のファイルを用意して mvn jfx:native すればいいです。 Linux は環境がないので調べてませんが、後述のように調べれば同様にできると思います。

  • Mac の場合
    • src/main/deploy/package/macosx/アプリ名.icns を用意する
  • Windows の場合
    • src/main/deploy/package/windows/アプリ名.ico を用意する

アプリ名は pom の build -> finalName です。詳細は以下に述べます。

アイコンファイルをどこに置くか

とりあえず Oracle の公式は以下のような感じです。

To get more insight into what resources are being used, enable verbose mode by adding the verbose="true" attribute to , or pass the -v option to the javapackager -deploy command.

なんかよくわかりませんが、ビルド時に verbose="true" を指定すれば、どういうリソースを使うのかわかるよ!って感じでしょうか。しかしここの例では ant なので、 Maven における verbose オプションの指定方法がわかりません。 mvn コマンドの -X オプションを試してみたが、これではないようです。

ここで前述の javafx-maven-plugin の公式サイトを見てみましょう。

lag to turn on verbose logging. Set this to "true", if you are having problems and want more detailed information.

そのものずばり verbose オプションを指定するスイッチがありますね。これをオンにすると pom.xml に以下のように追加されます。

	<groupId>com.zenjava</groupId>
	<artifactId>javafx-maven-plugin</artifactId>
	<version>8.6.0</version>
	<configuration>
		<mainClass></mainClass>
		<verbose>true</verbose><!-- これ -->
	</configuration>

この状態で mvn jfx:native を叩くと以下のような出力が得られます(抜粋)。 Oracle 公式にあったような感じですね。

  Using default package resource [icon]  (add package/macosx/アプリ名.icns to the class path to customize)
(略)
  Using default package resource [dmg background]  (add package/macosx/アプリ名-background.png to the class path to customize)
  Using default package resource [volume icon]  (add package/macosx/アプリ名-volume.icns to the class path to customize)

上記は Mac で試したものですが、実行環境の OS により少しパスが異なります。

どうやら Mac の場合は package/macosx/アプリ名.icns というやつを用意してクラスパスに追加すればよさそうです。他にも アプリ名-background.pngアプリ名-volume.icns とかいうのもありますね。クラスパスということですがどこに置くのがよいのか、ここで javafx-maven-plugin の公式サイトをもう一度よく読みます。

Default: ${project.basedir}/src/main/deploy
(略)
The most common usage for this is to provide platform specific icons for native bundles. In this case you need to follow the convention of the JavaFX packaging tools to ensure your icons get picked up.

なるほど、 ${project.basedir}/src/main/deploy/package/macosx を用意すれば良いっぽいですね。

アイコンファイルの用意

というわけでアイコンファイルを用意しましょう。 icns という見慣れない拡張子(当社比)が出てきましたが、これはなんでしょうか。

Mac 用のアイコンファイルのようですね。ターミナルから作れるようなので作ってみましょう。元ネタの png はなんとかして用意する*1として、各サイズは Mac のプレビューアプリからリサイズすることで作れます。

icons_256x256.png とかいろんなサイズの画像を作り、 アプリ名.iconset というフォルダに突っ込みます。しかるのちにターミナルで以下のコマンドを叩くと、 アプリ名.icns が出来上がります。

$ iconutil -c icns アプリ名.iconset

今回はめんどくさいので 256x256 だけ用意しましたが特に問題なく作成できました。ファイル名で表されたサイズと実際のファイルサイズが異なっているとうまく icns ファイルが作成されないので気をつけましょう。

出来上がったアイコンファイルを ${project.basedir}/src/main/deploy/package/macosx に配置し、改めて mvn jfx:native を叩きます。

  Using custom package resource [icon]  (loaded from package/macosx/アプリ名.icns)
(略)
  Using default package resource [dmg background]  (add package/macosx/アプリ名-background.png to the class path to customize)
  Using default package resource [volume icon]  (add package/macosx/アプリ名-volume.icns to the class path to customize)

作成したアイコンファイルが読まれているのがわかります。これでめでたくアイコンが設定できました。

インストールすると、ちゃんと Finder や Dock に指定したアイコンが表示されます。

アプリ名-volume.icns はインストーラーがマウントされたときにデスクトップに出現するボリュームアイコン用のようです。このファイルを指定するとデスクトップに以下のアイコンが現れます。今回は同じアイコンファイルを使っています。

指定しない場合、デフォルトのジャバジャバしいやつです。

アプリ名-background.pngインストーラーの背景画像のようです。このファイルを指定すると以下のようになります。

なんかうっかりひどい色になってしまいました。すいません。とりあえず画像サイズは 512x256 にしてみたのですが、微妙に合ってないですね。

ウィンドウアイコンの設定

アプリのタイトルバーに表示するアイコンは以下のようにして設定できます。これ自体はネイティブアプリとは関係ないです。

  1. アイコンファイルを src/main/resources/images/icon.png あたりに配置する
    • Java コードから参照できる場所であればどこでも良いです
  2. JavaFX メインクラスの start メソッドでアイコンパスを指定する

アイコンパスの指定は以下のようなコードになります。

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("/fxml/Scene.fxml"));

        Scene scene = new Scene(root);
        scene.getStylesheets().add("/styles/Styles.css");

        // ↓この 1 行
        stage.getIcons().add(new Image(getClass().getResourceAsStream("/images/icon.png")));

        stage.setTitle("JavaFX Icon Sample");
        stage.setScene(scene);
        stage.show();
    }

これでこんな感じになります。もうちょいはっきりしたアイコンにしないと小さくてわかりづらいですね。

Mac の場合は未設定だとアイコン自体が表示されないのでなくても特に気になりませんが、 Windows だとデフォルトのウィンドウアイコンになってしまい、残念な感じになるのでこちらも設定しておいた方が良いでしょう。

Windows の場合

同様に Windowsmvn jfx:native を実行すると以下のような出力が得られます(抜粋)。

  Using default package resource [application icon]  (add package/windows/アプリ名.ico to the class path to customize)

Windows だと設定可能なアイコンが 1 種類しかないようですね。インストーラーを作成できるようにしてあるとまた違うのかもしれませんが、そのへんは未調査です。メッセージに従い、 src/main/deploy/package/windows/アプリ名.ico を用意して再度ビルドしてみると、 target/jfx/native/アプリ名 以下に実行ファイル類が一式作成され、アイコンもちゃんと設定されていることがわかります。

以上です。

*1:とりあえずなんでもいいのであれば Placehold.jp|ダミー画像生成 モック用画像作成 でダミー画像を作るのもありかと思います。 advanced オプションで CSS も使えるので、角丸やらグラデーションやら使えばそれなりにそれっぽくもなります。