Androidでdesugar関連のビルドエラーが出たらdesugarをデバッグすればいいよ


先日、Google Play servicesを11.6.2から11.8.0に上げたら以下のエラーが出ました。

```
Exception in thread "main" java.lang.IllegalArgumentException
  at com.google.common.base.Preconditions.checkArgument(Preconditions.java:121)
  at com.google.devtools.build.android.desugar.DefaultMethodClassFixer$DefaultMethodFinder.visit(DefaultMethodClassFixer.java:535)
  at org.objectweb.asm.ClassReader.accept(ClassReader.java:621)
  at org.objectweb.asm.ClassReader.accept(ClassReader.java:500)
  at com.google.devtools.build.android.desugar.DefaultMethodClassFixer.defaultMethodsDefined(DefaultMethodClassFixer.java:388)
  at com.google.devtools.build.android.desugar.DefaultMethodClassFixer.visitEnd(DefaultMethodClassFixer.java:97)
  at org.objectweb.asm.ClassVisitor.visitEnd(ClassVisitor.java:339)
  at com.google.devtools.build.android.desugar.InterfaceDesugaring.visitEnd(InterfaceDesugaring.java:116)
  at org.objectweb.asm.ClassReader.accept(ClassReader.java:702)
  at org.objectweb.asm.ClassReader.accept(ClassReader.java:500)
  at com.google.devtools.build.android.desugar.Desugar.desugarClassesInInput(Desugar.java:515)
  at com.google.devtools.build.android.desugar.Desugar.desugarOneInput(Desugar.java:393)
  at com.google.devtools.build.android.desugar.Desugar.desugar(Desugar.java:336)
  at com.google.devtools.build.android.desugar.Desugar.main(Desugar.java:816)
```

Google先生に聞いてもこれだけの情報だとわかりませんでした。
そんな時は、bazelを使ってDesugarの環境を作りましょう。

ちなみにdesugarとは簡単に言うと「javacコンパイラの出力した```.class```をさらにバイトコード変換をするツール」です。
https://developer.android.com/studio/write/java8-support.html?hl=ja

bazelとは、googleが開発しているmakeに変わるビルドツールです。iosやandroidアプリのビルドも可能です。

# Bazel

インストールします。JDK8が必要なので先にインストールしてください。
その後、homebrewでインストールします。
それ以外の環境は[こちら](https://docs.bazel.build/versions/master/install.html)を参照ください。

```
$ brew install bazel
```

# Desugar

次にソースを取得します。

[Bazelのサイト](https://github.com/bazelbuild/bazel)からcloneします。

```
$ git clone git@github.com:bazelbuild/bazel.git
```

このソースのルートディレクトリで以下のコマンドを叩きます。

```
$ bazel build //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar
```

次にビルドエラー時に表示されているコマンドを書きます。
Desugarのビルドエラーの場合は、エラーメッセージ内にコマンドが記述されているはずです。
自分の場合は以下を入力しました。(以下は長いので省略しています。)

```
$ bazel-bin/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar --verbose \
--input /Users/ユーザ名/アプリまでのパス/app/build/intermediates/transforms/stackFramesFixer/beta/44.jar \
--output /Users/ユーザ名/アプリまでのパス/app/build/intermediates/transforms/desugar/beta/52.jar \
・・・
--bootclasspath_entry /Applications/Android\ Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/charsets.jar \
--min_sdk_version 19 \
--desugar_try_with_resources_omit_runtime_classes \
--desugar_try_with_resources_if_needed \
--desugar_try_with_resources_omit_runtime_classes
```

このコマンドを実行するとAndroid Studioで出たのと同じようにjava.lang.IllegalArgumentExceptionが出ると思います。

# デバッグ

cloneしたbazel/src以下にDesugar.javaがあります。

```
▾ src/
  ▸ conditions/
  ▸ java_tools/
  ▸ main/
  ▸ objc_tools/
  ▸ test/
  ▾ tools/
    ▾ android/
      ▾ java/
        ▾ com/
          ▾ google/
            ▾ devtools/
              ▾ build/
                ▾ android/
                  ▾ desugar/
                  Desugar.java
```

これにLogを書けば色々わかります。

今回は、エラーメッセージの```at com.google.devtools.build.android.desugar.Desugar.desugarClassesInInput(Desugar.java:515)```にある以下の部分にログを仕込みました。

```
if (inputFilename.endsWith(".class")) {
    System.out.println("----------------------------------------------");
    System.out.println(inputFilename);
```

これでどのクラスでエラーが起きているのかがわかります。

再度、コマンドを実行すると以下のクラスがないことが問題だったことがわかります。

```
com/google/android/gms/internal/zzcec.class
```

このクラスは,```play-service-location```のクラスのものでした。

以下コマンドで依存しているライブラリを見るとOneSignalに依存しているplay-services-locationが11.6.2のままでした。

```
$ ./gradlew :app:dependencies
+--- com.onesignal:OneSignal:3.8.1
|    +--- com.google.android.gms:play-services-location:[11.6.2) 
```

これを11.8.0が使われるようにbuild.gradle明示的に指定して解決しました。

```
implementation "com.google.android.gms:play-services-location:11.8.0"
```