前略: Gradleは奥が深くできることが多いがなるべくシンプルに説明したい
GradleはAndroidアプリ開発には必須なスキルですが、環境設定系の内容なので役割として触れる人が限られてしまうことが多いのではないかと思います。
そんなGradleに対して、なんとなくストレスを減らし、なんとなく感覚を掴む、チーム内での最低限の共通認識にする、などに役立てたらとと思ってます。
なるべく短く簡潔を心がけますm(_ _)m
Gradle is
- オープンソースのビルドシステムです。
例えばJavaプロジェクトではjarファイルを、JavaのWebアプリならwarファイルを作ってくれたり、汎用性の高さからさまざまなプラットフォームで使われています。
ビルドはすべてプラグインで行うようになっていて、JavaをビルドしてJarファイルを作りたいなら build.gradle ファイルに以下を定義して gradle を実行します。
apply plugin: 'java'
- ローカル上やネットワークリポジトリ上にあるライブラリとの依存関係の解決ができます。
- 中身はGroovyで書かれています。(最近では kotlin DSL でも書けます。)GroovyはJavaと親和性が高いのでJava育ちにはとっつきやすいです。とはいえ、言語自体は最近の言語に似てるので、そもそもそんなにとっつきにくくないと思います。
- antやMavenなどのビルドシステムとの違いはXMLにビルド手順を記載しますが、Gradleはスクリプト言語でビルドスクリプトを書きます。
モジュールのビルドの仕組みざっくり
例えば以下のように3つのモジュールを読むパターンです。以下のように流れていきます。
root/
|- build.gradle // 1番目. ここが動きます。
|- settings.gradle // 2番目. ここで include メソッドで include ':module3', ':module1', ':module2' と書くと、以下の順番で build.gradle が読み込まれ、各 build.gradle でモジュールの依存関係を設定する事ができます。このファイルはPJ全体で1つだけ。
|- module1/
| |- src/...
| `- build.gradle // 4番目. ここが動きます。
|- module2/
| |- src/...
| `- build.gradle // 5番目. ここが動きます。
`- module3/
|- module3.aar
`- build.gradle // 3番目. ここが動きます。
シンプルなAndroidプロジェクトを例にすると以下のようになります。
root/
|- build.gradle // 1番目. ここが動きます。
|- settings.gradle // 2番目. ここで include メソッドで include ':app' と書いてあり、以下の順番で build.gradle が読み込まれ、各 build.gradle でモジュールの依存関係を設定する事ができます。
`- app/
|- src/...
`- build.gradle // 3番目. ここが動きます。
依存関係解決の仕組み、ちょっぴりマニアックだけど結構大事な話
マルチモジュールにするにあたって依存関係の設定は注意が必要です。
依存関係の解決には dependencies 内で implementation , api , compile を使いますが、 compile は使わないようにします。
apply plugin: 'java' // implementation , compile のため
apply plugin: 'java-library' // api のため
dependencies { // dependencies の中に依存関係の設定を書く
// ここに implementation , compile , api の3つで定義できる。
implementation project(':module2') // 基本的にはこれを使うと良いです。これを使えば別モジュールにこのモジュールのAPIとして提供しないようにするために implementation として定義する。javaプラグインで使える。
api 'リポジトリのアーティファクトIDとバージョンなど' // 意図的に別モジュールにも、このモジュール側としてAPI提供したい場合は、明示的に api で定義する。java-libraryプラグインで使える。
compile 'リポジトリのアーティファクトIDとバージョンなど' // 今は非推奨なので使わないようにしてください。api 同様、このモジュール側のAPIとして提供しますが、apiと違って意図しない公開を意味します。
}
ソフトウェアのソフトたる所以はシンプルな依存性も大事ですので、無駄に依存性の原因になるものを公開するのは避けたほうが良いです。
悪い例として、String系のユーティリティがBから公開されており、Aの中でそれを使い、あるときBが不要になったから削除しようと思ったら、Bのメイン機能以外に想定外のStringユーティリティ系のものまで依存しており、多くのモジュールに修正が必要になってしまう場合です。
これ以上話すと、コンポーネント設計の話になって Gradle から脱線しそうになるので、ここまでとします。
AndroidがGradleビルドになる前
AndroidがGradleビルドになる前は eclipse を使っていました。
- 主に eclipse を使ってた。eclipseのAndroid開発プラグインを使って。
- Android Studio を Google が正式リリースされ、開発IDEとしてもこれを使っていき、eclipseのプラグインはサポートしないようにすると明言。
Android Studio は IntelliJ IDEA の派生 IDE です。Gradleの汎用性の高さのためか、もともと IntellJ がGradleプロジェクト に対応していたこともその理由か?(ちなみにeclipseもGradleのプラグインを入れればできる)
ともあれ、Android Studio では Gradleビルドをベースにしており、今はGradleがAndroidビルドのスタンダードです。。
Androidにおけるgradleビルドは何ができるようになったのか?
どんなことができるかというと、スクリプトを書けるのでぶっちゃけたところ、かなりいろいろできますが、代表的なところで言うと
- なんと!AndroidManifestを始め、静的に定義していたアプリバージョンやパッケージ名などをビルドパターンによって動的に定義できるようになった
- なんと!証明書ファイルもビルドパターンによって動的に定義できるようになった
- なんと!環境毎にソースセットを分けることが簡単にできるようになった(何を入れて何を除外するなども)
- なんと!出来上がるapkファイル名を編集できる
- なんと!ビルド前後に行いたいこともできるようになりました。(たとえばできあがったapkファイルをどこかのサーバーにアップするとか)
など。
ant でもできましたが、冒頭に書いたように xml ではなく groovy でできるようになったということです。
所感ですが、設定に関連するコードの量もだいぶ減って簡単にできるようになった気がします。
Androidのプロジェクトを作ると自動で build.gradle が出来ますが、よく見たら以下の Gradleビルドのプラグインが必ず書いてあるです。
apply plugin: 'com.android.application'
これでapkを作ることをはじめ、apkを作る前段でいろいろな設定ができます。
BuildTypeとProductFlavorを組み合わせたものがBuildVariantであり、ビルドパターンである
ビルドタイプとプロダクトフレーバーをしっくり来る言葉で説明するのが難しいですが、、
- ビルドタイプ(buildTypes)
デバッグビルドやリリースビルドなど、工程ごとのビルド設定に使われデバッグ機能や難読化などの設定ができます - プロダクトフレーバー(productFlavors)
目的別のビルド設定。環境の向き先や用途に合わせた設定で、ソース切り分けなどができます。 - ビルドバリアント
ビルドタイプとプロダクトフレーバーを組み合わせたものです
例)
ビルドタイプが
- debug : 開発時向けのビルドタイプで、デバッグ可能設定としており、難読化もしないようになっている。
- release : リリース向けのビルドタイプで、デバッグ不可能としておりとして、難読化もしている。証明書も商用の証明書を設定している。
プロダクトフレーバーが
- production : GoogleのAPIキーを商用アカウントで設定している。アプリパッケージも商用。
- staging : GoogleのAPIキーを検証アカウントで設定している。アプリパッケージは商用に+.test とつくようにしている
とすると、ビルドバリアントは以下の4つが出来上がります。
- productionDebug
- productionRelease
- stagingDebug
- stagingRelease
また、不要な組み合わせを除外するためにvariantFilterという機能もあります。
掛け合わせなので単純に組み合わせると膨大になりがちなので、そういうときはこれを使います。
groovy上の構造は以下のようになります。
android { // com.android.applicationプラグインが提供する
buildTypes { // ここに buildTypes
debug {
// ここに必要な定義
}
release {
// ここに必要な定義
}
}
productFlavors { // ここに productFlavors
production {
// ここに必要な定義
}
staging {
// ここに必要な定義
}
}
}
参考: https://developer.android.com/studio/build?hl=ja
ソースセット管理について
productFlavors 毎にソースセットが管理出来ます。
Gradle にはそもそも sourceSets というプロパティがありますが、Androidでは android.sourceSets を使い productFlavors と併用して使いやすくなっています。
android {
sourceSets {
production {
java.srcDirs = ['other/java']
res.srcDirs = ['other/res1', 'other/res2']
}
staging {
java.srcDirs = ['other/java']
res.srcDirs = ['other/res3', 'other/res4']
manifest.srcFile 'other/AndroidManifest.xml'
}
}
productFlavors {
production { ... }
staging { ... }
}
}
特に、Androidのapkはデコンパイルが簡単なので、セキュリティ観点でもデバッグコードが入らないようにするためにも有効です。
参照: https://developer.android.com/studio/build/gradle-tips?hl=ja#manage-projects-and-sources
まとめ
- Android のビルドは Gradle です。
- ビルドバリアント毎にソースの切り分けしやすい。
- プロダクトの大枠のビルド構成の理解のために、ビルドバリアントの種類と内容を見たら大枠の感覚はつかめるんじゃないでしょうか。
- できることが多いので、これくらいで。