2012-12-19 2012年 Android Advent Calendar 18日目

_ 2012年 Android Advent Calendar 18日目

Android のビルドシステムの不満点を解消する新ビルドシステムを開発中と聞いて

Android Advent Calendar 18日目の @zaki50です。既に19日目すら終わろうとしていますが皆様いかがお過ごしでしょうか(すみません...)。

今回は、Android Tools Project で開発が進められている新ビルドシステムについて書きます。ここで言うビルドシステムとは、Android アプリソースコードやリソースファイルを apk に変換するための仕組みのことです。現状では eclipse や ant を使ったビルドシステムが提供されていますが、それが今後どのように改善され発展していくか興味があったので調べたことをまとめます。

まず初めにお断りしておきますが、新ビルドシステムはまだまだ開発中のものです。リリース時期が決まってないどころか現状実装されている機能がそのままリリースされるかもわかりません。もちろん未実装の機能もたくさんあります。ですが、実際に試してみる事が出来る程度には実装されているので、興味が有る方はぜひ試してみてください。

今回書いた内容は、 Android Tools Project の New Build System に書かれている内容を元にしています。一次情報に当たりたいという方はぜひこちらも見てください。

今回のエントリはこれを読んで新ビルドシステムに興味をもった人が実際に試して見ることを目指します。元のサイトでは省略されているが実際に試すには必要となる情報を補いながら進めます。

新ビルドシステムが目指すこと

Build System Concepts のページには、新ビルドシステムのゴールとして以下の3つが掲げられています。

  • コードやリソースの再利用性を高めること
  • マルチAPKや有料/無料版など、1つのアプリに対して複数の派生バージョンを簡単に作れるようにすること
  • ビルドの拡張やコンフィギュレーション変更を簡単にすること

上記の内容を具体的に何ができるかで表現すると以下のようになります。

  • リソースがあるライブラリプロジェクトを単一バイナリにビルドすることができ、 maven で使用できる。
  • 一つのプロジェクトから、無料版/有料版、マルチAPK用のさまざまな apk など、一部のコードやリソースが異なる複数の APK を作成することができる。
  • 1つのプロジェクトから複数の APK を作る際、パッケージ名やパーミッションなど、AndroidManifest.xml の内容を個別にカスタマイズすることができる。

このようなことが可能になるビルドシステムに興味はあるでしょうか。興味が有る方はさっそく新ビルドシステムを使用するための環境を整えましょう。

セットアップ

新ビルドシステムを使うための方法は Using the new Build System に書かれています。

新ビルドシステムは Gradle というant と Maven のいいとこ取りみたいなシステムの上に構築されています。そこで、まずは Gradle を使える環境を構築します。 Gradle については、 http://www.infoq.com/jp/news/2012/06/gradle-1 など幾つか解説サイトがあるので詳細はそちらを参照してください。

以下、Mac 上での環境構築を前提に記述します。他の環境の人は適宜読み替えをお願いします。

Gradle のセットアップ

Gradle を http://gradle.org/downloads から落としてきます。注意するポイントは、最新の Gradle ではなく、 Gradle-1.2 をダウンロードすることです。Gradle-1.2 をダウンロードしたら、適当な場所に展開し gradle-1.2/bin/ にパスを通してください。

$ which gradle
/Applications/gradle-1.2/bin/gradle
$ gradle
:help

Welcome to Gradle 1.2.

To run a build, run gradle <task> ...

To see a list of available tasks, run gradle tasks

To see a list of command-line options, run gradle --help

BUILD SUCCESSFUL

Total time: 1.511 secs

こんな感じに出力されればまずは成功です。

MacPorts でも Gradle をインストールすることができますが、そのまま入れると 1.3 が入ってしまうのでがんばって 1.2 をインストールしてください。

環境変数の設定

環境変数 ANDROID_HOME に、 Android SDK のパスをセットします(もし Android SDK をインストールしていない場合は適当な場所にインストールし、最新の Platform-tools と、android-support-v4 を落としてください)。

$ env |grep ANDROID_HOME
ANDROID_HOME=path-to/android-sdks

この環境変数はビルドの際に SDK の場所を特定するために使用されます。

以上で、新ビルドシステムを使用する準備は完了しました。Android アプリケーションのビルドのために必要なプラグイン等はすべて Gradle が必要に応じてダウンロードしてくれます。

では早速 Gradle でアプリをビルドしてみましょう。

プロジェクト作成

まずは、gradle でビルドするためのプロジェクトの作成です。AndroidManifest.xml や各種リソース、ソースコードなどは今までのプロジェクトと同じですが、配置する場所が異なります。また、ビルドに関する設定を行う build.gradle という名前のファイルを作成する必要があります。

build.gradle の作成

