Androidのメソッド数が65k(65536)を超えた場合にビルドができなくなる問題の対処法

# 概要
Androidはアプリ内で定義しているメソッド数(依存ライブラリも含む)が65536を超えると、ビルドできなくなる問題がある。

例えばGradleでビルドしていた場合はこういった表示が出るはず。

```
Unable to execute dex: method ID not in [0, 0xffff]: 65536
```

主にこういった状況は大規模なライブラリ(GuavaやApache Commons等)利用した時に起こるので、業務アプリのような比較的大規模な開発では悩まされた人も多いのではないだろうか。

今回はその問題についての説明と、対処法について紹介する。

# この問題について
そもそもなぜこの問題が起きるのか。
この問題の根本的な原因についてはgfxさんの記事が参考になる

- **DalvikバイトコードのMethod数65k制限について**
 - http://d.hatena.ne.jp/gfx/20140704/1404431315

> つまり、アプリケーションで定義したメソッド数が65kを超えるかどうかではなく、ひとつのdex fileで参照しているメソッド数が65kを超えるときに問題が起きる

dexは簡単に言うと、コンパイルされたjavaクラスコードをAndroid上の仮想環境であるDalvikで解釈できるように変換したファイルを指す。

> http://ja.wikipedia.org/wiki/Dalvik%E4%BB%AE%E6%83%B3%E3%83%9E%E3%82%B7%E3%83%B3

ここらへんの用語を出して概要をややこしくしたくなかったので、あえて「アプリ内で定義されたメソッド数」と言っているが、正確には**dex fileで参照しているメソッド数の上限が65536**であり、この後紹介する対処法はこのdex fileのメソッド数をどうやりくりするかといった内容になる。

# この問題の対処方法
この問題に対処するためには主に二つの方法がある

1. Proguardを利用する
2. Multiple Dex Fileを作る

## Proguardを利用する
ProguardはAndroidアプリのコードを難読化・未使用コードの削除をしてくれる。
つまりこの対処法は未使用コードの削除をする事で65536の制限を回避する方法である。

未使用メソッドを削除しても65536の制限を超える場合はこの方法は使えない。(滅多にないと思うけど)

Proguardの使い方は検索すると色々出てくるのでそれを参考に設定ファイルを書いてみると良いかも。

## Multiple Dex Filesを作る
「一つのdex fileに65536しか参照できないならファイルを増やせばいいじゃない」的な解決方法
### 一昔前
一昔前の方法だと手動で作るやり方があった。
僕が最初にこの問題に悩まされていた時に検索した時は、Multiple Dex Filesを作る方法がこの方法くらいしか載ってなかった。

こういうやり方で作れるのねーって感じで一応紹介

> http://android-developers.blogspot.co.il/2011/07/custom-class-loading-in-dalvik.html

### 最近
いつの間にかにAndroidのサイトにこの問題に関するページができてた。

> http://developer.android.com/tools/building/multidex.html

これによってAndroid Gradle Pluginでビルドしているプロジェクトであれば、defaultConfigにパラメータを追加してちょっとコードをいじれば簡単にMultiple Dex Filesのビルドができるようになった！

今回はその作業手順も紹介する

#### 導入手順
- Android StudioのバージョンをCanary Channelでアップデートする(記事執筆当時1.0-RC)
- android-gradle-pluginのバージョンを`0.14.2`にする
- ビルドに利用しているGradleは2.1以上にする(僕は2.2で試した)
- defaultConfigに`multiDexEnabled true`を追加する

```groovy:build.gradle
android {
    defaultConfig {
        ...
        multiDexEnabled true
    }
    ...
}
```

- dependenciesにMultiDexビルド用のライブラリを追加する

```groovy:build.gradle
dependencies {
  compile 'com.android.support:multidex:1.0.0'
}
```

- AndroidManifest.xmlにMultiDexビルド用のApplicationクラスを指定する

```xml:AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.multidex.myapplication">
    <application
        ...
        android:name="android.support.multidex.MultiDexApplication">
        <!-- 独自Application使いたい場合は独自ApplicationクラスをMultiDexApplicationから派生させるようにする -->
        ...
    </application>
</manifest>
```

- あとは普通にビルドするだけ

# それぞれの対処法のメリット・デメリット
## Proguard
### メリット
- アプリ上不要なコードを排除できるので効率が良い
- 難読化のために利用される事が多いので、難読化のついでに対応できる

### デメリット
- Proguard難しい
 - エラー出た時にパッと見Proguardのどこの設定が悪さしているのか分かりづらい(何かコツあるんだろうか)

### 補足
Proguardは未使用コードを削除・難読化するので、それによってデバッグ実行の確認がしづらいとかはありそう(申し訳ない事にProguard本格的に使った事なくて検証できてない)

## Multiple Dex Files
### メリット
- 導入が簡単

### デメリット
- アプリのファイルサイズが増える(2倍くらい)
 - 15MB → 30MB
- 不具合が起きる可能性がある
 - http://developer.android.com/tools/building/multidex.html
 - Limitations of the multidex support libraryの項目を参照

# まとめ
個人的な理想だと、Proguardで対処しつつProguardでも対処できなくなってきたらMultiple Dex Filesの方法で対応するのがいいのかなーといった感じ。

それぞれ良し悪しがあるので、機会があればここらへん色々試してみたいと思う。

# 追記 2014/11/25
Multiple Dex Filesの導入手順でAndroid Gradle Pluginのバージョンを0.14.0で記述していたが、これだとLollipop端末以下？(Galaxy Nexus 4.2で確認)にてビルドにこける問題が発生したのでバージョンを0.14.2に変更した。

一応0.14.4が最新だが、このバージョンにするとbuildTypesの`runProguard`のとこで未サポートのエラーが出たので注意。(バグなのかそれとも0.14.4からrunProguardに変わるプロパティに変更されたのかはまだ未確認)