Gradleではapplication
プラグインを使うことで実行用のスクリプトを生成できるが,この方法では複数のファイルに別れてしまい,使い勝手が悪い.そこで,単一ファイルにしたりインストーラーで簡単に導入できるようにしたファイルの作り方を紹介する.
方法その1 依存するクラスをすべて内包したJARを作る
gradleをつかって依存ライブラリを含む単一で実行可能なjarを生成するなどで紹介されているが,このまま使うと,このプロジェクトに依存したプロジェクトを作るとクラスの重複が起こってしまって問題になるので,別のタスクとして定義し,別の名前のファイルになるようにする.
apply plugin: 'java'
apply plugin: 'application'
mainClassName = 'info.informationsea.java.excel2csv.Excel2CSV'
def executableBaseName = "excel2csv"
task executableJar(type: Jar, dependsOn: jar) {
archiveName = "${executableBaseName}.jar"
manifest {
attributes 'Main-Class' : mainClassName
}
from configurations.compile.collect {it.isDirectory() ? it : zipTree(it)}
from "$buildDir/classes/main"
from "$buildDir/resources/main"
}
こうしておくと${executableBaseName}.jar
がbuild/libs
にでき上がる.
方法その1-2 java -jar
なしで実行可能にする
java -jar
で指定するJARには先頭に余計なデータがついていても途中のJARの部分から読んでくれるので,ファイルの先頭に
#!/bin/sh
exec java -jar $0 "$@"
と書いて,後ろにJARをくっつけておくとそのまま実行できる(Linux, OS Xの場合).そのようなファイルを自動生成するタスクは以下の通り.上で説明したexecutableJar
タスクが存在していることが前提となっている.
task createExecutable(dependsOn: executableJar) << {
def executableFile = file("$buildDir/deploy/${executableBaseName}")
executableFile.parentFile.mkdirs()
def output = new FileOutputStream(executableFile)
output.write(("#!/bin/sh\n" +
"\n" +
"exec java -jar \$0 \"\$@\"\n").bytes)
output.write file("$libsDir/${executableBaseName}.jar").bytes
output.close()
executableFile.executable = true
}
方法その1-3 javapackager
でJREを入りのインストーラーを作る
javapackager
コマンドを利用するとJREを含んだインストーラーやアプリケーションを作ることができる.これによりGUIのJavaのプログラムを配るときに,JREをインストールさせなくて良いので楽になる.ただし,コマンドラインで使うアプリケーションには使えない.Antタスクでもできるようだが,いまいちやり方が分からないのでコマンドを呼んでいて,そのせいで汎用性に乏しいコードになってしまっている.以下のコードは OS X 専用.
task nativePackage(dependsOn: executableJar) << {
file("$buildDir/deploy").mkdirs()
exec {
executable System.getProperty("java.home")+"/../bin/javapackager"
args "-deploy", "-title", "${project.name}", "-name", project.name, "-appclass", mainClassName,
"-native", "installer", "-outdir", "$buildDir/deploy", "-outfile", project.name,
"-srcdir", "$libsDir", "-srcfiles", "${executableBaseName}.jar"
}
}
その他のOSでも同様にコマンドを呼んであげれば良い. OS X 専用になってしまっているのはjavapackager
を探すところだけなので,他のOSでもコマンドの呼び出し方は同じ.-srcfiles
に指定するJARは必要なファイルがすべて含まれているものにする.
javapackager
はお仕着せ感の強いアプリケーションなので,インストーラーに利用規約を追加したり,App Store提出用バイナリにPermission追加したりするのは面倒くさそう.
方法その2 Capsuleを使う
一部の Class Path をスキャンするようなプログラムでは上で説明したように一つのJARにまとめてしまうと上手く動かない(たとえばSpring).そこで単一JARの中に複数のJARをまとめて入れて,実行時に展開させることができる.そのためには Capsule を使う.
Gradle Capsule Pluginを使うことで,Gradleから簡単に使うことができる.
plugins {
id "us.kirchmeier.capsule" version "0.10.0"
}
apply plugin: 'java'
apply plugin: 'application'
mainClassName = 'info.informationsea.java.excel2csv.Excel2CSV'
task fatCapsule(type: FatCapsule) {
applicationClass mainClassName
}
task executableCapsule(type: FatCapsule) {
applicationClass mainClassName
reallyExecutable
archiveName = "excel2csv"
}
ここでは二つのタスクを定義している.最初のfatCapsule
は実行可能なJARを作成している.このプログラムは実行時に内部のJARを~/.capsule/apps
以下に展開して実行する.このときJVMを新たに立ち上げるのでメモリを多く使ったり,場合によっては面倒なことになるかもしれない.
次のexecutableCapsule
は上の 方法その1-2 java -jar
なしで実行可能にする で説明したスクリプトと同じようなことをするためのもの.archiveName
を設定することで自由にファイル名を変えられる.