読者です 読者をやめる 読者になる 読者になる

javapackagerの紹介

JavaFX

このエントリは JavaFX Advent Calendar 2015 の 19 日目のエントリです。前日は id:yumix_h さんによる「 JavaFXで画面解像度を調べてみる 」でした。

今回は JDK に付属しているツールである javapackager について紹介します。このツール、私が見る限り公式のドキュメント以外では断片的な解説しか無い (主にネイティブパッケージの解説などでしか登場しない) ように見受けられるので、ここでこのツールができること全般について紹介したいと思います。

アプリケーション配布を巡る環境の変化

まず、javapackager のようなツールが登場した背景について触れたいと思います。これにはアプリケーション配布を巡る環境の変化が大きく関わっていると考えています。

既にご存じの通り、Java は "Write Once, Run Anywhere." を目指して作られたものであり、Java で実装、ビルドしたアプリケーションはどの環境でもそのまま動くことが期待されています。

この Java アプリケーションの配布ですが、元々はどのプラットフォームにも JRE がインストールされていることを前提とした考え方でした。クライアントアプリケーションの配布は実行可能 JAR の形態で行うことが普通です。サーバサイド Java では JRE の上にさらに Java EE コンテナのレイヤを敷き、アプリケーションは WAR もしくは EAR として配布しますね。

ところが、最近はこのように予めランタイムを別途インストールしておき、その上にアプリケーションをデプロイするスタイルはあまり好まれなくなっているように見受けられます。必要なものは1つのパッケージに全て含まれており、箱から出したらすぐ使えるような形態 (これを「自己完結型パッケージ」と呼びます) が好まれるようになっています。

これは OS ベンダ提供のアプリケーションストアという配布形態の登場が大きく関係していると考えています。アプリケーションストアから配布するアプリケーションはサンドボックス化されており、自己完結型であることが望まれています。エンドユーザとしても、アプリケーションストアからワンクリックでインストールが可能なスタイルに慣れてしまうと、わざわざランタイムをインストールするのは煩わしく感じられるようになるでしょう。特にデフォルトでは JavaFlash などがインストールされておらず、アプリケーションストアの利用率が高い Mac 環境ではその傾向が強いように思われます。

そしてもう一つの環境の変化はセキュリティです。どの OS、プラットフォームでも以下のようにセキュリティ対策が強化され、以前のように何も考えずに「野良アプリケーション」をほいほいインストールできなくなっています。

  • Java Web StartJava Applet では未署名のアプリケーションの実行はブロックされるようになりました。
  • Windows では未署名アプリケーションをダウンロードする際にはブラウザが警告を出します。
  • Mac では Gatekeeper という仕組みが導入され、デフォルトの状態では Mac App Storeからインストールしたアプリケーション、もしくはAppleデベロッパ登録し、そのデベロッパ ID で署名したアプリケーションのみが起動可能になっています。
  • FirefoxGoogle Chrome といった Web ブラウザの拡張機能でさえも、ブラウザベンダが運営する配布サイトからのみのインストールに制限されるようになりました。

JDK に同梱されている javapackager はこのようなクライアントアプリケーション配布を巡る環境の変化に対応できるようになっています。

javapackager の概要

javapackager は JDK に付属しており、Java アプリケーションのパッケージング、デプロイメントのためのツールです。

元々は javafxpackager という名前で、その名の通り JavaFX アプリケーションをパッケージングするための専用ツールとして JavaFX SDK に同梱されていました。JDK7 update6 以降は JDK に同梱されるようになり、Java アプリケーション全般に利用可能なツールになりました。JDK8 update20 以降は javapackager に名を変え、名実共に Java SE のためのツールに昇格 (?) しています。

javapackager が提供する機能は次のようなものになります。

  • 実行可能 JAR のビルド
  • 配布用パッケージの生成
    • Java Web StartJava Applet 向けバンドルの生成
    • 自己完結型パッケージの生成
      • インストール先の OS に合わせたネイティブインストーラの生成
      • JRE も含めたパッケージを生成し、OS 側にランタイムの事前インストールを要求しない
  • 配布プラットフォームに合わせたアプリケーションの署名
  • アプリケーションストア向けパッケージの生成

以降では上に挙げた javapackager の各機能について簡単に説明していきます。

