倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

JavaFX 開発のための Gradle プロジェクト : 別アプローチ2つ

前回JavaFX 開発のための Gradle プロジェクトを書いてみましたが、そこでの方法では力ずくでパッケージングを行っていて、JavaFXSDK に付属しているパッケージング・ツールを使っていませんでした。 これでは、署名を行ったり、JavaFX SDK のバージョンアップなどでパッケージングの仕方が変わったりすると、修正が結構大変です。 したがって、今回は前回とは違って SDK 付属のパッケージング・ツールを使ってパッケージングを行う方法を試してみます。

SDK 付属のパッケージングには2種類ありましたが、ここでは以前の記事でみた Apache Ant タスクを通してパッケージング・ツールを使います。 アプローチ方法は次の2つです:

  • Ant ビルドファイルを別ファイルで用意する
  • AntBuilder で Gradle タスクを書く

それぞれ見ていきましょう。 まぁ、半分くらい Gradle のビルドファイルを書く練習みたいなものですけど・・・

Ant ビルドファイルを別ファイルで用意する


まず1つ目の方法は、Ant ビルドファイルを別ファイルで用意する方法。 Gradle のビルドファイル側では、Ant のビルドファイルを読み込んで実行します。 まず、以下のような Ant のビルドファイルを用意しましょう。 ここでは fxjar.xml というファイル名にします:

<project name="JavaFXProject" basedir="." xmlns:fx="javafx:com.sun.javafx.tools.ant">
    <property environment="env" />
    <property name="javafx.tools.ant.jar" value="${env.JAVAFX_HOME}/tools/ant-javafx.jar" />
    <property file="build.properties" />

    <taskdef resource="com/sun/javafx/tools/ant/antlib.xml"      
                 uri="javafx:com.sun.javafx.tools.ant"
                 classpath="${javafx.tools.ant.jar}"/>
 
    <fx:application id="appInfo" name="${appName}" mainClass="${appMainClass}" />
    
    <fx:jar destfile="${dest}/libs/${appName}-${appVersion}.jar">
        <fx:application refid="appInfo"/>
        <manifest>
            <attribute name="Implementation-Vendor" value="${appVendor}"/>
            <attribute name="Implementation-Title" value="${appName}"/>
            <attribute name="Implementation-Version" value="${appVersion}"/>
        </manifest>
        <fileset dir="${dest}/classes/main"/>
    </fx:jar>
</project>

JavaFX プロジェクトの実行可能 Jar ファイルを作成する with Apache Ant」で見たビルドファイルに比べて property の設定を省いて、かわりに build.properties ファイルからプロパティを呼ぶようにしています。 この build.properties ファイルは Gradle プロジェクトの設定値(プロジェクト名やグループ名など)を使用したいので、ちょっと手間ですが Gradle のビルドファイルから生成されるようにしましょう。 Gradle のビルドファイル build.gradle は以下のようになります:

apply plugin:'java'

defaultTasks 'test'
//defaultTasks 'clean', 'build'

group = 'org.waman'
version = 1.0
def jdkVersion = 1.7
def enc = 'UTF-8'
def mainClass = 'org.sample.Main'

def javafxHome = System.getenv('JAVAFX_HOME')

sourceCompatibility = jdkVersion
targetCompatibility = jdkVersion
tasks.withType(Compile){ options.encoding = enc }

// ***** Settings for dependencies *****
repositories {
    mavenCentral()
}

dependencies {
    compile files("$javafxHome/rt/lib/jfxrt.jar")
    testCompile 'junit:junit:4.10'
}

// build.properties を生成
task generateBuildProperties << {
    def buildGradle = new File('build.gradle'), buildProperties = new File('build.properties')
    if((!buildProperties.exists())
            || buildGradle.lastModified() > buildProperties.lastModified()){

        def props = new Properties()

        props.dest = 'build'
        props.appVendor = project.group
        props.appName = project.name
        props.appVersion = project.version.toString()
        props.appMainClass = mainClass

        buildProperties.withOutputStream{ props.save(it, '') }
        ant.echo 'Generate "build.properites"'
    }
}

// Ant ビルドファイル fxjar.xml を読み込んで実行
task fxjar(dependsOn:[classes, generateBuildProperties]) << {
    ant.importBuild 'fxjar.xml'
}

fxjar タスクで「ant.importBuild()」によって Ant ビルドファイル fxjar.xml を読み込んで実行しています。 dependsOn 属性を設定していることで、fxjar タスクの実行前に classes タスク(java プラグインのビルトイン・タスク)と generateBuildProperties タスク(build.gradle 内で定義)を実行します。

この build.gradle をプロジェクト・ルートに配置して、以下のコマンド

gradle clean fxjar

を実行すると、実行可能 Jar ファイルが「$PROJECT_HOME/build/libs」フォルダに生成されます。

AntBuilder で Gradle タスクを書く


次は Gradle のビルドファイル内に直接ビルド処理を書く方法。 ここでも JavaFX アプリケーションの実行可能 Jar ファイルを生成するタスクを fxjar としています:

apply plugin:'java'

defaultTasks 'test'
//defaultTasks 'clean', 'build'

group = 'org.waman'
version = 1.0
def jdkVersion = 1.7
def enc = 'UTF-8'
def mainClass = 'org.sample.Main'

def javafxHome = System.getenv('JAVAFX_HOME')

sourceCompatibility = jdkVersion
targetCompatibility = jdkVersion
tasks.withType(Compile){ options.encoding = enc }

// ***** Settings for dependencies *****
repositories {
    mavenCentral()
}

dependencies {
    compile files("$javafxHome/rt/lib/jfxrt.jar")
    testCompile 'junit:junit:4.10'
}

// ***** Settings for Executable Jar *****
task fxjar(dependsOn:'classes') << {
    def fx = 'javafx:com.sun.javafx.tools.ant'

    ant.sequential{
        taskdef(resource:'com/sun/javafx/tools/ant/antlib.xml',
                uri:fx, classpath:"$javafxHome/tools/ant-javafx.jar")

        "$fx:application"(id:'app-info', name:project.name, mainClass:mainClass)

        "$fx:jar"(destfile:"build/libs/${project.name}-${project.version}.jar"){
            application(refid:'app-info')
            fileset(dir:'build/classes/main')
        }
    }
}

基本的には、AntBuilder を使って Ant ビルドファイルの内容に対応する処理を書いていけばいいんですが(ant プロパティで AntBuilder のインスタンスにアクセス可)、JavaFX SDK に付属しているパッケージング・ツールの Ant タスクでは名前空間を使用しているので少し注意。 Ant ビルドファイルで「fx:application」や「fx:jar」と書いていたタグ名は「javafx:com.sun.javafx.tools.ant:application」、「javafx:com.sun.javafx.tools.ant:jar」などとします。 ただし「fx:jar」要素下の「fx:application」は「application」という風に名前空間を使わなくていい(使ってはいけない)ようです。 あと、「fx:jar」要素下の manifest 要素を書くとうまく動作しなかったので、ここでは省略。

ビルドを実行するには、以下のコマンド

gradle clean fxjar

を実行します。
Ant 第2版 プログラミングGROOVY Building and Testing With Gradle JavaFX 2.0: Introduction by Example