d8

d8 là một công cụ dòng lệnh được Android Studio và trình bổ trợ Android cho Gradle sử dụng để biên dịch mã byte Java của dự án thành mã byte DEX chạy trên các thiết bị Android. d8 cho phép bạn sử dụng các tính năng ngôn ngữ Java 8 trong mã ứng dụng.

d8 cũng được đưa vào dưới dạng một công cụ độc lập trong Công cụ xây dựng Android 28.0.1 trở lên: android_sdk/build-tools/version/.

Cách sử dụng chung

d8 chỉ yêu cầu một đường dẫn tới mã byte Java được biên dịch mà bạn muốn chuyển đổi thành mã byte DEX. Ví dụ:

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

Mã byte đầu vào có thể là sự kết hợp bất kỳ của các tệp hoặc vùng chứa *.class, chẳng hạn như tệp JAR, APK hoặc ZIP. Bạn cũng có thể đưa tệp DEX vào d8 để hợp nhất các tệp đó vào dữ liệu đầu ra DEX. Điều này rất hữu ích khi đưa vào dữ liệu đầu ra của một bản dựng tăng dần (incremental build).

Theo mặc định, d8 sẽ biên dịch mã byte Java thành các tệp DEX được tối ưu hoá và đưa vào thông tin gỡ lỗi mà bạn có thể dùng để gỡ lỗi cho mã trong thời gian chạy. Tuy nhiên, bạn có thể đưa vào các cờ tuỳ chọn để tạo bản dựng tăng dần, chỉ định các lớp cần được biên dịch trong tệp DEX chính và chỉ định đường dẫn đến các tài nguyên bổ sung cần thiết để sử dụng các tính năng của ngôn ngữ Java 8.

d8 path-to-input-files [options]

Bảng sau đây mô tả các cờ tuỳ chọn bạn có thể sử dụng với d8:

Tuỳ chọn Nội dung mô tả
--debug

Biên dịch mã byte DEX để đưa vào thông tin gỡ lỗi, chẳng hạn như bảng ký hiệu gỡ lỗi.

Tuỳ chọn này được bật theo mặc định. Để bao gồm thông tin gỡ lỗi trong mã byte DEX, d8 dự kiến rằng mã byte Java đầu vào sẽ bao gồm thông tin đó. Ví dụ: nếu đang sử dụng javac để biên dịch mã, bạn cần chuyển sang cờ -g này để đưa thông tin gỡ lỗi vào mã byte Java đầu ra.

Khi biên dịch tệp DEX cho phiên bản phát hành của ứng dụng hoặc thư viện, hãy sử dụng cờ --release.

--release

Biên dịch mã byte DEX mà không cần thông tin gỡ lỗi. Tuy nhiên, d8 có chứa một số thông tin được dùng khi tạo dấu vết ngăn xếp (stacktrace) và ngoại lệ ghi nhật ký.

Chuyển cờ này khi biên dịch mã byte cho một bản phát hành công khai.

--output path

Chỉ định đường dẫn mong muốn cho dữ liệu đầu ra DEX. Theo mặc định, d8 sẽ xuất ra (các) tệp DEX trong thư mục đang hoạt động.

Nếu bạn chỉ định một đường dẫn và tên của tệp ZIP hoặc JAR, d8 sẽ tạo tệp được chỉ định và đưa vào các tệp DEX đầu ra. Nếu bạn chỉ định đường dẫn đến một thư mục hiện có, thì d8 sẽ xuất ra các tệp DEX trong thư mục đó.

--lib android_sdk/platforms/api-level/android.jar Chỉ định đường dẫn đến android.jar của SDK Android. Cờ này là bắt buộc khi biên dịch mã byte có sử dụng các tính năng của ngôn ngữ Java 8.
--classpath path Chỉ định tài nguyên đường dẫn lớp (classpath resources) theo yêu cầu của d8 để biên dịch các tệp DEX của dự án. Đặc biệt, d8 sẽ yêu cầu bạn chỉ định một số tài nguyên khi biên dịch mã byte có sử dụng các tính năng của ngôn ngữ Java 8.
--min-api number Chỉ định cấp độ API tối thiểu mà bạn muốn các tệp DEX đầu ra hỗ trợ.
--intermediate Chuyển cờ này để d8 biết rằng bạn không biên dịch toàn bộ mã byte Java của dự án. Cờ này rất hữu ích khi thực hiện các bản dựng tăng dần. Thay vì biên dịch các tệp DEX được tối ưu hoá mà bạn mong muốn chạy trên một thiết bị, d8 sẽ tạo các tệp DEX trung gian và lưu trữ các tệp đó trong đường dẫn mặc định hoặc đầu ra được chỉ định.