なお、この javapackager の使い方を含む、クライアント Java アプリケーションのデプロイメント全般について詳細に解説した Oracle 公式のドキュメントがあります。日本語化もされています。詳細についてはこちらを参照してもらうとして、ここではつかみの部分を解説することにします。

Java Platform, Standard Editionデプロイメント・ガイド
http://docs.oracle.com/javase/jp/8/docs/technotes/guides/deploy/

javapackager 提供機能の簡単な説明

基本的な使い方

javapackager はコマンドラインツールです。javac や jar コマンドなどと同じディレクトリにインストールされているはずなので、これらコマンドへのパスが通っていれば使うことができます。また、Ant 向けタスクも用意されているのですが、ここではコマンドラインとしての使い方に限定して説明します。Ant での利用方法については上記ドキュメントを参照してください *1

次のような使い方をします。

$ javapackager コマンド [オプション]

javapackager に続けて実行したいタスクに応じたコマンドを指定するのが基本です。コマンド別にオプションがあり、必要に応じて指定します。コマンドは次の 5 種類があります。

コマンド 実行するタスク
-createbss CSS ファイルをバイナリ形式に変換する。
-createjar 実行可能 JAR を生成する。
-deploy デプロイ可能なパッケージを生成する。
-makeall -createjar と -deploy の両方を実行し、実行しているプラットフォームで生成可能な全ての形式のアーカイブを生成する。
-signjar JAR ファイルを署名する。

実行可能 JAR のビルド

まずは基本となる実行可能 JAR のビルドです。通常の jar コマンドが提供する機能に加え、次のような JavaFX 固有の機能を提供しています。

  • プリローダアプリケーションの指定
  • CSS のバイナリ化

1番目にあるプリローダとは、JavaFX アプリケーション本体が起動するまでの間に表示する小さなアプリケーションのことです。主にネットワークからアプリケーションをダウンロードする Java Web StartApplet で使われます。

2番目は CSS ファイルをバイナリ変換するというもので、CSS ファイルが巨大な場合などに、ファイルのパース速度を上げる目的で使用されます *2

-createjar コマンドを使って本機能を利用します。以下にコマンドの実行方法を示します。

$ javapackager -createjar -nocss2bin -appclass アプリケーションクラス名 -srcdir JARに含めるファイルのディレクトリ -outdir JARの出力ディレクトリ -outfile JARファイル名 -preloader プリローダクラス名

-nocss2bin オプションを指定すると、CSS ファイルのバイナリ化が実行されなくなります。未指定の場合だと CSS ファイルのバイナリ化が勝手に実行されてしまうので注意が必要です。 -appclass オプションで指定するのは main メソッドを含むクラスの名前です。マニフェストファイルは勝手に作ってくれますが、自分で追加の属性を指定したい場合は -manifestAttrs オプションに続けて "名前=値,名前=値,..." の形式で指定します。

配布用パッケージの生成

これが javapackager のメイン機能となります。アプリケーション JAR ファイルを準備した状態で -deploy コマンドを使って実行しますが、オプションの指定次第で様々なことができます。

まずは基本的な使い方を示します。以下に示すコマンドを実行すると、Java Web StartApplet 向けに JNLP ファイル及び Applet を実行する HTML ファイルが出力されます。

$ javapackager -deploy -outdir 出力ディレクトリ -outfile 出力ファイル名 -srcdir JARのあるディレクトリ -srcfiles 対象となるJARファイル名 -appclass アプリケーションクラス名 -name アプリケーション名称 -title アプリケーションタイトル

このコマンドを実行すると -name オプションで指定した名前の HTML、JNLP ファイルが出力されます。-title オプションは JNLP ファイル内の <title> タグに反映されます。また、これから説明する自己完結型パッケージの生成でも意味を持ちます。他にもオプションはあるのですが、詳細は javapackager コマンドのリファレンス ( Windows 向けMac、Linux 向け ) を参照してください。

ここでさらに -native オプションを指定すると、自己完結型パッケージを生成することが可能になります。インストール先の OS 向けのネイティブインストーラを生成し、アプリケーション専用の JRE も含めたインストールイメージを作成します。これにより、インストール先の OS に JRE の事前インストールを要求せず、また OS に予めインストールされている public JRE の影響も受けません。これならば「アプリケーションの検証が終わっていないので、JRE のアップグレードはしないでください (> <)」みたいなかっこ悪いことも言わずに済みますね。:)

