Gradle による Android アプリのビルド
週末は Gradle と Android アプリのビルドツールと戯れていたので、得られた知見などを書き残しておく。
Gradle について
- Gradle 公式サイト: Gradle - Build Automation Evolved
Java 周辺のプロジェクト管理ツール (ビルドシステム?) といえば Ant や Maven があるけど、最近 (?) 注目を集めているのが Gradle。 XML で記述される Ant や Maven とは違い、Gradle のビルドファイルは Groovy による DSL で記述される。 Ruby におけるビルドツールである Rake と似たような雰囲気。 記述の容易さはもちろんのこと、Ant のタスクをそのまま使えたり、依存関係解決に Maven リポジトリを使えたりする など、良さそうな雰囲気を醸し出している。
今のところの難点としては、Maven を使っている場合と比べて依存関係の解決が甘い (?) ことがあること。
ただ、これは Android アプリ開発時には問題にはならないと思う。
Gradle と Android アプリのビルド
Android アプリのビルドツールとして公式的には Ant が採用されているが、最近 Gradle を使った新しいビルドシステムを開発しているらしい (Android Studio に合わせて公開されたのかな)。
Gradle のプラグインとして android プラグインが提供されている。 このプラグインは Maven のセントラルリポジトリで公開されているので、build.gradle に次のように記述するだけで Android アプリのビルド用のあれこれが使えるようになる。
buildscript { repositories { mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:0.7.1+' } } apply plugin: 'android' android { compileSdkVersion 19 }
buildscript
の部分では、ビルドスクリプト自体の依存関係を解決している (参考: 第59章 ビルドロジックの体系化)。 android
の部分が Android アプリのビルドのための設定を記述する場所。
サンプルプロジェクトを作ってみた
- 作ってみたサンプルプロジェクト: nobuoka/android-gradle-build-system-sample · GitHub
実際に試してみないとわからないのでサンプルプロジェクトを作ってみた。 ビルド方法などは README に書いてある。
Gradle ラッパーについて
サンプルプロジェクトに含まれている次のファイルは Gradle ラッパーのためのもの。
- gradlew ファイル
- gradlew.bat ファイル
- gradle/ ディレクトリ
Gradle ラッパー (gradlew) というのは gradle コマンドの代わりに使用されるもので、(既にシステムにインストール済みで) gradle コマンドが使用できるならば *1 それに処理を委譲し、使用可能でなければインターネット経由で gradle を取得してローカルディレクトリにインストールしてそれを使用する、というものである。
- 日本語ドキュメント: 第61章 Gradleラッパー
Android Studio で新しくプロジェクトを作るとこれらのファイルが含まれているので、バージョン管理する必要があるのかどうか悩むところではあるが、あると便利といえば便利 (特にバージョンが固定されるのが良い) なので、特に理由がなければバージョン管理すれば良さそう。 (Gradle コミュニティの文化としては、Gralde ラッパーはバージョン管理するものであるようだ。)
マルチプロジェクトについて
上に書いたサンプルプロジェクトでは、アプリ本体と、ライブラリ Volley をそれぞれサブプロジェクトとしており、マルチプロジェクト構成になっている。 ライブラリは基本的に AAR や JAR で扱えるのが一番良い *2 と思うのだけど、Volley みたいに公式的な JAR がない場合や、自社で開発しているライブラリを使用しながらどんどん変更を加えていきたい場合などは、ライブラリをサブプロジェクトとしてプロジェクトに追加するのが良さそうだと思う。
- Android のビルドツールのマルチプロジェクト構成のドキュメント: Gradle Plugin User Guide - Android Tools Project Site
- Gradle 全般のマルチプロジェクト構成のドキュメント: Chapter 56. Multi-project Builds
マルチプロジェクト構成は次のような感じになるっぽい (間違ってるかも)。
- 親プロジェクトに settings.gradle というファイルがあって、サブプロジェクトのディレクトリがどれかを指し示す
- 各サブプロジェクトは親プロジェクト内の好きな場所 (?) に置ける
- 親プロジェクトも各サブプロジェクトもそれぞれ独自の build.gradle を持つことができる
- 親プロジェクトで Gradle のタスクを実行すると、すべてのサブプロジェクトの同じタスクが実行される
サブプロジェクトのビルドスクリプトを親プロジェクトの build.gradle に記述できる
結構面白いと思ったのが、サブプロジェクトのビルドスクリプトを、そのサブプロジェクトの build.gradle ではなく、別の build.gradle (例えば親プロジェクトの build.gradle) に記述できるということ。
例えば今回のサンプルプロジェクトだと、サブプロジェクトとして Volley を使っているわけだけど、リポジトリは本家のものを使用しているのでサブプロジェクト内の build.gradle を変更することができない。 なので親プロジェクトの build.gradle で Volley 用のビルド設定を変更する、なんてことをやってみた。
また、昔の Volley は build.gradle を持っていなかったので、それこそビルドスクリプトを全て親プロジェクトに書いたりしていた。
基本的にはサブプロジェクトのビルドスクリプトはそのリポジトリの中に入れておきたいところではある。
ディレクトリ構成
Gradle の Java プラグインでのデフォルトのディレクトリ構成は、Maven と同じで src/main/java 以下に Java のソースコードを配置する、というものらしい (参考: Chapter 23. The Java Plugin)。 Android アプリ用のプラグインでも同じようなディレクトリ構成が採用されている。
もちろんデフォルトのディレクトリ構成じゃないプロジェクトでも簡単に対応することができる。 サンプルプロジェクトでも、Volley のディレクトリ構成に合わせてビルドスクリプトを記述した。
ソースコードのエンコーディング指定
javac コマンドは、ソースコードのエンコーディング設定としてデフォルトではシステムのエンコーディングを使用する。 システムのエンコーディングが UTF-8 になっている環境 (多くの *iux 系環境ではそうだと思う) では問題になることは少ないが、Windows を使用していると痛い目に合うことが多い。 Gradle で Java のコンパイル時のエンコーディング指定をするのは次のように書くのが今のところ最良のような気がする。
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
コマンドで PC でビルドした Android アプリのパッケージを Android 端末にインストールする
Android Gradle プラグインは、Android 端末にアプリのパッケージをインストールするタスクも提供している。 installXxxx
というタスクがそれである。 (./gradlew tasks
で確認できる。) 例えば、Debug ビルドのパッケージをインストールする場合は、次のようにすればよい。
./gradlew installDebug
すると、接続している Android 端末に、debug ビルドのパッケージがインストールされる。
古い内容 (自分でタスクを起動する処理を書いてみた)
Gradle のタスクとしてアプリを起動するタスクを書いておけば便利。 android プラグインで提供されてるような気もするけど見つけられなかった。 → 上で書いたように、パッケージをインストールするタスクは提供されている。 起動までするタスクはないようだけど。
// Android SDK Tools に含まれる adb コマンドのパスを文字列で返す def getAdbCmdPath = { def androidPlugin = project.plugins.getPlugin('android') // プラグインオブジェクトの取得方法: http://www.gradle.org/docs/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:plugins def sdkDir = androidPlugin.sdkDirectory // android プラグインのソースコード: https://android.googlesource.com/platform/tools/build/ return new File(sdkDir, 'platform-tools/adb').toString() } task installToDevice(type:Exec) { // apk ファイル名 (TODO 自動で取得できるように) def apkPackageName = 'GradleBuildSystemSample-debug-unaligned.apk' // デバイスへのインストール def installCmd = getAdbCmdPath() + ' -d install -r ' + buildDir + '\\apk\\' + apkPackageName // コマンド実行 (Windows 用) commandLine 'cmd', '/c', installCmd } task runOnDevice(type:Exec) { // Main Activity のパッケージ名とアクティビティクラス名 (TODO 自動で取得できるように) def mainPackage = 'info.vividcode.android.app.gradlebuildsystemsample' def mainActivity = 'MainActivity' // コマンド実行 (Windows 用) commandLine 'cmd', '/c', getAdbCmdPath() + ' shell am start -a android.intent.action.MAIN -n ' + mainPackage + '/.' + mainActivity }
起動する Activity のパッケージ名などを動的に取得できるようにしたいところ。
Eclipse 対応
ビルドシステムとして Gradle を使えば Android Studio にいい感じにインポートできるが、Eclipse へのインポートはそう簡単にはいかない。
Gradle のデフォルトのディレクトリ構成では、Eclipse の Android プラグイン (com.android.ide.eclipse.adt) が対応できないっぽい。 プラグインのソースコードを読んだ感じだと、res ディレクトリの位置などはプロジェクト直下にあることが想定されていて、外部から変更できない感じだった *3。
Eclipse 上で Gradle のタスクを実行すること自体は難しくなくて、Gradle Integration for Eclipse というプラグインを使用すればよい。 今回のサンプルプロジェクトは主に Eclipse 上で開発したのだが、その際もこのプラグインを使用して Gradle のビルドを実行するという感じで開発していた。 *4
Gradle をビルドシステムとして使用するプロジェクトで、Eclipse でも開発できるようにするには、とりあえずは次のようにするのが良いのかなーと思った。
まとめ
Building and Testing With Gradle
- 作者: Tim Berglund,Matthew Mccullough,Hans Dockter
- 出版社/メーカー: Oreilly & Associates Inc
- 発売日: 2011/07/13
- メディア: ペーパーバック
- クリック: 7回
- この商品を含むブログ (7件) を見る
- Gradle 便利
- Groovy 便利
- 今後は Android アプリのビルドも Gradle で管理するのが良さそう
- マルチプロジェクト構成とかディレクトリ構成とかプラグイン周りのこととか、基本的に Gradle を勉強しなきゃなー、という感じ