Nếu muốn biên dịch tệp DEX mà bạn định chạy trên một thiết bị nào đó, hãy xoá cờ này và chỉ định đường dẫn đến lớp DEX trung gian dưới dạng dữ liệu đầu vào.

--file-per-class

Biên dịch mỗi lớp thành các tệp DEX riêng biệt.

Việc bật cờ này cho phép bạn tạo nhiều bản dựng tăng dần hơn bằng cách chỉ biên dịch lại các lớp đã thay đổi. Khi tạo các bản dựng tăng dần bằng trình bổ trợ Android cho Gradle, tính năng tối ưu hoá này sẽ được bật theo mặc định.

Bạn không thể sử dụng cờ này khi đồng thời chỉ định --main-dex-list.

--no-desugaring Tắt các tính năng của ngôn ngữ Java 8. Chỉ dùng cờ này nếu bạn không có ý định biên dịch mã byte Java mà sử dụng các tính năng của ngôn ngữ Java 8.
--main-dex-list path

Chỉ định tệp văn bản liệt kê các lớp d8 cần có trong tệp DEX chính, thường có tên là classes.dex. Khi bạn không chỉ định danh sách các lớp bằng cờ này, d8 không đảm bảo lớp nào sẽ được đưa vào tệp DEX chính.

Do hệ thống Android sẽ tải tệp DEX chính trước khi khởi động ứng dụng, nên bạn có thể dùng cờ này để ưu tiên một số lớp khi khởi động bằng cách biên dịch các lớp đó thành tệp DEX chính. Cách này đặc biệt hữu ích khi hỗ trợ các chế độ multidex cũ vì chỉ có các lớp trong tệp DEX chính mới có sẵn trong thời gian chạy cho đến khi thư viện multidex cũ được tải.

Lưu ý rằng mỗi tệp DEX vẫn phải đáp ứng giới hạn tham chiếu 64K. Vì vậy, đừng chỉ định quá nhiều lớp cho tệp DEX chính, nếu không bạn sẽ gặp lỗi biên dịch. Theo mặc định, khi chỉ định các lớp bằng --main-dex-list, d8 chỉ đưa các lớp đó vào tệp DEX chính. Việc này giúp các sự cố liên quan đến các lớp bị thiếu trong tệp DEX chính dễ gỡ lỗi hơn. Nếu chỉ định chế độ --release, d8 sẽ cố gắng giảm số lượng tệp DEX được đóng gói vào phiên bản phát hành của ứng dụng bằng cách đưa càng nhiều lớp khác vào tệp DEX chính càng tốt, cho đến khi đạt giới hạn tham chiếu 64K.

Bạn không thể sử dụng cờ này khi đồng thời chỉ định --file-per-class.

--pg-map file Sử dụng file làm tệp ánh xạ để phân phối.
--file-per-class-file

Tạo một tệp DEX riêng cho mỗi tệp .class đầu vào.

Giữ các lớp tổng hợp bằng lớp gốc.

--desugared-lib file

Chỉ định cấu hình thư viện được đơn giản hoá.

file là tệp cấu hình thư viện được đơn giản hoá ở định dạng JSON.

--main-dex-rules file Quy tắc giữ Proguard để các lớp đặt trong tệp DEX chính.
--pg-map file Sử dụng file làm tệp ánh xạ để phân phối.
--main-dex-list-output file Xuất ra danh sách kết quả DEX chính trong tệp.

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

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

Buộc bật mã xác nhận do javac tạo.

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

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

Buộc tắt mã xác nhận do javac tạo. Đây là cách xử lý mặc định của mã xác nhận javac khi tạo tệp DEX.

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

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

Đừng thay đổi mã xác nhận do javac tạo. Đây là cách xử lý mặc định cho mã xác nhận javac khi tạo tệp class.

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

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

Thay đổi mã xác nhận do javackotlinc tạo để gọi phương thức handler method với từng lỗi xác nhận thay vì gửi. handler method được chỉ định làm tên lớp, theo sau là dấu chấm và tên phương thức. Phương thức của trình xử lý phải nhận một đối số duy nhất thuộc loại java.lang.Throwable và có loại dữ liệu trả về void.
--thread-count number of threads Chỉ định số lượng luồng cần sử dụng để biên dịch. Nếu bạn không chỉ định, số này sẽ dựa trên phương pháp phỏng đoán, sau khi xem xét số lượng lõi.
--map-diagnostics[ :type] from-level to-level Ánh xạ thông tin chẩn đoán của type (bất kỳ mặc định) được báo cáo là from-level đến to-level, trong đó from-levelto-level là một trong các giá trị như "info" (thông tin), "warning" (cảnh báo) hoặc "error" (lỗi) và type không bắt buộc là tên loại Java đơn giản hoặc đủ điều kiện của một thông tin chẩn đoán. Nếu chưa chỉ định type, tất cả các thông tin chẩn đoán tại from-level sẽ được ánh xạ. Xin lưu ý rằng không thể ánh xạ các lỗi nghiêm trọng về trình biên dịch.
--version In phiên bản d8 mà bạn đang sử dụng.
--help In văn bản trợ giúp để dùng d8.