-native オプションに続けて、次のバンドルタイプを指定することができます。

タイプ 説明
all 無指定の場合はこれが選ばれる。installer、image の両方を指定した場合と同じ結果になる。
installer コマンドを実行している OS が対応している全てのインストーラを生成する。
image アプリケーションインストールディレクトリの内容を展開する。Mac の場合は .app ディレクトリを作り、その下に展開する。
exe Windows の .exe インストーラを生成する。Inno Setup のバージョン 5 以上がインストールされている必要がある。
msi Windows の .msi インストーラを生成する。WiX Toolset のバージョン 3.8 以上がインストールされている必要がある。
dmg MacDMG パッケージ (ドラッグ&ドロップ形式のインストーラ) を生成する。
pkg Mac の PKG インストーラを生成する。
mac.appStore Mac App Store 用のパッケージを生成する。
rpm RPM パッケージを生成する。
deb Debian パッケージを生成する。

指定できるタイプはコマンドを実行する OS で利用可能なパッケージに限定されます。Windows では exe や msi を指定できますが、dmg や pkg、rpmdeb は指定できません。Mac App Store 向けのバンドルタイプもありますね!

-native オプションを使って、自己完結型パッケージを生成する場合、パッケージ固有のオプションを -Bオプション名=値 の形式で指定することができます。ここでは、WindowsMac 向けの代表的なオプションを紹介します。

Windows 向けパッケージ生成オプション

Windows の場合、-native exe もしくは -native msi オプションでインストーラを生成しますが、さらに次のようなオプションを指定することで、カスタマイズを行うことができます。

オプション 説明
-BappVersion=バージョン文字列 アプリケーションのバージョンを指定します。アプリケーションのプロパティで確認できるバージョンになります。
-Bicon=icoファイルのパス アプリケーションのアイコンファイル (.ico ファイル) を指定します。パスは -srcdir で指定するディレクトリからの相対パスになります。
-Bcopyright=コピーライト文字列 アプリケーションのコピーライト文字列を指定します。
-BlicenseFile=ファイルパス exe の場合にのみ有効で、インストーラに使用許諾契約を表示したい場合、そのファイルへのパスを指定します。
-BmenuHint=boolean インストール後、スタートメニューにショートカットを追加したい場合は true を指定します。
-BshortcutHint=boolean インストール後、デスクトップにショートカットを追加したい場合は true を指定します。
-BsystemWide=boolean アプリケーションをユーザローカルにインストールするか、システムレベルにインストールするかを選択します。
-Bwin.menuGroup=グループ名称 スタートメニューにショートカットを追加する場合、スタートメニューにグループを追加した上でその下にショートカットを作ります。そのグループ名を指定します。
-Bvendor=任意文字列 アプリケーションを提供する組織や個人名などを指定します。

結構色んな指定ができることが分かるでしょう。少し重要なのが -BsystemWide オプションです。true にした場合はシステムレベルでインストールされ、いわゆる Program Files ディレクトリ以下にイントールされるようになります。つまり、インストールに管理者権限が必要となります。false の場合はユーザローカルにインストールされます (インストールディレクトリは %LOCALAPPDATA%) 。この場合は管理者権限は不要です。

生成されたインストーラに対して、SignTool を使って署名することもできます。

以下に、実際のコマンド実行例を示します。自分が開発している Social Bookmark Viewer FX をパッケージ化したときのコマンドです。

> javapackager -deploy -native exe -outdir target -outfile SocialBookmarkViewer -srcdir target -srcfiles social-bookmark-viewer-fx-0.1-SNAPSHOT.jar -appclass aoetk.bookmarkviewer.MainApp -name "SocialBookmarkViewer" -title "Social Bookmark Viewer" -BappVersion=0.1 -BsystemWide=true -Bwin.menuGroup="Social Bookmark Viewer"

これを実行すると、次のような出力が得られます。
f:id:aoe-tk:20151219164935p:plain

生成されたインストーラを実行すると、次のようなおなじみのアプリケーションインストーラが立ち上がることになります。
f:id:aoe-tk:20151219165022p:plain

