d8

d8 是 Android Studio 和 Android Gradle 外掛程式的指令列工具,可將專案的 Java 位元碼編譯為在 Android 裝置上執行的 DEX 位元碼,而且可讓您在應用程式的程式碼中使用 Java 8 語言功能。

d8 也包含在 Android Build Tools 28.0.1 以上版本的獨立工具中:android_sdk/build-tools/version/

一般使用情況

d8 使用相當簡單,您只需要將要編譯的 Java 位元碼路徑轉換為 DEX 位元碼 (如下所示),

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

輸入的位元碼可以是 *.class 檔案或容器的任意組合,例如 JAR、APK 或 ZIP 檔案。您也可以加入 d8 的 DEX 檔案,將這些檔案合併到 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 傳遞這個旗標,讓 d8 知道您並未編譯完整的專案 Java 位元碼。這個旗標對執行漸進式建構作業時相當實用,而不是編譯在裝置上執行的最佳化 DEX 檔案,d8 會建立中繼 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 檔案中納入 _only_ 這些類別,藉此使主要 DEX 檔案中缺少類別的問題更易於偵錯。如果指定 --release 模式,d8 會嘗試在主要 DEX 檔案中包含盡可能多的其他類別,以減少封裝到應用程式的發布版本中的 DEX 檔案數量,直到達到 64K 的上限為止。

指定 --file-per-class 時,無法使用此旗標。

--version 列印目前使用的 d8 版本。
--help 列印使用 d8 的說明文字

執行漸進式建構作業

如要改善開發期間的建構速度 (例如進行持續整合建構作業),請指示 d8 只編譯專案 Java 位元碼的的部分。例如,如果您啟用每個類別的 dex,即可僅重新編譯自上次建構之後已修改的類別。

下列指令會執行幾個類別的漸進式建構,並啟用每個類別的內容排除功能。這個指令也會指定漸進式建構作業的輸出目錄。

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

d8 執行漸進式建構作業時,會在 DEX 輸出中儲存其他資訊,之後用於在應用程式的完整構建期間正確處理 --main-dex-list 選項並合併 DEX 檔案。例如,在處理 Java 8 lambda 類別時,d8 會記錄為每個輸入類別創建了哪些 lambda 類別。在完整建構作業中,當 d8 在主要 DEX 檔案中納入類別時,系統會查詢中繼資料,以確保為該類別建立的所有 lambda 類別也都已納入主 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 可讓您透過名為 Deugaring 的編譯程式,在您的程式碼中使用 Java 8 語言功能,這些實用的語言功能會轉換為位元碼,可在 Android 平台上執行。

Android Studio 和 Android Gradle 外掛程式包含 d8,為您啟用 Desugaring 所需的類別路徑資源。不過,透過指令列使用 d8 時,您必須自行加入。

這類資源是目標 Android SDK 的 android.jar。這項資源含有一組 Android 平台 API,而您使用 --lib 旗標來指定路徑。

另一項資源是專案的已編譯 Java 位元碼組合,但您目前並未編譯 DEX 位元碼,但需要將其他類別編譯成 DEX 位元碼。例如,如果您的程式碼使用預設和靜態介面方法 (即 Java 8 語言功能),您必須使用此標記來指定所有專案的 Java 位元碼 (即使您不打算將所有程式碼編譯成 DEX 位元碼)。這是因為 d8 需要這些資訊瞭解專案程式碼,並解析介面方法的呼叫。

下列程式碼範例會針對可存取預設介面方法的類別,執行漸進式建構作業:

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