Android Gradle Plugin 0.13が9月にリリースされて2週間以上が経ち、既に記事を書かれている方もいらっしゃるので今更なのですが、個人的に重要と思う箇所があり0.12 → 0.13の変更点について詳細に確認してみました。
http://tools.android.com/tech-docs/new-build-system
対象は、現時点でリリースされている0.13.0から0.13.2までです。
実際の動作等は部分的にしか確認できていませんので、ご了承ください。
※伝聞調の書き方の部分は未確認と思ってください
※後日アップデートするかもしれません
0.13.0の変更点
Gradle 2.1以上が必要
これまでGradle 1.10+が必要でしたが、これではもう動かなくなりました。
Gradleラッパー(gradlew)を使っている場合は、gradle/wrapper/gradle.properties
のdistributionUrl
のバージョン部分を以下のように2.1
に修正する必要があります。
distributionUrl=http\://services.gradle.org/distributions/gradle-2.1-all.zip
build.gradle
に独自のスクリプトを書いている場合は、Gradle 2.1で使えなくなるものがないか確認する必要があるかもしれません。
テストアプリでAndroidManifest
が定義可能に
テストアプリといっているのはconnectedAndroidTest
などのタスクで動かすInstrumentationTestCase
などのことですが、これまでは Plugin がテスト用のManifestを自動生成していたため、独自の設定を入れたりすることができませんでした。
これは特にライブラリ開発の場合に重要です。
UIライブラリなどでは実際のActivityに組込んで動かさなければほとんどテストできないため、Activityから利用するテストケースを書きたくなりますが、Activityを呼び出すにはAndroidManifest
に<activity>
の定義を書かなければなりません。
今まで、Android Gradle Pluginでのテストではこうした設定が書けなかったため、以下のような方法をとるしかありませんでした。
- Activityを使わなくてもできる部分だけをテストする
- テスト用のアプリを別プロジェクトとして用意してテストする
- (ライブラリにテスト用のActivityを組込む)
例えば、パッケージcom.example
をテストするActivityを使って以下のようにテストケースを書くとします。
package com.example.test;
:
public class ActivityTest extends ActivityInstrumentationTestCase2<DemoActivity> {
private DemoActivity activity;
public ActivityTest() {
super(DemoActivity.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
setActivityInitialTouchMode(true);
activity = getActivity();
}
この場合、AndroidManifestに以下のような定義を書く必要があり、今までは書いても無視されていたのですが0.13で取り込まれるようになりました。
(つまり、テスト専用のActivityを用意してライブラリをテストすることができます)
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.test">
<application>
<uses-library android:name="android.test.runner" />
<activity android:name=".DemoActivity" />
</application>
</manifest>
<instrumentation>
は自動的に追加されます。
※この変更のおかげで、自分のUIライブラリの場合はJaCoCoによるカバレッジ計測で10%程度だったものが95%以上までカバーできるようになりました。
Android Studioでの注意点
現時点のBeta 0.8.6はこの仕組みに対応していないため、少々問題があります。
テスト用のR.javaが生成されない
テストアプリのpackageは末尾に.test
がつく別アプリの位置づけになるため、R.javaは本体とは別になりますが、0.8.6ではこれがビルドされません。
Android Studioで認識させるには、一度コマンドラインで./gradlew connectedCheck
などでビルドする必要があります。
現時点のBeta Channelで配布されているAndroid Studio 0.8.9では解消しています。
テスト用AndroidManiest
内のURIやActivity名が認識されない
以下のように赤字になってしまいますが、動作上は問題ないです。
これはAndroid Studio 0.8.9でも、Canary Channel最新の0.8.11でも未解決のようです。
AndroidManifest
の placeholder が Build Types でも設定可能に
AndroidManifest
におけるplaceholderというのは、Android Gradle Plugin 0.11で導入された(はずの)ものです。
AndroidManifest
内に${xxx}
の形式で記述しておき、build.gradle
でその値を決定するものです。
例えば以下のように書いておき、ActivityのラベルをProduct Flavorごとに変えることができます。
defaultConfig {
applicationId "com.example"
:
manifestPlaceholders = [ activityLabelMain: "Example" ]
}
productFlavors {
free {
applicationId "com.example.free"
manifestPlaceholders = [ activityLabelMain: "Example free" ]
}
pro {
manifestPlaceholders = [ activityLabelMain: "Example pro" ]
}
}
<activity
android:name=".MainActivity"
android:label="${activityLabelMain}" >
上記では、installFreeDebug
でインストールするとExample Free
、installProDebug
でインストールするとExample Pro
のラベルが表示されます。
これまでこの機能はProduct Flavorで利用可能でしたが、Build Typeでも使えるようになったようです。
同じ例を使うと、例えば以下のようにBuild Typeをラベルにくっつけることができます。
defaultConfig {
applicationId "com.example"
:
manifestPlaceholders = [ activityLabelMain: "Example" ]
}
productFlavors {
free {
applicationId "com.example.free"
manifestPlaceholders = [ activityLabelMain: "Example free" ]
}
pro {
manifestPlaceholders = [ activityLabelMain: "Example pro" ]
}
}
buildTypes {
// debugビルドのみ末尾に debug を付与
debug {
manifestPlaceholders = [ activityLabelSuffix: " debug" ]
}
release {
:
manifestPlaceholders = [ activityLabelSuffix: "" ]
}
}
<activity
android:name=".MainActivity"
android:label="${activityLabelMain}${activityLabelSuffix}" >
上記でビルドすると、ラベルは以下のようになります。
-
installFreeDebug
→Example Free debug
-
installFreeRelease
→Example Free
-
installProDebug
→Example Pro debug
-
installProDRelease
→Example Pro
ライブラリのAndroidManifestでplaceholderを定義可能に
ライブラリでも上記のplaceholderが利用できるようになったようです。
ライブラリ内で未解決のplaceholderは利用アプリ側で解決させることもできるようです。
(未確認です)
Variant.getMappingFile()でProGuardマッピングファイルが参照可能に
ProGuardを実行すると、難読化前後の名称のマッピングファイルが生成されますが、このファイルにbuild.gradle
からアクセスできるようになったということのようです。
例えば、以下のようにすると、ProGuardをかけたVariantではマッピングファイルのオブジェクト(File)が取得できていることが分かります。
android {
:
productFlavors {
free {
:
}
pro {
:
}
}
buildTypes {
debug {
:
}
release {
runProguard true
:
}
}
:
}
afterEvaluate { ->
android.applicationVariants.each { variant ->
println "mapping: ${variant.name}: ${variant.getMappingFile()?.path}"
}
}
$ ./gradlew assemble
mapping: freeDebug: null
mapping: freeRelease: /xxx/app/build/outputs/proguard/free/release/mapping.txt
mapping: proDebug: null
mapping: proRelease: /xxx/app/build/outputs/proguard/pro/release/mapping.txt
:app:preBuild
:
※Issueとしては下記がありますが、アップデートがないため使い方等はよく分かりませんでした。
https://code.google.com/p/android/issues/detail?id=73737
DensityとABIでの複数APKへのSplitメカニズムを導入
詳細はApk Splitsにあります。
(未確認です)
バグ修正
(未確認です)
0.13.1の変更点
テスト用のManifestで<instrumentation>
をマージできるように
上述のテスト用AndroidManifest
での<instrumentation>
を自分で書いた場合にもマージされるようになったようです。
(未確認です)
uninstallAll
タスクの修正
0.13.0で発生した不具合の修正のようです。
./gradlew uninstallAll
を実行するとエラーが発生するようになっていたようです。
https://code.google.com/p/android/issues/detail?id=76388
設定不備があるとVariantが出力されずGradleの評価が失敗する問題を修正
(未確認です)
テストがない場合にconnectedCheck
が失敗するように
これまではテストケースのないプロジェクトではconnectedCheck
やconnectedAndroidTest
タスクを呼び出しても何事もなく通過していましたが、0.13.1ではテストケース(テストケースクラス)が一つもないとタスクが失敗するようになりました。
テストが全くないプロジェクトで(テストでなくlint等を動かしたいために)取りあえずタスクを通過させるには、androidTest/java
ディレクトリ以下に何らかのテストケースクラスを作ればOKです。
0.13.2の変更点
manifest mergerが不正な<uses-sdk>
を追加するのを修正
0.13.1で発生した不具合の修正のようです。
下記のIssueなどでレポートされており、AndroidManifest
のマージにより<uses-sdk>
が複数出力されてしまう問題があったようです。
https://code.google.com/p/android/issues/detail?id=76612
補足
Issueは以下で検索して確認しています。
https://code.google.com/p/android/issues/list?can=1&q=label%3ASubcomponent-Tools-gradle&colspec=ID+Type+Status+Owner+Summary+Stars&cells=tiles