Android Studioのビルドシステムを説明しているAndroid Tools Project SiteのNew Build Systemを翻訳しました。
1 イントロダクション
1.1 新しいビルドシステムのゴール
新しいビルドシステムのゴールは以下の通りです。
- コードやリソースの再利用を簡単にする
- マルチapkや、アプリケーションの異なるフレーバーなど、一部をカスタムしたアプリケーションの作成を簡単にする
- 簡単な設定、簡単なビルドプロセスのカスタマイズ
- IDEとの統合
(訳注: Google I/O 2013でGradleとの統合環境としてAndroidStudioが発表されました)
1.2 何故Gradleか?
Gradleは高度なビルドシステムで、プラグインを通してカスタムしたビルドロジックの構築を可能とします。
我々がGradleを選んだ理由となる特徴を以下に示します。
- ビルドロジックを記述し、制御する為のDSL(ドメイン特化言語)
- ビルドファイルはGroovyベースで、DSLを通して要素の宣言をミックスしたり、カスタムロジックを提供するDSLの要素を操作するためのコードを利用できる。
- Mavenかlvyを通した依存性管理機能をビルドインしている
- とてもフレキシブル。ベストプラクティスがあるが、強制はしない。それぞれのやり方でオッケー
- プラグインで独自のDSLやビルドファイルで使うAPIを公開出来る
- IDEとの統合に良いAPIが提供されている
2 必須要件
- Gradle 1.6
- SDK with Build Tools 17.0.0 (2013/5/16 リリース)
3 基本プロジェクト
Gradleのプロジェクトはプロジェクトのルートフォルダにあるとbuild.gradle呼ばれるファイルでそのビルドを定義しています。
3.1 単一のビルドファイル
殆どのシンプルなjavaのみのプロジェクトは以下の様なbuild.gradleとなります
apply plugin: 'java'
これはGradleに同梱されているJavaプラグインを適用します。このプラグインはjavaアプリケーションをビルドしたりテストする為の全ての機能を提供します。殆どのシンプルなAndroidプロジェクトは以下の様なbuild.gradleとなります:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.3'
}
}
apply plugin: 'android'
android {
compileSdkVersion 17
}
この Android ビルドファイルには、3つの主なエリアがあります:
buildscript { ... } はビルドを走らせるコードを設定します。このケースでは、この定義は Mavenセントラルリポジトリを使用することを宣言し、Mavenアーティファクトに依存するクラスパスがあります。このアーティファクトは Android プラグイン for Gradle バージョン0.4.2 に含まれているライブラリです。
注意:これはビルドの実行コードに影響を及ぼすのみで、プロジェクトではありません。このプロジェクトは自身に、自身のリポジトリ及び依存性を宣言する必要があります。これは後で補足します。その後、Javaプラグインのように 'android' プラグインが先に適用されます。
最後に、android { ... } は、androidビルド向けの全てのパラメータを設定します。これはAndroid DSL のエントリポイントです。デフォルトでは、コンパイルターゲットのみが必要で、compileSdkVersion プロパティによって行われます。このプロパティは、旧ビルドシステムで project.properties がターゲットプロパティを設定しているのと同じです。新しいプロパティは、int型(APIレベル)または、以前のtargetプロパティと同じ値の文字列のいずれかを割り当てることができます。
重要:android プラグインのみ割り当てるべきです。javaプラグインを適用するとビルドエラーが発生します。
注意:sdk.dir プロパティを使用して、既存の SDK が要求するのと全く同じ方法でSDKの位置を設定するために local.properties ファイルが必要となります。あるいは、ANDROID_HOME と呼ばれる環境変数を設定することができます。
3.2 プロジェクトの構造
基本のビルドファイルは上記のデフォルトのフォルダ構造を期待します。Gradle は設定の慣習の概念に従い、可能な時はデフォルトのオプションの値を知覚可能なものとして提供します。
基本プロジェクトは、"ソースセット"と呼ばれる2つのコンポーネントから開始します。メインソースコードとテストコードです。これらはそれぞれ以下に存在します:
- src/main/
- src/instrumentTest/
これらのフォルダの中にそれぞれのソースコンポーネントが存在します。JavaとAndroidプラグインの両方に、JavaのソースコードとJavaのリソースがあります:
- java/
- resources/
Androidプラグインには、Android向けの追加のファイルやフォルダがあります:
- AndroidManifest.xml
- res/
- assets/
- aidl/
- rs/
- jni/
注意:src/instrumentTest/AndroidManifest.xml は自動的に生成されるため特に必要としません。
3.2.1 設定と構造
デフォルトのプロジェクトが適切でない時は変更することができます。Gradleのドキュメントによると、Javaプロジェクトのソースセットの変更は以下のように実行できます:
sourceSets {
main {
java {
srcDir 'src/java'
}
resources {
srcDir 'src/resources'
}
}
}
注意:srcDir は既存のソースフォルダリストにフォルダーを実際に追加します(これはGradleのドキュメントでは明示されていませんが、実際の挙動です。)
デフォルトソースフォルダをリプレースするには、パスの配列の代わりにsrcDirsを使用します。これはまた関係のあるオブジェクトの使い方で別の方法を示します:
sourceSets {
main.java.srcDirs = ['src/java']
main.resources.srcDirs = ['src/resources']
}
さらなる情報については、Java plugin の Gradle ドキュメントをご覧ください。
Android プラグインは同様のシンタックスを使用しますが、自身のsourceSetsを使用するため android のオブジェクト内で実施します。メインコードの古いプロジェクト構造を使用して、instrumentTest sourceSet をテストフォルダに再マッピングする例を示します:
android {
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
instrumentTest.setRoot('tests')
}
}
注意:古い構造は全てのソースファイル(Java, AIDL, レンダースクリプト, Javaのリソース)を同じフォルダに格納するため、これら全てをsourceSetの新しいコンポーネントとして同じsrcフォルダに再マップしなければなりません。
注意:setRoot() は全体の sourceSet(とサブフォルダ)を新しいフォルダーに移動します。これは src/instrumentTest/* から tests/* に移動します。これは Android 特有のもので Java の sourceSetsでは動作しません。
3.3 ビルドタスク
3.3.1 一般的なタスク
ビルドファイルにプラグインを適用すると、ビルドタスクのセットを自動的に生成します。JavaプラグインとAndroidプラグインの両方で実施します。
タスクの慣習は以下の通り:
- assemble
- プロジェクトの出力をアセンブルするタスク
- check
- 全てのチェックを実行するタスク
- build
- アセンブルとチェックの両方を実行するタスク
- clean
- プロジェクトの出力を消去するタスク
タスクのアセンブル、チェック、ビルドでは、実際には何もしません。これらはプラグインのためのアンカータスクで、実際に仕事をするタスクを追加するためのものです。
これは、プロジェクトのタイプが何であっても、あるいは、どのプラグインが適用されていても関係なく、同じタスクを常に呼び出すことを可能にします。例えば、checkタスクが呼ばれていても、findbugsプラグインが適用すると新しいタスクを生成し、依存関係をチェックし、呼び出されます。
コマンドラインから以下を実行することで、高レベルタスクの実行を取得できます:
gradle tasks
タスク実行中に全てのリストと依存性を見るには:
gradle tasks --all
注意:Gradleはタスクの入出力の宣言を自動的にモニタします。
変更なしにビルドが2回実行すると全てのタスクが最新であると Gradle はレポートしますが、これは要求される動作がないことを意味します。これは、余計なビルドの操作を必要とせずに、タスクがお互いに依存することを許します。
3.3.2 Javaのプロジェクトタスク
Java プラグインは2つの主なタスクを生成します。これはメインアンカータスクに依存します:
- assemble
- jar:このタスクは出力を生成します。
- check
- test:このタスクはテストを実行します。
jarタスク自身は、直接的あるいは間接的に他のタスクに依存します:インスタンスのクラスは Javaのコードをコンパイルします。
テストはテストクラスでコンパイルされますが、テストが(クラスと同様に)自身に依存するため、これを呼び出すことは有用ではありません。
一般的に、assemble と check のみ呼び出し、その他のタスクは無視されるでしょう。
全てのタスクセットとJava プラグインの説明はこちらを御覧ください。
3.3.3 Androidのタスク
Androidプラグインは他のプラグインと互換性を保つため、同じルールを使用し、アンカータスクを追加します:
- assemble
- プロジェクトの出力をアセンブルするタスクです。
- check
- 全てのチェックを実行するためのタスクです。
- connectedCheck
- 要求される接続されたデバイスまたはエミュレータのチェックを実行します。全てのデバイスは並行で実行されます。
- deviceCheck
- リモートデバイスに接続するためのAPIを使用してチェックを実行します。
- build
- アセンブルとチェックの両方のタスクを実行します。
- clean
- プロジェクトの出力をクリーンするタスクです。
デバイスに接続することを必要としない一般的なチェックを実行するために、新しいアンカータスクは必要とされています。
ビルドが deviceCheck または connectedCheck に依存しないことに注意してください。
Androidプロジェクトは少なくとも2つの出力を保持します:デバッグAPKとリリースAPKです。
明確に分けてビルドするために、それぞれは自身のアンカータスクを持っています:
- assemble
- assembleDebug
- assemblRelease
これらは両方とも、タスクがAPKをビルドするために複数のステップを実行する他のタスクに依存しています。
assemble タスクは両方に依存していており、両方のAPKをビルドします。
Tip: Gradleは コマンドライン上でタスク名としてキャメルケースをサポートします。例えば:
gradle aR
これは、'aR’にマッチするタスクが他になければ、次のようにタイプすることと同じです
gradle assembleRelease
check アンカータスクは自身の依存性を有しています:
- check
- lint (まだ実装されていません)
- connectedCheck
- connectedInstrumentTest
- connectedUiAutomatorTest (まだ実装されていません)
- connectedInstrumentTest
- deviceCheck
- 他のプラグインがテスト拡張ポイントを実装した時に生成されるタスクに依存します
最後に、プラグインはインストール可能な限り(署名を要求します)、全てのビルドタイプ(debug, release, test)のインストール/アンインストールタスクを生成します。
3.4 基本ビルドのカスタマイズ
Android プラグインは、ビルドシステムから直接的に多くのものをカスタマイズするために、広域のDSLの提供します。
3.4.1 マニフェストエントリー
DSLを通じて、以下のマニフェストのエントリを変更することができます:
- minSdkVersion
- targetSdkVersion
- versionCode
- versionName
- packageName
- Package Name for the test application
- Instrumentation test runner
例:
android {
compileSdkVersion 15
defaultConfig {
versionCode 12
versionName "2.0"
minSdkVersion 16
targetSdkVersion 16
}
}
defaultConfig要素は、android要素の中にあり、全ての設定が定義されます。動的にビルドファイルに記述することができます。
例えば、どこかのファイルからバージョン名読み出したり、カスタムのロジックを使用することができます:
def getVersionName() {
...
}
android {
compileSdkVersion 15
defaultConfig {
versionCode 12
versionName getVersionName()
minSdkVersion 16
targetSdkVersion 16
}
}
DSLを通じてプロパティをセットしていない場合、デフォルト値が使用されます。以下はこれがどのように処理されるかを示す表です。
プロパティ名 | DSLオブジェクトのデフォルト値 | デフォルト値 |
---|---|---|
versionCode | -1 | 存在する場合はマニフェストの値 |
versionName | null | 存在する場合はマニフェストの値 |
minSdkVersion | -1 | 存在する場合はマニフェストの値 |
targetSdkVersion | -1 | 存在する場合はマニフェストの値 |
packageName | null | 存在する場合はマニフェストの値 |
testPackageName | null | アプリのパッケージ名 + “.test” |
testInstrumentationRunner | null | android.test.InstrumentationTestRunner |
signingConfig | null | null |
proguardFile | N/A (設定のみ) | N/A (設定のみ) |
proguardFiles | N/A (設定のみ) | N/A (設定のみ) |
これらのプロパティを実行するビルドスクリプトでロジックをカスタムする場合、2つ目のカラムの値は重要です。
例えば、次のように書くことができます:
if (android.defaultConfig.testInstrumentationRunner == null) {
// assign a better default...
}
値が null のままの場合、ビルド時にカラム3から実際のデフォルト値でリプレースされますが、DSL要素がこのデフォルト値を有していないので再び実行することはできません。これは実際に必要のないマニフェストがパースされることを防ぎます。
3.4.2 ビルドタイプ
アプリのデバッグとリリースの両方のバージョンをビルドするために、デフォルトではAndroidプラグインは自動的にプロジェクトをセットアップします。これらは大抵セキュア(devでない)デバイス上で、アプリをデバッグする能力やAPKの署名方法で違いがあります。
キーまたは証明書によって署名されたデバッグバージョンは、よく知られた名前/パスワードで自動的に生成されます(ビルド中にプロンプトを要求されることを防ぐため)。リリースはビルド中では署名を行わず、後で必要になります。
この設定は、ビルドタイプと呼ばれるオブジェクトを通じて実行されます。デフォルトでは、デバッグとリリースの2つのインスタンスが生成されます。
Androidのプラグインはその他のビルドタイプの生成と同様に2つのインスタンスをカスタマイズすることを許します。これは、ビルドタイプのDSLコンテナで実行します:
android {
buildTypes {
debug {
packageNameSuffix ".debug"
}
jnidebug.initWith(buildTypes.debug)
jnidebug {
packageNameSuffix ".jnidebug"
jnidebugBuild true
}
}
}
上記スニペットは以下をアーカイブします:
- デフォルトのデバッグビルドタイプを設定します:
- 同じデバイスでデバッグとリリースのAPKをインストールするために、パッケージに <app package>.debug を設定します。
- jnidebugと呼ばれるビルドタイプを生成し、デバッグビルドタイプのコピーを設定します。
- JNIコンポーネントのデバッグビルドを有効にすることによって jnidebug の設定を維持し、異なるパッケージのサフィックスを追加します。
新しいビルドタイプの生成は新しい要素を使用することと同じぐらい簡単で、ビルドタイプコンテナ下で initWith() を呼び出すかクロージャで設定します。
可能なプロパティとデフォルト値は:
プロパティ名 | デバッグ用のデフォルト値 | リリース/その他のデフォルト値 |
---|---|---|
debuggable | true | false |
jniDebugBuild | false | false |
renderscriptDebugBuild | false | false |
renderscriptOptimLevel | 3 | 3 |
packageNameSuffix | null | null |
versionNameSuffix | null | null |
signingConfig | android.signingConfigs.debug | null |
zipAlign | false | true |
runProguard | false | false |
proguardFile | N/A (設定のみ) | N/A (設定のみ) |
proguardFiles | N/A (設定のみ) | N/A (設定のみ) |
これらのプロパティに加えて、ビルドタイプはコードとリソースをビルドするのに役立てることができます。
それぞれのビルドタイプのために、新しくマッチした sourceSet がデフォルトの位置と共に生成されます
src/<buildtypename>/
これはビルドタイプ名が main または instrumentTest ではなく(これはプラグインによって強いられます)、お互いにユニークである必要があることを意味します。
その他のソースセットのように、ビルドタイプソースセットの位置は再配置可能です:
android {
sourceSets.jnidebug.setRoot('foo/jnidebug')
}
加えて、それぞれのビルドタイプは 新しい <BuildTypeName> アセンブルタスクを生成します。
assembleDebug と assembleRelease タスクは、既に言及されています。debug と release ビルドタイプは予め作成された時、同様にタスクも自動的に作成されます。
上記のbuild.gradleスニペットはさらに assembleJnidebug タスクを生成し、assembleDebug と assembleRelease タスクに依存するように、同じ方法に依存する形でアセンブルされるでしょう。
Tip: gradle aJ で assembleJnidebug タスクが実行できることを覚えておいてください。
使用可能なユースケース:
- リリースモードではなく、デバッグモードのみの許可
- デバッグ用のカスタム実装
- デバッグモード異なるリソース(例えば、リソースの値が署名された証明書に強く紐づく場合)
ビルドタイプのコード/リソースは以下の方法で使用されます:
- アプリのマニフェストにマージされたマニフェスト
- コードがその他のソースフォルダとして機能する
- リソースがメインのリソースをオーバーレイして、既存の値を置換する
3.4.3 署名設定
アプリケーションの署名に必要なものは以下の通り:
- キーストア
- キーストアパスワード
- キーエイリアス名
- キーパスワード
- ストアタイプ
キーネームと同じように位置は、パスワードとストアタイプによって署名設定を形成します(SigningConfigタイプ)
デフォルトでは、デバッグ設定はよく知られたパスワードと良く知られたパスワードを用いたデフォルトのキーによる、デバッグキーストアでセットアップされています。
デバッグキーストアは、$HOME/.android/debug.keystore に格納されており、なければ生成されます。
デバッグビルドタイプは、この debug SigningConfig を自動的に使用します。
その他の設定を作成したり、デフォルトで内蔵されているものをカスタマイズすることが可能です。これは、signingConfigs DSL コンテナを通じて行います。
android {
signingConfigs {
debug {
storeFile file("debug.keystore")
}
myConfig {
storeFile file("other.keystore")
storePassword "android"
keyAlias "androiddebugkey"
keyPassword "android"
}
}
buildTypes {
foo {
debuggable true
jniDebugBuild true
signingConfig signingConfigs.myConfig
}
}
}
上記のスニペットは、デバッグキーストアの位置をプロジェクトのルートに変更するものです。自動的にこれを使用するビルドタイプに影響を与えます。このケースの場合、 debug Build タイプです。
また、新しい Signing Config と 新しいビルドタイプを生成し、新しい設定を利用します。
注意:デフォルトの場所のデバッグキーストアだけが自動的に生成されます。デバッグキーストアの位置を変更すると、オンデマンドで生成されんくなります。違う名前でSigningConfigを生成すると自動的にデフォルトのデバッグキーストアを使用します。
言い換えると、キーストアの位置が強く結びついており、設定名ではありません。
注意:キーストアの位置は大抵はプロジェクトのルートから相対的なもので、絶対パスはオススメできません。(自動的に生成される debugキーストアを除く)。
3.4.4 ProGuardの実行
バージョン0.4から、ProGuardはProGuardバージョン4.9向けGradleプラグインを通じてサポートされています。
ビルドタイプが runProguard プロパティを通じてProGuardが設定されている場合、ProGuardプラグインは自動的に適用され、タスクは自動的に生成されます。
android {
buildTypes {
release {
runProguard true
proguardFile getDefaultProguardFile('proguard-android.txt')
}
}
productFlavors {
flavor1 {
}
flavor2 {
proguardFile 'some-other-rules.txt'
}
}
}
変数はこれらのビルドタイプとプロダクトフレーバーに定義されている全てのルールファイルを使用します。
2つのデフォルトルートファイルがあります。
- proguard-android.txt
- proguard-android-optimize.txt
これらは SDK に格納されています。getDefaultProguardFile() を使用して、ファイルのフルパスを返します。これらは最適化が有効になることを除いて全く同一です。
4 依存性、Android ライブラリと複数プロジェクトのセットアップ
Gradleプロジェクトは他のコンポーネントへの依存性を持つことができます。これらコンポーネントは外部のバイナリパッケージや他のGradleプロジェクトです。
4.1 バイナリパッケージの依存性
4.1.1 ローカルのパッケージ
外部ライブラリのjarに依存する設定のため、コンパイル設定上の依存性を追記する必要があります。
dependencies {
compile file('libs/foo.jar')
}
android {
...
}
注意:DSL要素は標準 Gradle API の一部で、android の要素中には属しません。
コンパイルの設定は、メインアプリケーションをコンパイルするために使用されます。全てコンパイルのクラスパスとして追加され、APKにも含まれます。
これらは依存性を追加する他の使用可能な設定です:
- compile: メインアプリケーション
- instrumentTestCompile: テストアプリケーション
- debugCompile: デバッグビルドタイプ
- releaseCompile: リリースビルドタイプ
関連するビルド・タイプがないAPKを構築することが不可能なため、APKは常に2つ(以上)の設定を有します:
compile and <buildtype>Compile.
新しいビルドタイプを生成すると、自動的に名前をベースとした新しい設定を生成します。
これはデバッグバージョンが(インスタンスのクラッシュを報告するなどで)カスタムライブラリが必要である一方、リリースでは必要がない時や同じライブラリの異なるバージョンに依存する場合に使用するのに便利です。
4.1.2 リモートアーティファクト
Gradle は Maven と Ivy リポジトリからアーティファクトをpullすることをサポートしています。
最初にリポジトリはリストに追加しなければなりません。その後、依存性は Maven または Ivy が宣言するアーティファクトに従って宣言される必要があります。
repositories {
mavenCentral()
}
dependencies {
compile 'com.google.guava:guava:11.0.2'
}
android {
...
}
注意:mavenCentral はリポジトリのURLを特定するためのショートカットです。Gradle はリモート及びローカルリポジトリの両方をサポートします。
注意:Gradle は全ての依存性において他動的に従うでしょう。これは、依存性が自身の依存性を有する場合、同様にpullされることを意味します。
依存性のセットアップに関するさらなる情報は、Gradleユーザーガイド、および、 DSLドキュメントを参照してください。
4.2 複数のプロジェクトセットアップ
Gradleプロジェクトは、複数プロジェクトのセットアップを使用することにより、他のGradleプロジェクトに依存することもできます。
複数プロジェクトのセットアップは、ルートプロジェクトのサブフォルダとして全てのプロジェクトを有することにより、大抵は動作します
例えば、以下のような構造を与えます:
MyProject/
+ app/
+ libraries/
+ lib1/
+ lib2/
3つのプロジェクトを識別することができます。Gradle は以下の名前を参照します:
それぞれのプロジェクトは、自身の build.gradle を持ち、どのようにビルドするかを宣言します。
加えて、settings.gradleと呼ばれるファイルをプロジェクトのルートに宣言します。
これは以下のような構造を与えます:
MyProject/
| settings.gradle
+ app/
| build.gradle
+ libraries/
+ lib1/
| build.gradle
+ lib2/
| build.gradle
settings.gradle のコンテンツは非常にシンプルです:
include ':app', ':libraries:lib1', ':libraries:lib2'
これは、どのフォルダが実際のGradleプロジェクトかを定義します。
:app プロジェクトはライブラリに依存し、以下の依存性を宣言することで実行されます:
dependencies {
compile project(':libraries:lib1')
}
さらなる情報については、複数プロジェクトのセットアップを参照してください。
4.3 ライブラリプロジェクト
上記の複数プロジェクトのセットアップで、:libraries:lib1 と :libraries:lib2 は Javaプロジェクト、:app は Android プロジェクトで、jarの出力を使用します。
しかし、Android API または Android スタイルのリソースへのアクセスをするコードをシェアしたい場合、Androidライブラリプロジェクトでなければなりません。
4.3.1 ライブラリプロジェクトの生成
ライブラリプロジェクトは、一般的な Android プロジェクトが若干の違いを持っていることに似ています。
ライブラリのビルドはアプリケーションのビルドとは異なるため、異なるプラグインが使用されます。
内部的には、両方のプラグインが同じコードの大部分を共有し、これらは同じ com.android.tools.build.gradle jar を提供します。
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.4.2'
}
}
apply plugin: 'android-library'
android {
compileSdkVersion 15
}
これは コンパイルのために API 15 を使用するライブラリプロジェクトを生成します。
ソースセットと依存性は、アプリケーションプロジェクトと同じように、同じ方法でカスタマイズすることができます。
4.3.2 プロジェクトとライブラリプロジェクトとの違い
ライブラリプロジェクトは APKを生成せず、(Androidアーカイブを表す).aar パッケージを生成します。同一のアンカータスクはこれ(assembleDebug, assembleRelease)のために使用されます。そのため、そのようなプロジェクトを構築するコマンドに違いはありません。
ライブラリプロジェクトはまた、テスト APK を(テストの章をご覧ください)生成します。しかし、これはスコープとビルドタイプの使い方はさらに制限されています。これらのプロジェクトは2つのビルドタイプ、debug と release にのみアクセスします。デバッグタイプはテストアプリによって使用されます。リリースタイプはライブラリを使用するプロジェクトによって利用されます。
さらに、APKが生成されるのは一つだけなので、唯一の SigningConfig オブジェクトが存在します。これはテストAPKの署名で使用されます。DSLライブラリプロジェクトは次のようになります:
android {
debug {
...
}
release {
...
}
debugSigningConfig {
storeFile file("debug.keystore")
}
}
ビルドタイプの主な設定は、ライブラリプロジェクトには適用されないことに注意してください。
しかしながら、プロジェクトによって使用されているか、テストされているかによって、ライブラリの内容を変更するカスタムソースセットを使用することができます。
4.3.3 ライブラリの参照
ライブラリの参照は、参照された他のプロジェクト同じように実行することができます:
dependencies {
compile project(':libraries:lib1')
compile project(':libraries:lib2')
}
注意:一つ以上のライブラリを有する場合、順序は重要です。これは、project.properties ファイルの依存性の順序が重要な旧ビルドシステムと同様です。
5 テスト
テストアプリケーションのビルドは、アプリケーションプロジェクトに統合されています。テストプロジェクトを分ける必要はありません。
5.1 基礎と設定
前節で示したように、mainのソースセットの次はinstrumentTestソースセットで、デフォルトでは src/instrumentTest/ に配置されています。このソースセットから、Android instrumentation フレームワークを使用して、アプリケーションをテストするためにデバイスにデプロイされる、テストAPKがビルドされます。ソースセットには AndroidManifest.xml を含めるべきではありません。なぜなら、自動的に生成されるためです。
テストアプリ用に設定可能ないくつかの値があります。
- testPackageName
- testInstrumentationRunner
前に示した通り、これらは defaultConfig オブジェクトで設定されます:
android {
defaultConfig {
testPackage "com.test.foo"
testInstrumentationRunner "android.test.InstrumentationTestRunner"
}
}
defaultConfig および/または ビルドタイプオブジェクトの設定に関わらず、テストアプリケーションマニフェスト中の、instrumentation ノードの targetPackage の属性値は、テストされるアプリのパッケージ名で自動的に埋められます。これは自動的にマニフェストが自動的に生成される理由の一つとなっています。
加えて、ソースセットは依存性を持つように設定することができます。デフォルトでは、アプリケーションとその依存性はテストアプリのクラスパスに追加されますが、これは以下の方法で拡張することができます。
dependencies {
instrumentTestCompile 'com.google.guava:guava:11.0.2'
}
テストアプリは assembleTest タスクによってビルドされます。これは メインの assemble タスクには依存せず、代わりにテストが実行される際に自動的に呼び出されます。
現在は1つのビルドタイプのみテストされます。デフォルトでは、debug ビルドタイプのみですが、これは以下のように再設定することができます。
android {
...
testBuildType "staging"
}
5.2 テストの実行
前に示したように、deviceCheck と呼ばれる一番最後のタスクによって起動された接続済み端末を要求することをチェックします。これは instrumentTest タスクに依存しており、これにより実行されます。このタスクは次のことを実行します:
- アプリとテストアプリがビルドされることを保証します。(assembleDebug 及び assembleTestに依存します)
- 両方のアプリをインストールします。
- テストを実行します。
- 両方のアプリをアンインストールします。
もし、1つ以上の端末が接続されている場合、全てのテストは並列に全て接続済み端末上で実行されます。いずれかの端末上でテストが失敗したら、ビルドは失敗します。
全てのテスト結果は build/instrumentTest-results 下の XML ファイルに格納されます。(これは、build/test-results 下に格納される一般的な jUnit の結果と似ています。)
これは以下のように設定することができます。
android {
...
testOptions {
resultsDir = "$project.buildDir/foo/results"
}
}
android.testOptions.resultsDir の値は Project.file(String) で評価されます。
5.3 Androidライブラリのテスト
Android のライブラリプロジェクトのテストは、アプリのプロジェクトと全く同一の方法で行います。
唯一の違いは、全体のライブラリ(とその依存性)が、テストアプリに対してライブラリの依存性として自動的に付加されることです。
結果は、テストAPK自身コードではなく、ライブラリとその全ての依存性を含んでいる、テストAPKです。ライブラリのマニフェストは、テストアプリのマニフェストにマージされています(このライブラリを参照するプロジェクトのケースとして)。
instrumentTest タスクはテストAPKのインストール(とアンインストール)時のみ変更されます(インストールする他のAPKがないため)。
その他は全て同一です。
5.4 テストレポート
ユニットテストの実行時、Gradle は 結果が容易に分かるように HTMLのレポートを出力します。Android のプラグインは これをビルドし、全ての接続済み端末の結果を集計するために HTML のレポートを拡張します。
5.4.1 単一のプロジェクト
プロジェクトはテストの実行で自動的に生成されます。デフォルトの配置場所は build/reports/instrumentTests です。これは build/reports/tests にある jUnit のレポート の配置場所、あるいは、 build/reports/<plugin>/ の中によくある、他のレポートの配置場所に似ています。
配置場所は以下のようにして変更することができます。
android {
...
testOptions {
reportDir = "$project.buildDir/foo/report"
}
}
レポートは異なる端末で実行された複数のテストを集計します。
5.4.2 複数プロジェクトのレポート
複数のアプリケーションとライブラリのプロジェクトを伴う複数プロジェクトのセットアップは、同時に全てのテストが実行される時に、全ての instrumentation テストを単一の結果として生成するのに便利です。
これを実施するために、同じ生成物の中で、異なるプラグインを使用できるようにします。それは以下のようにして適用します:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.3'
}
}
apply plugin: 'android-reporting'
これは settings.gradle の次の build.gradle の中でなど、ルートプロジェクトで適用すべきです。この時、ルートフォルダーから、以下のコマンドラインで全てのテストを実行し、結果を集計します:
gradle deviceCheck mergeAndroidReports --continue
注意: --continue オプションは全てのテストを保証し、例えば一部のテストが失敗しても全てのサブプロジェクトは実行されます。このオプションがなければ、最初のテストの失敗時にテストの実行は中断され、全てのテストは実行されません。
5.5 Lintのサポート
まだサポートしていません。しばし待たれよ。
6 ビルド変数
新しいビルドシステムのゴールのひとつは、同じアプリケーションの異なるバージョンの生成を有効にすることです。大きく2つのユースケースがあります:
- 同じアプリケーションの異なるバージョン。例えば、フリー/デモ版 VS 有料の pro 版。
- Google Play Store のマルチAPKによる異なるパッケージの同じアプリ。詳細は、http://developer.android.com/google/play/publishing/multiple-apks.html を参照。
- 1. と 2. のコンビネーション。
ゴールは、単一のライブラリプロジェクトと2つ以上のアプリケーションプロジェクトを使用することとは対照的に、同じプロジェクトからこれらの異なるAPKを生成することです。
6.1 プロダクトフレーバー(Product flavors)
プロダクトフレーバーは、プロジェクトによりビルドするカスタマイズされたアプリケーションのバージョンを定義します。単一のプロジェクトは、生成されたアプリケーションを変える異なるフレーバーを持つことができます。
この新しいコンセプトとは、変更がとても小さい時に便利なように設計されています。「これは同じアプリケーションか?」という問いに対して答えがYesの時、これはおそらくライブラリプロジェクトに関する方法です。
プロダクトフレーバーは、productFravors DSLコンテナを使用して宣言します:
android {
....
productFlavors {
flavor1 {
...
}
flavor2 {
...
}
}
}
これは、flavor1 と flavor2 の2つのフレーバーを生成します。
注意:フレーバーの名前は、既に存在するビルドタイプや instrumentTest ソースセットの名前を衝突してはいけません。
6.2 ビルドタイプ + プロダクトフレーバー = ビルド変数
前説で確認したように、それぞれのビルドタイプは新しいAPKを生成します。
プロダクトフレーバーも同じように機能します:プロジェクトの出力は、ビルドタイプと適用可能であればプロダクトフレーバーの両者の全ての可能な組み合わせとなります。
それぞれ(ビルドタイプ、プロダクトフレーバー)の組み合わせは、ビルド変数と呼ばれます。
デフォルトの debug と release ビルドタイプの例では、4つのビルド変数を生成します:
- flavor1 - debug
- flavor1 - release
- flavor2 - debug
- flavor2 - release
フレーバーのないプロジェクトもまたビルド変数を有します。しかし、単一のデフォルトフレーバー/設定が無名で使用され、ビルドタイプのリストに似た変数のリストを作成します。
6.3 プロダクトフレーバーの設定
各フレーバーはクロージャで設定されます:
android {
...
defaultConfig {
minSdkVersion 8
versionCode 10
}
productFlavors {
flavor1 {
packageName "com.example.flavor1"
versionCode 20
}
flavor2 {
packageName "com.example.flavor2"
minSdkVersion 14
}
}
}
android.productFlavors.* オブジェクトは、android.defaultConfigオブジェクトと同じタイプのプロダクトフレーバータイプのオブジェクトです。これは、同じプロパティを共有することを意味します。
defaultConfig は全てのフレーバーと各フレーバーが任意の値でオーバーライド可能な、基準の設定を提供します。以下の例では次のように解釈されます:
- flavor1
- packageName: com.example.flavor1
- minSdkVersion: 8
- versionCode : 20
- flavor2
- packageName: com.example.flavor2
- minSdkVersion: 14
- versionCode: 10
たいていの場合、ビルドタイプ設定は他の設定の上にオーバーレイされます。例えば、ビルドタイプの packageNameSuffix はプロダクトフレーバーの packageName に追加されます。ビルドタイプとプロダクトフレーバーの両方が設定可能なケースがあります。このケースの場合、基本ケースの上にケースが乗っています。例えば、signingConfig はこれらの属性の一つです。
これは、全てのリリースパッケージが android.buildTypes.release.signingConfig によって同じ SigningConfig を共有するか、あるいは、それぞれのリリースパッケージが、android.productFavors.*.signingConfig オブジェクトを個別に設定することで、自身の SigningConfig を使用することを有効にします。
6.4 ソースセットと依存性
ビルドタイプと同様にプロダクトフレーバーもまた、自身の sourceSets を通じてコードとリソースを提供します。
上記の例は、4つの sourceSets を生成します:
- android.sourceSets.flavor1
- Location src/flavor1/
- android.sourceSets.flavor2
- Location src/flavor2/
- android.sourceSets.instrumentTestFlavor1
- Location src/instrumentTestFlavor1/
- android.sourceSets.instrumentTestFlavor2
- Location src/instrumentTestFlavor2/
これらの sourceSets は android.sourceSets.main と ビルドタイプの sourceSet と並んで、APK のビルドで使用されます。
以下のルールは、単一の APK をビルドするために全てのソースセットを取り扱う際に使用されます:
- 全てのソースコード(src/*/java)は、単一の結果を生成する複数のフォルダと共にっ使用されます。
- マニフェストは、単一のマニフェストの中に全てマージされます。これは、ビルドタイプと同様に、プロダクトフレーバーに異なるコンポーネント、及び/または、権限を持つことを許します。
- 全てのリソース(Android の res と assets)は、プロダクトフレーバーをオーバーライドするビルドタイプのところで、優先度をオーバーレイして使用され、これは main ソースセットを上書きします。
- 各ビルド変数は、自身の R クラス(または他の生成されたソースコード)をリソースから生成します。変数間では何も共有されません。
最後に、ビルドタイプのようにプロダクトフレーバーは自身の依存関係を持つことができます。例えば、フレーバーが広告ベースのアプリと支払いベースのアプリを生成するために使用される場合、フレーバーの一つは広告SDKに依存し、他はそうしないようにできます。
dependencies {
flavor1Compile "..."
}
特にこの場合は、src/flavor1/AndroidManifest.xml ファイルがインターネット権限を含む必要が、おそらくあるでしょう。
6.5 ビルドとタスク
前にそれぞれのビルドタイプは自身の assemble<name> タスクを生成することをみましたが、しかし、そのビルド変数はビルドタイプとプロダクトフレーバーのコンビネーションです。
プロダクトフレーバーの使用時、assemble タイプのタスクが生成されます。これらは以下のようなものがあります。
- assemble<Variant Name>
- assemble<Build Type Name>
- assemble<Product Flavor Name>
1は単一の変数を直接ビルドすることを許します。例えば、assembleFlavor1Debug.
2は指定のビルドタイプで全てのAPKをビルドすることを許します。たとえば、assembleDebug は Flavor1Debug と Flavor2Debug の両方の変数をビルドします。
3は指定のフレーバーで全てのAPKをビルドすることを許します。例えば、assembleFlavor1 は Flavor1Debug と Flavor1Release の両方の変数をビルドします。
assemble タスクは、もちろん、全ての使用可能な変数をビルドします。
6.6 テスト
マルチフレーバープロジェクトのテストは、単純なプロジェクトに非常に似ています。
instrumenTest ソースセットは全てのフレーバーに渡る共通のテストとして使用され、それぞれのフレーバーはまた、自身のテストを持つことが可能です。
上記のように、各フレーバーをテストするためのソースセットは生成されます:
- android.sourceSets.instrumentTestFlavor1
- Location src/instrumentTestFlavor1/
- android.sourceSets.instrumentTestFlavor2
- Location src/instrumentTestFlavor2/
同様に、これらは自身の依存性を持つことができます:
dependencies {
instrumentTestFlavor1Compile "..."
}
テストの実行は、メインの deviceCheck アンカータスクを通じて実施することができます。あるいは、フレーバーが使用される時、アンカータスクとして動作するメインの instrumentTest タスクを通じて実施することができます。
各フレーバーはテストを実行するために自身のタスクを持ちます:instrumentTest<変数名>
例えば、
- instrumentTestFlavor1Debug
- instrumentTestFlavor2Debug
同様に、テストAPKはタスクをビルドし、変数ごとにインストール/アンインストールタスクがあります。
- assembleFlavor1Test
- installFlavor1Debug
- installFlavor1Test
- uninstallFlavor1Debug
...
最後に、HTMLレポートの生成は、フレーバーの集まりをサポートします。
テスト結果とレポートの場所は以下の通りです。最初はフレーバーのバージョンごとで、その後一つにまとめられます。
- build/instrumentTest-results/flavors/<FlavorName>
- build/instrumentTest-results/all/
- build/reports/instrumentTests/flavors<FlavorName>
- build/reports/instrumentTests/all/
それぞれのパスの変更は、ルートのフォルダーを変更するのみです。フレーバーごとのサブフォルダーは生成されたままで、結果やレポートはそこに集められます。
6.7 マルチフレーバー変数
ある場合では、一つ以上の基準で、同じアプリの異なるバージョンを作りたいかもしれません。
例えば、Google PlayがサポートするマルチAPKは4つの異なるフィルターがサポートされています。それぞれのフィルターにあわせて異なるAPKを分けて生成するには、1つ以上のプロダクトフレーバーが使用できることが求められます。
デモ版と有料版のゲームで、マルチAPKサポートでABIフィルターを利用したい場合の例を考えてください。3つのABIと2つのアプリケーションのバージョンがあると、APKは6つ生成しなければなりません(異なるビルドタイプによる変数はカウントしていません)。
しかし、有料版は3つのABIが同一なので、単純に6つのフレーバーを作成することはしません。その代わり2次元のフレーバーと変数で、可能な限りの組み合わせを自動的に利用すべきです。この機能はフレーバーグループで実装されています。それぞれのグループは次元を表現し、フレーバーは特別なグループに対してアサインされます。
android {
...
flavorGroups "abi", "version"
productFlavors {
freeapp {
flavorGroup "version"
...
}
x86 {
flavorGroup "abi"
...
}
}
}
android.flavorGroups の配列は順序と共に使用可能なグループを定義します。それぞれはグループにアサインされたプロダクトフレーバーを定義します。
プロダクトフレーバー[freeapp,paidapp]と[x86,arm,mips]、ビルドタイプ[debug,release]でグループ化されて、以下のビルド変数が生成されます:
- x86-freeapp-debug
- x86-freeapp-release
- arm-freeapp-debug
- arm-freeapp-release
- mips-freeapp-debug
- mips-freeapp-release
- x86-paidapp-debug
- x86-paidapp-release
- arm-paidapp-debug
- arm-paidapp-release
- mips-paidapp-debug
- mips-paidapp-release
android.flavorGroups で定義されたグループの順番は非常に重要です。
それぞれの変数はいくつかのプロダクトフレーバーで設定されます:
- android.defaultConfig
- One from the abi group
- One from the version group
フレーバーの値が、優先順位の低いフレーバーの値を上書きする時、グループの順番はその他でオーバーライドされたフレーバーを操作しますが、これはリソース面で非常に重要です。
フレーバーグループは優先順位の高く定義されます。以下のようなケースが成り立ちます:
abi > version > defaultConfig
7 ビルドカスタム応用編
7.1 ビルドオプション
7.1.1 Java コンパイルオプション
android {
compileOptions {
sourceCompatibility = "1.6"
targetCompatibility = "1.6"
}
}
デフォルト値は “1.6” です。Java ソースコードをコンパイルする全てのタスクに影響します。
7.1.2 aapt オプション
android {
aaptOptions {
noCompress 'foo', 'bar'
ignoreAssetsPattern "!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"
}
}
これは aapt を使用する全てのタスクに影響します。
7.1.3 dex オプション
android {
dexOptions {
incremental false
}
}
これは dex を使用する全てのタスクに影響します。デフォルトは true。
7.2 タスクの操作
基本的な Java プロジェクトは有限のタスクセットを保持しており、出力を生成するように動作します。Java ソースコードをコンパイルする classes タスクもその一つです。
スクリプト中で classes を単に使用して、build.gradle からアクセスするのは容易です。これは project.tasks.classes のショートカットです。
Android プロジェクトでは、同じタスクや Build Typesand Project Flavorsに基づいて生成される名前が数多くあることから、もう少し複雑になっています。これを確定するために、android オブジェクトは以下のプロパティを持っています:
- applicationVariants (アプリのプラグインのみ)
- libraryVariants (ライブラリのプラグインのみ)
- testVariants (両方のプラグイン)
それぞれ、ApplicationVariant, LibraryVariant, TestVariant オブジェクトの DomainObjectCollection を戻します。
各々のコレクションへのアクセスは、全てのタスクの生成のトリガとなることに注意してください。これは、コレクションのアクセス後に(再)設定すべきではないことを意味します。
DomainObjectCollection は、全てのオブジェクトに直接 または 便利なフィルタを通じてアクセスする方法を付与します。
android.buildVariants.each { variant ->
....
}
3つ全てで共有するプロパティは以下の通り:
プロパティ名 | プロパティタイプ | 説明 |
---|---|---|
name | String | 変数名。ユニークであることが保証されます。 |
description | String | 人間が読むことができる変数の説明。 |
dirName | String | 変数名のサブフォルダ。ユニークであることが保証されます。'debug/flavor1'のように1つ以上になる可能性 |
baseName | String | 変数の出力の基本名。ユニークであることが保証されます。 |
outputFile | File | 変数出力。これは読み込み/書き込みプロパティです。 |
processManifest | ProcessManifest | マニフェストを処理するタスク |
aidlCompile | AidlCompile | AIDLファイルをコンパイルするタスク |
renderscriptCompile | RenderscriptCompile | レンダースクリプトファイルをコンパイルするタスク |
mergeResources | MergeResources | リソースをマージするタスク |
mergeAssets | MergeAssets | アセットをマージするタスク |
processResources | ProcessAndroidResources | 処理とリソースのコンパイルをするタスク |
generateBuildConfig | GenerateBuildConfig | ビルドコンフィグクラスを生成するタスク |
javaCompile | JavaCompile | Javaのコードをコンパイルするタスク |
processJavaResources | Copy | Javaのリソースを処理するタスク |
assemble | DefaultTask | この変数のアセンブルアンカータスク。 |
ApplicationVariant クラスは下記を追加します:
プロパティ名 | プロパティタイプ | 説明 |
---|---|---|
buildType | BuildType | 変数のビルドタイプ |
productFlavors | List<ProductFlavor> | 変数のプロダクトフレーバー。常にNullは許容されないが、空は許容される。 |
mergedFlavor | ProductFlavor | android.defaultConfig と variant.productFlavors をマージしたもの。 |
signingConfig | SigningConfig | 変数によって使用される SigningConfig オブジェクト |
isSigningReady | boolean | 変数が署名のための必要な情報を全て有しているとき true |
testVariant | BuildVariant | 変数によってテストされるビルド変数 |
dex | Dex | dexコードのタスク。変数がライブラリならnullにできる。 |
packageApplication | PackageApplication | 最終APKを生成する。変数がライブラリならnullにできる。 |
zipAlign | ZipAlign | zipalignsのAPKのタスク変数がライブラリまたはAPKに署名されていない場合はnullにできる。 |
install | DefaultTask | インストールタスク。null可。 |
Uninstall | DefaultTask | アンインストールタスク |
LibraryVariant クラスは下記を追加します:
プロパティ名 | プロパティタイプ | 説明 |
---|---|---|
buildType | BuildType | 変数のビルドタイプ |
config | ProductFlavor | defaultConfigの値 |
testVariant | BuildVariant | 変数によってテストされるビルド変数 |
packageLibrary | Zip | AARアーカイブライブラリのパッケージのタスク。ライブラリでない場合はnull。 |
TestVariant クラスは下記を追加します:
プロパティ名 | プロパティタイプ | 説明 |
---|---|---|
buildType | BuildType | 変数のビルドタイプ |
productFlavors | List<ProductFlavor> | 変数のプロダクトフレーバー。常にNullは許容されないが、空は許容される。 |
mergedFlavor | ProductFlavor | android.defaultConfig と variant.productFlavors をマージしたもの。 |
signingConfig | SigningConfig | 変数によって使用される SigningConfig オブジェクト |
isSigningReady | boolean | 変数が署名のための必要な情報を全て有しているとき true |
testVariant | BuildVariant | 変数によってテストされるビルド変数 |
dex | Dex | dexコードのタスク。変数がライブラリならnullにできる。 |
packageApplication | PackageApplication | 最終APKを生成する。変数がライブラリならnullにできる。 |
zipAlign | ZipAlign | zipalignsのAPKのタスク変数がライブラリまたはAPKに署名されていない場合はnullにできる。 |
install | DefaultTask | インストールタスク。null可。 |
Uninstall | DefaultTask | アンインストールタスク |
connectedInstrumentTest | DefaultTask | 接続されたデバイス上のinstrumentationテストを実行するタスク |
providerInstrumentTest | DefaultTask | 拡張APIを使用するinstrumentation テストを実行するタスク |
Android 専用タスクタイプのAPIは次の通り。
- ProcessManifest
- File manifestOutputFile
- AidlCompile
- File sourceOutputDir
- RenderscriptCompile
- File sourceOutputDir
- File resOutputDir
- MergeResources
- File outputDir
- MergeAssets
- File outputDir
- ProcessAndroidResources
- File manifestFile
- File resDir
- File assetsDir
- File sourceOutputDir
- File textSymbolOutputDir
- File packageOutputFile
- File proguardOutputFile
- GenerateBuildConfig
- File sourceOutputDir
- Dex
- File outputFile
- PackageApplication
- File resourceFile
- File dexFile
- File javaResourceDir
- File jniDir
- File outputFile
- ZipAlign
- File inputFile
- File outputFile
それぞれのタスクタイプ用APIは、Gradle の振る舞いと Android プラグインをセットアップの振る舞いの両方に限定されます。
最初に、Gradleは入出力の位置と使用可能なフラグのみを設定するタスクを持つことが目的です。そのため、タスクは(いくつかの)入出力のみを定義します。
2番目に、これらのタスクの多くの入力は自明ではなく、sourceSets やビルドタイプ、プロダクトフレーバーから値をミックスしたものになります。読んだり理解するためにシンプルなビルドファイルを維持するため、開発者がDSLを通じてこれらのオブジェクトを操作しビルドを編集させることが目的です。
加えて、ZipAlign タスクタイプを除いて、全てのタイプはこれら作業のためのプライベートなデータをセットアップすることを要求します。
このAPIは変更の対象です。一般的に現在のAPIは、出力と、追加で他の処理が必要なタスクの入力(可能なら)にアクセスする権利を与えます。特に予期しなかったもので必要に応じて、フィードバックは評価されます。
Gradleタスク(DefaultTask, JavaCompile, Copy, Zip) については、Gradleのドキュメントを参照ください。
7.3 BuildType と Product Flavor プロパティの参照
乞うご期待。
文責:株式会社ブリリアントサービス 品川事業所 八木俊広、瀬戸直喜(@Lionas)
記載されている会社名、および商品名等は、各社の商標または登録商標です。
0 コメント:
コメントを投稿