LoginSignup
150
145

More than 5 years have passed since last update.

Multi-dex Support を使おう

Posted at

Multi-dex とは

一個の dex に含められるメソッドの総数が 65,535 なのは有名な話ですが、Google Play Services や Guava などの大きなライブラリを使うと、わりとすぐにその数字に達してしまいます。

Guava の場合、ドメインに応じて dependency をつまみ食いできるので、不要なものは dependencies に記述しなければ良いだけで済みます。
しかし、Google Play Services は All in one なライブラリのため、つまみ食いができず、ProGuard で使わないものを無理やり削ぎ落とすなどの工夫が必要です。

それでも、ライブラリへの依存が増えれば、その分だけメソッドの総数も増えていきます。どうしても 65,535 を超える場合、Multi-dex Support を使うことで、この問題に対応することができます。

その名の通り、Multi-dex Support では、1 つの apk に dex ファイルを複数持たせることで、擬似的にアプリ全体としてのメソッドの総数を 65,535 以上持つことができるようにします。
Android Lollipop ではネイティブレベルでこのサポートが入るため、特別なことは何もありませんが、それより前の OS では、Dalvik は 1 つの dex ファイルしか読みに行かないため、パッチを当てる必要があります。Multi-dex Support はそのパッチを当てる役割を果たし、これによって、API Level 4 までを Multi-dex 対応することができるようになります。

準備

Multi-dex Support 専用の jar を導入します。

/sdk/extras/android/support/multidex/library/libsandroid-support-multidex.jarがあるので、これをコピペしてきます。

次に、Application クラスを魔改造します。

Application クラスがないのであれば、MultiDexApplication クラスを AndroidManifest の<application>に指定します。
Application クラスがあって、親がApplicationであれば、MultiDexApplicationに変更するだけで済むでしょう。
何かしらの抽象Applicationクラスを継承しているのであれば、以下のように実装することで対応可能です。


public class MyApp extends HogeApplication {
  @Override
  protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    MultiDex.install(this);
  }
}

最後に、ビルドスクリプトをいじって Multi-dex を使うようにします。


android {
  dexOptions {
    preDexLibraries = false
  }
}

afterEvaluate {
  tasks.matching {
    it.name.startsWith('dex')
  }.each { dx ->
    if (dx.additionalParameters == null) {
      dx.additionalParameters = []
    }
    dx.additionalParameters += '--multi-dex'
    dx.additionalParameters += "--main-dex-list=$projectDir/multidex.keep".toString()
  }
}

multidex.keepによって、クラスローダが最初に読み込むclasses.dexに含まれてほしいものを宣言します。ほぼ決まり文句のようなものです。これを記述しないと、運悪くclasses.dexに以下の中間コードが含まれなかった場合にエラーとなります。


android/support/multidex/BuildConfig.class
android/support/multidex/MultiDex$V14.class
android/support/multidex/MultiDex$V19.class
android/support/multidex/MultiDex$V4.class
android/support/multidex/MultiDex.class
android/support/multidex/MultiDexApplication.class
android/support/multidex/MultiDexExtractor$1.class
android/support/multidex/MultiDexExtractor.class
android/support/multidex/ZipUtil$CentralDirectory.class
android/support/multidex/ZipUtil.class

この他、Application#onCreateで直接いろいろなコンポーネントの初期化を行う場合、運悪く、対象のクラスがclasses.dexに居ない時に、やはりクラスが見つからないエラーが出ます。回避策として、匿名の Runnable を用意し、Runnable#run()で初期化処理を動かす方法があります。

ビルド

いつもどおりビルドするだけです。

いいこと

65,535 を超えるメソッドを取り扱うことができるようになるので、モノリシックなライブラリも怖くないですね。

よくないこと

当然ですが、アプリケーションの起動時に見るべきファイルが増えるので、その分だけ起動に時間がかかります。
たとえば、ブロードキャスト Intent が飛んできた時にアプリのプロセスが立ち上がると、その時に複数の dex からクラスをロードしようとするので、ブロードキャストの処理が終わるまでに時間がかかります。

150
145
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
150
145