インストールが完了すると、スタートメニューにも登録されました!
f:id:aoe-tk:20151219165035p:plain

インストールディレクトリの下は次のようになっています。exe を実行して起動します。runtime ディレクトリの下には JRE のライブラリが入っています *3
f:id:aoe-tk:20151219165052p:plain

Mac 向けパッケージ生成オプション

Mac の場合は -native dmg-native pkg オプションを使いますが、Windows の場合と異なり、インストーラを生成するために特別なアプリケーションをインストールする必要が無いので、単純に -native だけを指定しちゃっても問題ありません。Mac 向けのカスタマイズオプションを示します。

オプション 説明
-BappVersion=バージョン文字列 アプリケーションのバージョンを指定します。アプリケーションのプロパティで確認できるバージョンになります。
-Bicon=icnsファイルのパス アプリケーションのアイコンファイル (.icns ファイル) を指定します。パスは -srcdir で指定するディレクトリからの相対パスになります。
-Bcopyright=コピーライト文字列 アプリケーションのコピーライト文字列を指定します。
-BlicenseFile=ファイルパス pkg の場合にのみ有効で、インストーラに使用許諾契約を表示したい場合、そのファイルへのパスを指定します。
-BsystemWide=boolean アプリケーションをユーザローカルにインストールするか、システムレベルにインストールするかを選択します。
-Bmac.CFBundleName=名称 アプリケーションメニューバーに表示するアプリケーション名称を -name オプションで指定した名称とは別の名称にしたい場合に指定します。
-Bmac.signing-key-developer-id-app=署名キー名 dmg の場合のオプション。Gatekeeper 向け署名を行いたい場合に指定します。キーがインストールされている場合はデフォルトでそれが使用されるようです。
-Bmac.signing-key-developer-id-installer=署名キー名 pkg の場合のオプション。Gatekeeper 向け署名を行いたい場合に指定します。キーがインストールされている場合はデフォルトでそれが使用されるようです。

Mac の場合、-BsystemWide は true にすると /Applications ディレクトリにインストールされます。Mac の場合はここにアプリケーションをインストールするのが一般的であるため、無指定の場合は true 扱いになります。false にした場合はユーザの Desktop ディレクトリがターゲットになります。

また、Mac 向けにはアプリケーションを "Gatekeeper Ready" にするための対応が入っていることが分かりますね。

Mac 向けのコマンド実行例も同様に示しておきますね。

$ javapackager -deploy -native -outdir target -outfile SocialBookmarkViewer -srcdir target -srcfiles social-bookmark-viewer-fx-0.1-SNAPSHOT.jar -appclass aoetk.bookmarkviewer.MainApp -name "SocialBookmarkViewer" -title "Social Bookmark Viewer" -BappVersion=0.1

これを実行すると、次のような出力が得られます。
f:id:aoe-tk:20151219021419p:plain

生成された DMG ファイルを起動すると、次のようなおなじみのインストール画面が出てきます。
f:id:aoe-tk:20151219021613p:plain

まとめ

このエントリでは javapackager の使い方について掴みの部分の紹介を行いました。最近のクライアントアプリケーション配布を巡る環境の変化に対応した、重要なツールであることを分かってもらえたらと思います。

このツールはクライアントアプリケーションだけでは無く、サーバアプリケーションでも使えると思います。最近はサーバアプリケーションもコンテナにデプロイするのでは無く、単一 JAR に全てをパッケージングしてデプロイする方法も好まれるようになってきました。javapackager を使えば、ランタイムごとパッケージングできるので、より配布が容易になるのではないでしょうか。

javapackager は今回紹介した内容の他にもまだ色々できることがあります (Mac App Store 向けパッケージの作成とか) 。詳しくは上に挙げた Oracle 公式のドキュメント読んでもらえればと。

明日は @ さんの予定です。

*1:というか、この公式ドキュメントでは Ant タスクで利用する方法ばかり説明されています

*2:バイナリ変換すると、ファイルの拡張子が ".css" から ".bss" に変わります。コード側もそれに合わせる必要があります。

*3:昔は JDK を丸ごと放り込むという豪快な感じになっていましたが、最近は結構スリムアップしました。JDK9 の Jigsaw が入るともっと効率よくなるでしょう。