d8

d8 是 Android Studio 和 Android Gradle 外掛程式的指令列工具,可將專案的 Java 位元碼編譯為在 Android 裝置上執行的 DEX 位元碼。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 檔案。您也可以加入 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 位元碼。在執行漸進式版本時這個標記很實用。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 會嘗試在主要 DEX 檔案中包含盡可能多的其他類別,以減少封裝到應用程式的發布版本中的 DEX 檔案數量,直到達到 64K 的上限為止。

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

--pg-map file 使用 file 做為發布的對應檔案。
--file-per-class-file

為每個輸入 .class 檔案產生獨立的 DEX 檔案。

在合成類別中保有原始類別。

--desugared-lib file

指定脫糖程序的程式庫設定。

file 是 JSON 格式的脫糖程式庫設定檔。

--main-dex-rules file Proguard 保有將類別存放在主要 DEX 檔案中的規則。
--main-dex-list-output file file 中輸出產生的主要 DEX 清單。

--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...]

變更 javackotlinc 產生的斷言程式碼,透過每個斷言錯誤叫用 handler method 方法,而不是擲回該錯誤。handler method 會指定為類別名稱,後面接著一個點和方法的名稱。這個處理常式方法必須使用一個 java.lang.Throwable 類型的引數,並且傳回類型 void
--thread-count number of threads 指定要用於編譯的執行緒數量。如未指定,該數量會以經驗法則為準,同時將核心數量納入考量。
--map-diagnostics[ :type] from-level to-level type (預設值) 的地圖診斷資料繪製為 from-levelto-level,其中 from-levelto-level 為「info」、「warning」或「error」之一,而選用的 type 則是簡易或完整的 Java 類型名稱。如果未指定 type,系統會對應 from-level 中的所有診斷資料。請注意,無法對應編譯器的嚴重錯誤。
--version 列印目前使用的 d8 版本。
--help 列印使用 d8 的說明文字。

執行漸進式建構

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

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

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

d8 執行漸進式建構作業時,會在 DEX 輸出中儲存其他資訊。d8 稍後會使用該資訊來正確處理 --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