Tạo các bản dựng tăng dần

Để cải thiện tốc độ bản dựng trong quá trình phát triển, chẳng hạn như cho bản dựng tích hợp liên tục, bạn có thể hướng dẫn để d8 chỉ biên dịch một tập hợp con của mã byte Java trong dự án. Ví dụ: nếu bật tính năng tạo tệp dex cho mỗi lớp, bạn chỉ có thể biên dịch lại các lớp mình đã sửa đổi kể từ phiên bản trước.

Lệnh sau đây sẽ tạo một bản dựng tăng dần của một vài lớp và bật tính năng tạo tệp dex cho mỗi lớp. Lệnh này cũng chỉ định một thư mục đầu ra cho bản dựng tăng dần đó.

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

Khi tạo một bản dựng tăng dần, d8 sẽ lưu trữ thêm thông tin trong dữ liệu đầu ra DEX. Sau đó, d8 sử dụng thông tin đó để xử lý chính xác tuỳ chọn --main-dex-list và hợp nhất các tệp DEX trong một bản dựng đầy đủ của ứng dụng.

Ví dụ: khi xử lý các lớp lambda của Java 8, d8 theo dõi xem lớp lambda nào được tạo cho mỗi lớp đầu vào. Trong quá trình tạo bản dựng đầy đủ, khi đưa một lớp vào trong tệp DEX chính, d8 sẽ tham khảo siêu dữ liệu để đảm bảo tất cả lớp lambda đã tạo cho lớp đó cũng được đưa vào tệp DEX chính.

Nếu bạn đã biên dịch tất cả mã byte của dự án thành các tệp DEX trên nhiều bản dựng tăng dần, hãy tạo một bản dựng đầy đủ bằng cách truyền thư mục của các tệp DEX trung gian cho d8, như thể hiện trong lệnh sau. Ngoài ra, bạn có thể chỉ định các lớp bạn muốn d8 biên dịch thành tệp DEX chính bằng cách sử dụng --main-dex-list. Vì đầu vào là một tập hợp các tệp đã được biên dịch thành mã byte DEX, bản dựng này sẽ hoàn thành nhanh hơn một bản dựng sạch.

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

Biên dịch mã byte sử dụng các tính năng của ngôn ngữ Java 8

d8 cho phép bạn sử dụng các tính năng của ngôn ngữ Java 8 trong mã của mình thông qua một quy trình biên dịch có tên là đơn giản hoá (desugaring). Quy trình này sẽ chuyển đổi các tính năng ngôn ngữ hữu ích này thành mã byte có thể chạy trên nền tảng Android.

Android Studio và trình bổ trợ Android cho Gradle sẽ thêm các tài nguyên classpath (đường dẫn lớp) theo yêu cầu của d8 để bật tính năng đơn giản hoá này. Tuy nhiên, khi sử dụng d8 bằng dòng lệnh, bạn phải tự thêm các tài nguyên đó.

Một trong những tài nguyên như vậy là android.jar trong SDK Android đích. Tài nguyên này bao gồm một nhóm API trên nền tảng Android. Hãy chỉ định đường dẫn của API đó bằng cách sử dụng cờ --lib.

Một tài nguyên khác là nhóm mã byte Java được biên dịch trong dự án của bạn nhưng hiện tại chưa được biên dịch thành mã byte DEX, được dùng để biên dịch các lớp khác thành mã byte DEX.

Ví dụ: nếu mã của bạn sử dụng các phương thức giao diện mặc định và giao diện tĩnh (đây là một tính năng của ngôn ngữ Java 8), thì bạn cần sử dụng cờ này để chỉ định đường dẫn đến tất cả mã byte Java của dự án, ngay cả khi bạn không có ý định biên dịch tất cả mã đó thành mã byte DEX. Đó là do d8 cần thông tin này để hiểu mã của dự án và phân giải các lệnh gọi đến các phương thức giao diện này.

Mã mẫu sau đây sẽ tạo một bản dựng tăng dần của một lớp có truy cập đến phương thức giao diện mặc định:

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