まず、プロジェクト用のディレクトリとして空のディレクトリを作成します(今回は MyProject_gradle にしました)。ここに、build.gradle とソースコードなどを順に配置していきます。

Using the new Build System に書かれている最小の build.gradle は以下のものです。

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.1'
    }
}
apply plugin: 'android'

android {
    target = 'android-17'
}

このままではいくつか問題があるので、以下の修正を行います。

  • ビルドに使用するプラグインのバージョンを最新に
 classpath 'com.android.tools.build:gradle:0.1'

 classpath 'com.android.tools.build:gradle:0.2'

に変更します。現在 milestone 0.2 がリリースされているので、 0.2 を使用するように変更します。

  • Java6 の class ファイルを生成する設定

最近は Java7 を入れている人も多いかと思いますが、Android は Java7 の class ファイルを扱えないので、Java6 互換として処理するように設定を追加します。今は java6 しかインストールしていなくても、将来的に Java7 を入れるかもしれないので今のうちに設定をしておきましょう。

build.gradle の最後に以下の記述を追加します。

sourceCompatibility=1.6
targetCompatibility=1.6
  • maven のリポジトリを参照する設定を追加

build.gradle の最後に以下の記述を追加します。

repositories {
    mavenCentral()
    mavenLocal()
}
  • 依存ライブラリの記述を追加

依存するライブラリを記述します。最近ではほぼ android-support-v4.jar を使用すると思います。Android SDK に含まれる support-v4.jar を依存 jar として追加するには以下の記述を build.gradle の最後に追加します。

dependencies {
    compile files("${System.getenv('ANDROID_HOME')}/extras/android/support/v4/android-support-v4.jar")
}

android-support-v4.jar を自分でローカルの maven リポジトリに入れているのであれば、以下のように記述することもできます。

dependencies {
    compile 'com.google.android:support-v4:r11'
}
  • build.gradle 作成のまとめ

ここまでの修正を行うと、 build.gradle は以下の様になっていると思います。

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.2'
    }
}

apply plugin: 'android'

android {
    target = 'android-17'
}

sourceCompatibility=1.6
targetCompatibility=1.6

repositories {
    mavenCentral()
    mavenLocal()
}

dependencies {
    compile files("${System.getenv('ANDROID_HOME')}/extras/android/support/v4/android-support-v4.jar")
}
ソースコードなどをコピー

まず、各種ファイルを配置するためのディレクトリ群を作成します。

$ mkdir -p src/{main,debug,release}/{java,jni,resources,aidl,rs,res,assets}

こんな感じに作成できていればOKです。

$ find .
.
./src
./src/debug
./src/debug/aidl
./src/debug/assets
./src/debug/java
./src/debug/jni
./src/debug/res
./src/debug/resources
./src/debug/rs
./src/main
./src/main/aidl
./src/main/assets
./src/main/java
./src/main/jni
./src/main/res
./src/main/resources
./src/main/rs
./src/release
./src/release/aidl
./src/release/assets
./src/release/java
./src/release/jni
./src/release/res
./src/release/resources
./src/release/rs

現状の Android アプリのプロジェクトからのファイルは、 src/ 以下に配置されます。src/ の直下には、 Sourceset と呼ばれるディレクトリが作成されます。今回は main, debug, release という Sourceset を作成しました。このうち main がすべての基本になるディレクトリです。このプロジェクトで作成するすべての apk に共通するものをここに配置します。 release は リリースビルドの際だけ使用するファイル群を、debug にはデバッグビルドの際に使用するファイル群を配置します。これら以外にも、自由にsourceset ディレクトを作成することができます。

また、全ての Sourceset は直下に以下のファイル/ディレクトリを持つことができます。

AndroidManifest.xml
使用する apk 生成の際に使用する AndroidManifest.xml です。build.gradle で設定の一部を上書きすることができます。
java
Java のソースコードを配置します
res
Android のリソースを配置します。
assets
アセットを配置します。
aidl
AIDL ファイルを配置します。
rs
RenderScript ファイルを配置します。
jni
JNI のファイルを配置します。
resources
Java のリソースを配置します。

次に現状のプロジェクトからファイルをコピーします。元のプロジェクトが ../MyProject にあるとします。

