Android Gradle Plugin 0.12 → 0.13の変更点


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`に修正する必要があります。

```groovy:gradle.properties
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を使って以下のようにテストケースを書くとします。

```:java
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によるカバレッジ計測](http://ksoichiro.blogspot.jp/2014/05/androidgradle-jacoco.html)で10%程度だったものが[95%以上](https://github.com/ksoichiro/SimpleAlertDialog-for-Android)までカバーできるようになりました。

### 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でも未解決のようです。

![Screenshot 2014-10-05 15.29.36.png](https://qiita-image-store.s3.amazonaws.com/0/29368/90686598-b88c-d6b6-5cfa-fe1d883534c1.png "Screenshot 2014-10-05 15.29.36.png")


## `AndroidManifest`の placeholder が Build Types でも設定可能に

`AndroidManifest`におけるplaceholderというのは、Android Gradle Plugin 0.11で導入された(はずの)ものです。
`AndroidManifest`内に`${xxx}`の形式で記述しておき、`build.gradle`でその値を決定するものです。
例えば以下のように書いておき、ActivityのラベルをProduct Flavorごとに変えることができます。

```groovy:build.gradle
    defaultConfig {
        applicationId "com.example"
        :
        manifestPlaceholders = [ activityLabelMain: "Example" ]
    }
    productFlavors {
        free {
            applicationId "com.example.free"
            manifestPlaceholders = [ activityLabelMain: "Example free" ]
        }
        pro {
            manifestPlaceholders = [ activityLabelMain: "Example pro" ]
        }
    }
```

```xml:AndroidManifest.xml
        <activity
            android:name=".MainActivity"
            android:label="${activityLabelMain}" >
```

上記では、`installFreeDebug`でインストールすると`Example Free`、`installProDebug`でインストールすると`Example Pro`のラベルが表示されます。

これまでこの機能はProduct Flavorで利用可能でしたが、Build Typeでも使えるようになったようです。
同じ例を使うと、例えば以下のようにBuild Typeをラベルにくっつけることができます。

```groovy:build.gradle
    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: "" ]
        }
    }
```

```xml:AndroidManifest.xml
        <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)が取得できていることが分かります。

```groovy:build.gradle
android {
    :
    productFlavors {
        free {
            :
        }
        pro {
            :
        }
    }
    buildTypes {
        debug {
            :
        }
        release {
            runProguard true
            :
        }
    }
    :
}

afterEvaluate { ->
    android.applicationVariants.each { variant ->
        println "mapping: ${variant.name}: ${variant.getMappingFile()?.path}"
    }
}
```

```sh
$ ./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](http://tools.android.com/tech-docs/new-build-system/user-guide/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ではテストケース(テストケースクラス)が一つもないとタスクが失敗するようになりました。

![Screenshot 2014-10-05 15.40.40.png](https://qiita-image-store.s3.amazonaws.com/0/29368/20cea825-1401-5b8e-4b5a-bf5c17c3542f.png "Screenshot 2014-10-05 15.40.40.png")


テストが全くないプロジェクトで(テストでなく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