d8

d8 は、プロジェクトの Java バイトコードを Android デバイスで動作する DEX バイトコードにコンパイルするために、Android Studio と Android Gradle プラグインで使用するコマンドライン ツールです。d8 を使用すると、アプリのコードで Java 8 言語機能を使用できます。

また、d8 は、Android Build Tools 28.0.1 以降にスタンドアロン ツールとして組み込まれています(android_sdk/build-tools/version/)。

一般的な使用方法

d8 の必須のパラメータは、DEX バイトコードに変換するコンパイル済み Java バイトコードのパスだけです。次に例を示します。

d8 MyProject/app/build/intermediates/classes/debug/*/*.class

入力バイトコードは、任意の組み合わせの *.class ファイルまたはコンテナ(JAR ファイル、APK ファイル、ZIP ファイルなど)に含めることができます。また、DEX 出力にマージする d8 用の DEX ファイルを含めることもできます。これは、増分ビルドからの出力を追加する際に役立ちます。

デフォルトでは、d8 は Java バイトコードを最適化された DEX ファイルにコンパイルし、実行時のコードのデバッグに使用できるデバッグ情報を追加します。ただし、オプションのフラグを追加して、増分ビルドを実行したり、メイン DEX ファイルにコンパイルする必要があるクラスを指定したり、Java 8 言語機能を使用するために必要な追加リソースのパスを指定したりすることもできます。

d8 path-to-input-files [options]

d8 で使用できるオプションのフラグを次の表に示します。

オプション 説明
--debug

DEX バイトコードをコンパイルして、デバッグ シンボル テーブルなどのデバッグ情報を追加します。

このオプションはデフォルトで有効になっています。DEX バイトコード内にデバッグ情報を含めるため、d8 では、入力 Java バイトコードにその情報が含まれていると想定されます。たとえば、javac を使用してコードをコンパイルする場合は、-g フラグを渡して、出力 Java バイトコードにデバッグ情報を含める必要があります。

アプリまたはライブラリのリリース バージョン用に DEX ファイルをコンパイルする場合は、代わりに --release フラグを使用します。

--release

デバッグ情報なしで DEX バイトコードをコンパイルします。ただし、d8 は、スタック トレースの生成と例外のロギングの際に使用される情報を追加します。

公開リリース用にバイトコードをコンパイルするときは、このフラグを渡してください。

--output path

必要に応じて DEX 出力のパスを指定します。デフォルトでは、d8 は、現在の作業ディレクトリに DEX ファイルを出力します。

ZIP ファイルまたは JAR ファイルのパスと名前を指定すると、d8 は指定されたファイルを作成して、出力 DEX ファイルをそれに含めます。既存のディレクトリのパスを指定すると、d8 はそのディレクトリに DEX ファイルを出力します。

--lib android_sdk/platforms/api-level/android.jar Android SDK の android.jar のパスを指定します。 このフラグは、Java 8 言語機能を使用するバイトコードをコンパイルする際に必要です。
--classpath path d8 がプロジェクトの DEX ファイルをコンパイルするために必要とする可能性のあるクラスパス リソースを指定します。d8 は、Java 8 言語機能を使用するバイトコードをコンパイルする際に、特定のリソースの指定を必要とします。
--min-api number 出力 DEX ファイルがサポートする最小 API レベルを指定します。
--intermediate このフラグを渡すと、コンパイル対象がプロジェクトの Java バイトコードの完全なセットではないことを d8 に知らせることができます。このフラグは、増分ビルドを実行する際に有用です。d8 は、デバイスで実行されることを想定した最適化済みの DEX ファイルをコンパイルするのではなく、中間 DEX ファイルを作成して、指定された出力またはデフォルトパスに格納します。

デバイスで実行されることを想定した DEX ファイルをコンパイルする場合は、このフラグを渡さずに、中間 DEX クラスのパスを入力として指定します。

--file-per-class

各クラスを個別の DEX ファイルにコンパイルします。

このフラグを有効にすると、変更されたクラスのみを再コンパイルすることで、より多くの増分ビルドを実行できます。Android Gradle プラグインを使用して増分ビルドを実行する場合、この最適化はデフォルトで有効になっています。

--main-dex-list を指定する場合、このフラグは使用できません。

--no-desugaring Java 8 言語機能を無効にします。このフラグは、Java 8 言語機能を使用する Java バイトコードをコンパイルする予定がない場合にのみ使用します。
--main-dex-list path

d8 でメイン DEX ファイルに含める必要があるクラスをリストしたテキスト ファイルを指定します。通常、このファイルは classes.dex という名前にします。このフラグでクラスのリストを指定しない限り、d8 によりどのクラスがメイン DEX ファイルに含められるかは保証されません。

Android システムはアプリの起動時にメイン DEX ファイルを最初に読み込むので、このフラグを使用して、特定のクラスをメイン DEX ファイルにコンパイルすることで、起動時にそれらのクラスの優先順位を高めることができます。これは、特に古い Multidex をサポートする場合に有用です。古い Multidex ライブラリが読み込まれるまでは、実行時にメイン DEX ファイル内のクラスだけが利用可能になるからです。

各 DEX ファイルは 64K 参照制限を満たす必要があることに留意してください。そのため、メイン DEX ファイルに対して、あまりに多くのクラスを指定しないように注意してください。コンパイル エラーが発生します。デフォルトでは、--main-dex-list を使用してクラスを指定した場合、指定したクラスだけが d8 によりメイン DEX ファイル内に格納されます。これにより、メイン DEX ファイル内にないクラスに関する問題をデバッグしやすくなります。--release モードを指定した場合、d8 は、64K 制限の範囲内でその他のクラスを可能な限り多くメイン DEX ファイルに含めることで、アプリのリリース バージョンにパッケージ化される DEX ファイルの数を減らそうとします。

--file-per-class を指定する場合、このフラグは使用できません。

--pg-map file 配布用のマッピング ファイルとして file を使用します。
--file-per-class-file

.class 入力ファイルごとに個別の DEX ファイルを生成します。

合成クラスを元のクラスとともに保持します。

--desugared-lib file

脱糖ライブラリ構成を指定します。

file は、JSON 形式の脱糖ライブラリ構成ファイルです。

--main-dex-rules file ProGuard keep-rules を指定して、プライマリ DEX ファイルに配置するクラスを保護します。
--main-dex-list-output file 生成されたメイン DEX リストを file に出力します。

--force-enable-assertions [:class_or_package_name...]

--force-ea [:class_or_package_name...]

javac によって生成されたアサーション コードを強制的に有効にします。

--force-disable-assertions [:class_or_package_name...]

--force-da [:class_or_package_name...]

javac によって生成されたアサーション コードを強制的に無効にします。これは、DEX ファイルを生成する際に javac アサーション コードに対して行われるデフォルト処理です。

--force-passthrough-assertions [:class_or_package_name...]

--force-pa [:class_or_package_name...]

javac によって生成されたアサーション コードを変更しないようにします。これは、class ファイルを生成する際に javac アサーション コードに対して行われるデフォルト処理です。

--force-assertions-handler:handler method [:class_or_package_name...]

--force-ah:handler method [:class_or_package_name...]

javac および kotlinc によって生成されたアサーション コードを変更し、アサーション エラーをスローするのではなく、アサーション エラーごとにメソッド handler method を呼び出すようにします。handler method は、クラス名、ドット、メソッド名の順で指定します。ハンドラ メソッドは、java.lang.Throwable 型の単一の引数を取り、戻り値の型が void でなければなりません。
--thread-count number of threads コンパイルに使用するスレッドの数を指定します。指定しなかった場合は、コア数を考慮したヒューリスティックに基づいてスレッド数が決定されます。
--map-diagnostics[ :type] from-level to-level from-level として報告された type(デフォルトでは任意)の診断を to-level にマッピングします。from-levelto-level は「info」、「warning」、「error」のいずれかで、オプションの type は単純なまたは完全修飾された診断の Java 型名です。type を指定しなかった場合は、from-level のすべての診断がマッピングされます。 致命的なコンパイラ エラーはマッピングできないことにご注意ください。
--version 現在使用している d8 のバージョンを出力します。
--help d8 の使用方法のヘルプテキストを出力します。

増分ビルドを実行する

継続的インテグレーション ビルドなどの開発でビルド速度を向上させるために、プロジェクトの Java バイトコードのサブセットのみをコンパイルするよう d8 に指示できます。たとえば、クラス単位の dex 変換を有効にしている場合は、前回のビルド以降に変更されたクラスのみを再コンパイルできます。

次のコマンドは、いくつかのクラスの増分ビルドを実行し、クラス単位の dex 変換を有効にします。増分ビルドの出力ディレクトリも指定しています。

d8 MainActivity.class R.class --intermediate --file-per-class --output ~/build/intermediate/dex

d8 は、増分ビルドを実行する際に、追加情報を DEX 出力に格納します。d8 は、後でアプリをフルビルドする際にこの情報を使用して、--main-dex-list オプションを正しく処理し、DEX ファイルをマージします。

たとえば、d8 は、Java 8 のラムダクラスを処理する際に、入力クラスごとに作成されたラムダクラスをトラッキングします。フルビルドでは、d8 はクラスをメイン DEX ファイルに含める際にメタデータを参照し、そのクラス用に作成されたすべてのラムダクラスをメイン DEX ファイルに含めます。

複数回の増分ビルドによってプロジェクトのすべてのバイトコードを DEX ファイルにコンパイルした場合は、次のコマンドに示すように、中間 DEX ファイルのディレクトリを d8 に渡すことによってフルビルドを実行できます。さらに、--main-dex-list を使用して、d8 でメイン DEX ファイルにコンパイルしたいクラスを指定できます。DEX バイトコードにすでにコンパイルされたファイルのセットを入力に使用しているので、このビルドはクリーンビルドより速く完了するはずです。

d8 ~/build/intermediate/dex --release --main-dex-list ~/build/classes.txt --output ~/build/release/dex

Java 8 言語機能を使用するバイトコードをコンパイルする

d8 により、「脱糖」と呼ばれるコンパイル プロセスにより、コード内で Java 8 言語機能を使用できます。desugar は、このような便利な言語機能を、Android プラットフォームで実行できるバイトコードに変換します。

Android Studio と Android Gradle プラグインには、d8 で脱糖を有効にするために必要なクラスパス リソースが含まれています。ただし、コマンドラインから d8 を使用する場合は、手動でクラスパス リソースを含める必要があります。

そのようなリソースの一つが、ターゲット Android SDK の android.jar です。このリソースには、Android プラットフォーム API のセットが含まれています。--lib フラグを使用してパスを指定します。

別のリソースの例は、プロジェクトにコンパイルされた Java バイトコードのセット(現在 DEX バイトコードにコンパイルしておらず、他のクラスを DEX バイトコードにコンパイルする必要があるもの)です。

たとえば、Java 8 言語機能であるデフォルトおよび静的インターフェース メソッドを使用するコードの場合、プロジェクトのすべてのバイトコードを DEX バイトコードにコンパイルする予定がなくても、このフラグを使用してプロジェクトのすべての Java バイトコードのパスを指定する必要があります。これは、d8 がプロジェクトのコードを理解し、インターフェース メソッドの呼び出しを解決するために、この情報を必要とするからです。

次のサンプルコードの場合、デフォルト インターフェース メソッドにアクセスするクラスの増分ビルドを実行します。

d8 MainActivity.class --intermediate --file-per-class --output ~/build/intermediate/dex
--lib android_sdk/platforms/api-level/android.jar
--classpath ~/build/javac/debug