Android plugin for Gradle 2.0.0 に更新したら Data Binding ライブラリ周りで ProGuard が警告を吐いてビルドできなくなった問題

アプリが依存するライブラリと `com.android.databinding:compiler` の依存先ライブラリがかぶっていると ProGuard が警告を吐いてビルドできなくなることがある。 多くのプロジェクトではこの問題は起こらないと思う。

最終的にどうするのがいいかまではわかってないし、詳しいこともわかっておらず原因について推測してる箇所が多いけど、メモ程度に書き残しておく。

# 発生する問題

例えば、`compile` configuration の依存に `com.google.guava:guava:19.0` が含まれていると、ProGuard の処理で以下のような警告が出て、`:app:transformClassesAndResourcesWithProguardForRelease` タスクが失敗する。 ([Android Plugin for Gradle](http://developer.android.com/intl/ja/tools/building/plugin-for-gradle.html) 2.0.0 を使って、[Data Binding](http://developer.android.com/intl/ja/tools/data-binding/guide.html) 有効で、ProGuard 有効な場合。)

```
Warning: library class android.databinding.tool.util.SourceCodeEscapers$1 extends or implements program class com.google.common.escape.CharEscaper
Warning: library class android.databinding.tool.util.SourceCodeEscapers$JavaCharEscaper extends or implements program class com.google.common.escape.ArrayBasedCharEscaper
Warning: library class android.databinding.tool.util.SourceCodeEscapers$JavaCharEscaperWithOctal extends or implements program class com.google.common.escape.ArrayBasedCharEscaper
```

下記でも同様の問題が書かれている。

* [Conflict between Android data binding and Guava causes ProGuard error - Stack Overflow](http://stackoverflow.com/questions/35472130/conflict-between-android-data-binding-and-guava-causes-proguard-error)

# 原因に関する前提

## Data Binding ライブラリと `provided` configuration への依存関係の追加

Data Binding ライブラリを有効にしている (build.gradle に `android { dataBinding { enabled = true } }` を記述) と、`provided` configuration に `com.android.databinding:compiler` の依存が追加される。 これは、ビルド時にのみ使われるツールで、レイアウトファイルを基に `YourLayoutBinding` クラスみたいなやつを生成するなどの処理に使われるっぽい。 (詳細は追いかけてない。)

Android Plugin for Gradle 1.5.0 のころは、以下のような依存関係になっていた。

```
$ ./gradlew :app:dependencies
(略)
provided - Classpath for only compiling the main sources.
\--- com.android.databinding:compiler:1.0-rc5
     +--- com.android.databinding:baseLibrary:1.0-rc5
     \--- com.googlecode.juniversalchardet:juniversalchardet:1.0.3
(略)
```

Android Plugin for Gradle 2.0.0 では、`com.android.databinding:compiler` のバージョンも更新されており、以下のようになる。

```
$ ./gradlew :app:dependencies
(略)
provided - Classpath for only compiling the main sources.
\--- com.android.databinding:compiler:2.0.0
     +--- com.android.databinding:compilerCommon:2.0.0
     |    +--- com.android.databinding:baseLibrary:2.0.0
     |    +--- com.tunnelvisionlabs:antlr4:4.5
     |    |    +--- com.tunnelvisionlabs:antlr4-runtime:4.5
     |    |    |    +--- org.abego.treelayout:org.abego.treelayout.core:1.0.1
     |    |    |    \--- com.tunnelvisionlabs:antlr4-annotations:4.5
     |    |    +--- com.tunnelvisionlabs:antlr4-annotations:4.5
     |    |    +--- org.antlr:antlr-runtime:3.5.2
     |    |    \--- org.antlr:ST4:4.0.8
     |    |         \--- org.antlr:antlr-runtime:3.5.2
     |    +--- commons-io:commons-io:2.4
     |    +--- com.googlecode.juniversalchardet:juniversalchardet:1.0.3
     |    \--- com.google.guava:guava:17.0
     +--- com.android.databinding:baseLibrary:2.0.0
     +--- org.jetbrains.kotlin:kotlin-stdlib:1.0.0
     |    \--- org.jetbrains.kotlin:kotlin-runtime:1.0.0
     +--- commons-io:commons-io:2.4
     +--- commons-codec:commons-codec:1.10
     +--- com.tunnelvisionlabs:antlr4:4.5 (*)
     \--- com.googlecode.juniversalchardet:juniversalchardet:1.0.3
(略)
```

## ProGuard と `provided` configuration

ProGuard が入力として受け付ける JAR (や WAR、AAR など) ファイルには、[input jar](http://proguard.sourceforge.net/manual/usage.html#injars) と [library jar](http://proguard.sourceforge.net/manual/usage.html#libraryjars) の 2 種類がある。

input jar は、アプリケーションに含まれるクラスファイルを含むもので、これらが処理されて出力される。
library jar の方は出力には含まれない。 「input jar の中のクラスがが依存するが、出力には含めない」というようなものを library jar として指定するようになっている。

さて、Android Plugin for Gradle には ProGuard の処理を行うタスクが定義されるが、その ProGuard の設定としては `provided` configuration に含められている依存関係を ProGuard の library jar として渡すようになっているっぽい。

[`ProGuardTransform` クラス](https://android.googlesource.com/platform/tools/base/+/gradle_2.0.0/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/transforms/ProGuardTransform.java) のコードをちょっと見たけど、追いかけられてない。

# 原因

上に書いたように、`provided` configuration に含まれる `com.android.databinding:compiler:2.0.0` は `com.google.guava:guava:17.0` に依存するが、多分 `compile` configuration の `com.google.guava:guava` の方が新しくて、そっちを使うという風に ProGuard がみなすのだと思う。 そうすると、library jar 側の `android.databinding.tool.util.SourceCodeEscapers` が input jar 側の Guava に依存することになって、[『library class ... depends on program class ...』 の警告](http://proguard.sourceforge.net/manual/troubleshooting.html#dependency)が発生するのだと思う。

# 対応

## とりあえずの対応

`com.android.databinding:compiler:2.0.0` はビルド時のみに使われるものなので、単に警告を無視してやれば良さそう。 うちのプロジェクトでは以下のような記述を proguard-rules.pro に追加した。

```
# Data Binding library
# ====================
# * Data Binding ライブラリを有効にすると、ビルド時に使われる
#   (`com.android.databinding:compiler:2.0.0`) が `provided` configuration に追加される。
# * さらに `provided` configuration の依存が ProGuard の library jars に追加されるっぽい。
# * `com.android.databinding:compiler:2.0.0` は `com.google.guava:guava:17.0` などに依存して
#   いるが、それらのライブラリのより新しいバージョンが `compile` configuration にも含まれて
#   いると、ProGuard の処理時に 「library class ... depends on program class ...」 という
#   ような警告が発生してビルドが止まってしまうっぽい。

-dontwarn android.databinding.tool.util.**
```

## 根本的には？

根本的には、以下のどちらかが必要そう？

* Data Binding ライブラリのビルド時用のツールを `provided` configuration の依存に含めない。
* `provided` configuration の依存を ProGuard の library jar に含めない。

`provided` configuration がどういう目的のものかによって上記のどちらがいいかが違ってくると思うけど、本来の `provided` configuration というのは 「実行環境により提供されるのでプログラム側には含めなくていいけどコンパイル時に参照する必要があるもの」 を含めるところだと思うので、それだとすると前者の対応ができるといいのかなぁと思う。