$ cp ../MyProject/AndroidManifest.xml src/main/
$ cp -r ../MyProject/src/* src/main/java/
$ cp -r ../MyProject/res/* src/main/res/
$ cp -r ../MyProject/assets/* src/main/assets/

もし、 元のプロジェクトが AIDL ファイルを含んできる場合は、src/main/java/ から src/main/aidl/ へ移動してください。

ここまでくればapk をビルドする準備は完了です。

ビルドと実行

さっそくビルド&インストールします。APK を端末にインストールするので、端末をつなげておいてください。

$ gradle installDebug
Download http://repo1.maven.org/maven2/com/android/tools/build/gradle/0.2/gradle-0.2.pom
Download http://repo1.maven.org/maven2/com/android/tools/build/builder/0.2/builder-0.2.pom
Download http://repo1.maven.org/maven2/com/android/tools/build/gradle/0.2/gradle-0.2.jar
Download http://repo1.maven.org/maven2/com/android/tools/build/builder/0.2/builder-0.2.jar
Deprecated: relying on packaging to define the extension of the main artifact is deprecated, and will not be supported in a future version of Gradle.
:prepareOrgZakkyAndroidMyLibrary10Library
:prepareDebugDependencies
:compileDebugAidl
:generateDebugBuildConfig
:crunchDebugRes
:processDebugManifest
:processDebugRes
:compileDebug
:dexDebug
:processDebugJavaRes UP-TO-DATE
:packageDebug
:installDebug
4184 KB/s (189521 bytes in 0.044s)
    pkg: /data/local/tmp/MyProject_gradle-debug-unaligned.apk
Success

BUILD SUCCESSFUL

Total time: 16.761 secs

BUILD SUCCESSFUL と出力されたでしょうか。もし BUILD FAILED と出た場合は、エラーメッセージを確認して対処してください。 build.gradle の記述ミスか、 src/main/ の下に必要なファイルが存在しないという場合が多いと思います。

gradle tasks と実行すると、他に実行可能なタスクの一覧が出力されます(--all もつければさらに細かい Task も出力されます)。

Flavor の追加

今まで作成した main, debug, release は予め定義されているもの(debug, release は BuildType と呼ばれます。BuildType を追加することもできますが今回は省略します)ですが、Flavor を追加することで、様々なバリエーションを持った APK を作成することができます。 Flavor を追加するには、 Flavor に対応する Sourceset を src/ ディレクトの下に作成し、build.gradle に productFlavors として記述を追加します。

たとえば、無料版と有料版で別 APK を作成するためので Flavor を追加する場合は以下のように build.gradle の android の中に以下の記述を追加します。

android{
    (略)
    // ここから追加
    defaultConfig {
        versionCode = 12
        versionName = "1.2"
    }
    productFlavors {
        freeapp {
            packageName = "org.zakky.myproject.free"
            minSdkVersion = 14
        }
        paidapp {
            packageName = "org.zakky.myproject.paid"
            minSdkVersion = 16
        }
    }
    // ここまで追加
}

すべての Flavor に共通の設定は defaultConfig に記述し、 Flavor 毎の設定は productFlavors に記述します。この例では、全 Flavor 共通で versionCode とversionName を指定し、Flavor の設定で packageName と minSdkVersion を変更しています。各 Flavor にディレクトリに AndroidManifest.xml を置くことができるので、その中で例えな Free 版にだけ広告のために必要な追加 permission を指定することもできます。その場合でも、 versionCode とversionName defaultConfig によって一元管理することでメンテナンスのコストが上がらないように工夫されています。

Flavor を追加すると、gradle に指定するタスクが自動的に増えます。今回は freeapp と paidapp Flavor を追加したので、 installDebug が無くなり、代わりに installFreeappDebug と installPaidappDebug が追加されます(gradle tasks で確認してみてください)。

Flavor を追加した場合は gradle installFreeappDebug の様に、 install + <flavor名> + <build type 名> をタスク名に指定してください。

今回は Flavor の定義を追加しただけですが、 追加した Flavor に対応する Sourceset フォルダの中の java や res フォルダにファイルを配置することで、その Flavor の時のみビルドされるクラスやリソースを追加することができます。たとえば有料版にしか存在しない機能のコードは src/paidapp/java/ に、無料版にしか存在しない広告のレイアウトリソースは src/freeapp/res/layout/ に配置します。

これで一つの プロジェクトから、様々な APK を作成できるようになりました。

各 Flavor や BuildType でどのような設定を行うことができるかは、 Basic Project Setup を参照してください。

ライブラリプロジェクト作成

次に、ライブラリプロジェクトの扱いについてです。

基本的には上に書いたアプリのプロジェクトとほぼ同じなのですが以下の特徴があります。

  • BuildType や Flavor が追加できない
  • maven などで扱うため、.alb という拡張子のファイル(フォーマットは zip) を生成する

アプリのプロジェクトでは Flavor を定義することで様々な APK を生成することができましたが、ライブラリプロジェクトが作成できるのは debug と release の2種類のファイルだけです。また、debug はあくまでUnitTest などのためで、maven リポジトリにdeploy できるのは release 版のみです。

プロジェクトの作成手順はほぼアプリプロジェクトと同じなので、ライブラリプロジェクトについては build.gradle の作成と、maven リポジトリへのdeploy について書きます。

build.gradle の作成

アプリプロジェクトと同じように、空ディレクトリを作成したらまずは build.gradle ファイルを作成します。

以下にライブラリプロジェクト用の build.gradle のサンプルを掲載します。

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.2'
    }
}
apply plugin: 'android-library'

sourceCompatibility=1.6
targetCompatibility=1.6

android {
    target = 'android-14'
}

dependencies {
    compile files("${System.getenv('ANDROID_HOME')}/extras/android/support/v4/android-support-v4.jar")
}

apply plugin: 'maven'
uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: "file://localhost/Users/zaki/.m2/repository/")
            pom.version = '1.0'
            pom.groupId = 'org.zakky.android'
            pom.artifactId = 'MyLibrary'
        }
    }
}

アプりプロジェクト用の build.gradle と違う部分だけ説明します。

  • プラグインが 'android' ではなく 'android-library'
  • maven プラグインを指定し、deploy 先のリポジトリと、deploy するさいの groupId などを指定している。

このような build.gradle を作成したら、アプリプロジェクトと同じように src/main などを作成し、必要なファイルを配置します。

gradle build でビルド御テストが走ります。

maven リポジトリへの deploy

maven リポジトリへは以下のコマンドで deploy することができます。

$ gradle uploadArchives
:packageDebugAidl UP-TO-DATE
:prepareDebugDependencies
:compileDebugAidl
:generateDebugBuildConfig
:processDebugManifest
:processDebugRes
:compileDebug
:processDebugJavaRes UP-TO-DATE
:packageDebugJar
:packageDebugRes
:packageDebugSymbols
:bundleDebug
:packageReleaseAidl UP-TO-DATE
:prepareReleaseDependencies
:compileReleaseAidl
:generateReleaseBuildConfig
:processReleaseManifest
:processReleaseRes
:compileRelease
:processReleaseJavaRes UP-TO-DATE
:packageReleaseJar
:packageReleaseRes
:packageReleaseSymbols
:bundleRelease
:uploadArchives
Uploading: org/zakky/android/MyLibrary/1.0/MyLibrary-1.0.alb to repository remote at file://localhost/path-to/repository/
Transferring 42K from remote
Uploaded 42K
Uploading: org/zakky/android/MyLibrary/1.0/MyLibrary-1.0-debug.alb to repository remote at file://localhost/Upath-to/repository/
Transferring 42K from remote
Uploaded 42K

BUILD SUCCESSFUL

Total time: 5.696 secs
ライブラリプロジェクトを使う

ライブラリプロジェクトが maven リポジトリに deploy されていれば、後は dependency に依存を記述するだけです。先ほどの アプリプロジェクトの build.gradle の dependencies にライブラリプロジェクトへの依存を追加します。

dependencies {
    compile 'org.zakky.android:MyLibrary:1.0'
    compile files("${System.getenv('ANDROID_HOME')}/extras/android/support/v4/android-support-v4.jar")
}

これで MyLibrary プロジェクトに含まれている物を MyProject から利用することができます。

$ gradle installFreeappDebug
Deprecated: relying on packaging to define the extension of the main artifact is deprecated, and will not be supported in a future version of Gradle.
:prepareOrgZakkyAndroidMyLibrary10Library
:prepareFreeappDebugDependencies
:compileFreeappDebugAidl
:generateFreeappDebugBuildConfig
:crunchFreeappDebugRes
:processFreeappDebugManifest
:processFreeappDebugRes
:compileFreeappDebug
:dexFreeappDebug
:processFreeappDebugJavaRes UP-TO-DATE
:packageFreeappDebug
:installFreeappDebug
3365 KB/s (189528 bytes in 0.054s)
    pkg: /data/local/tmp/MyProject_gradle-freeapp-debug-unaligned.apk
Success

BUILD SUCCESSFUL

Total time: 10.026 sec

まとめ

今回は現在開発が進んでいる Gradle ベースの新ビルドシステムを実際に試して、手順とできることを書いてみました。

Flavor のサポートによって1つのプロジェクトから様々な APK が作成できる点と、maven や Ivy と親和性の高いライブラリプロジェクトが大きな目玉です。正式リリースはもうしばらく先になるとは思いますが、今回これらの機能を実際に使ってみて今後は CI との親和性がより高くなりまたメンテナンスもしやすい開発環境が構築できるのではないかなと思いまいた。

既存のプロジェクトの移行は多少面倒ですが、正式リリースの際にはプロジェクトの移行ツールなども提供されるのではないかなと思っています。 今回はじめて Gradle を使ったのですが強力なビルドシステムだと感じました。Android 以外でも Gradle を使用しつつ将来の 新ビルドシステムに備えようと思います。

また、この新ビルドシステムについては adt-dev Group で議論されています。ADT などについてもここで議論されているのでなにか気づいたことがあれば投稿してみるといいとおもいます(@sys1yagi さんのように!)。


«前の日記(2011-12-10) 最新