Trong quá trình phát triển Android hiện đại, việc phát hành một ứng dụng nhỏ, nhanh và an toàn là kỳ vọng cơ bản của người dùng. Công cụ chính của hệ thống tạo Android để đạt được điều này là trình tối ưu hoá R8 , trình biên dịch xử lý mã không dùng và việc xoá tài nguyên để rút gọn, đổi tên hoặc giảm thiểu mã và tối ưu hoá ứng dụng.
Việc bật R8 là một bước quan trọng trong quá trình chuẩn bị phát hành ứng dụng, nhưng yêu cầu nhà phát triển phải cung cấp hướng dẫn dưới dạng "Quy tắc giữ lại".
Sau khi đọc bài viết này, hãy xem video Performance Spotlight Week (Tuần lễ tập trung vào hiệu suất) về cách bật, gỡ lỗi và khắc phục sự cố trình tối ưu hoá R8 trên YouTube.
Lý do cần có quy tắc lưu giữ
Nhu cầu viết Quy tắc giữ lại bắt nguồn từ một xung đột cốt lõi: R8 là một công cụ phân tích tĩnh, nhưng các ứng dụng Android thường dựa vào các mẫu thực thi động như phản chiếu hoặc các lệnh gọi vào và ra khỏi mã gốc bằng JNI (Giao diện gốc Java).
R8 tạo một biểu đồ về mã đã dùng bằng cách phân tích các lệnh gọi trực tiếp. Khi mã được truy cập theo cách linh động, quy trình phân tích tĩnh của R8 không thể dự đoán điều đó và sẽ xác định mã đó là không dùng rồi xoá mã đó, dẫn đến sự cố trong thời gian chạy.
Quy tắc giữ lại là một chỉ dẫn rõ ràng cho trình biên dịch R8, nêu rõ: "Lớp, phương thức hoặc trường cụ thể này là một điểm truy cập sẽ được truy cập linh hoạt trong thời gian chạy. Bạn phải giữ lại thông tin này, ngay cả khi không tìm thấy thông tin tham chiếu trực tiếp đến thông tin đó".
Hãy xem hướng dẫn chính thức để biết thêm thông tin về Quy tắc giữ lại.
Nơi viết quy tắc trong Keep
Quy tắc tuỳ chỉnh để giữ lại cho một ứng dụng được viết trong tệp văn bản. Theo quy ước, tệp này có tên là proguard-rules.pro và nằm trong thư mục gốc của ứng dụng hoặc mô-đun thư viện. Sau đó, tệp này được chỉ định trong loại bản dựng release của tệp build.gradle.kts của mô-đun.
release {
isShrinkResources = true
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
)
}Sử dụng tệp mặc định chính xác
Phương thức getDefaultProguardFile nhập một bộ quy tắc mặc định do SDK Android cung cấp. Khi sử dụng sai tệp, ứng dụng của bạn có thể không được tối ưu hoá. Đảm bảo bạn sử dụng proguard-android-optimize.txt. Tệp này cung cấp Quy tắc lưu giữ mặc định cho các thành phần Android tiêu chuẩn và cho phép R8 tối ưu hoá mã. proguard-android.txt đã lỗi thời chỉ cung cấp Quy tắc giữ lại nhưng không cho phép các hoạt động tối ưu hoá của R8.
Vì đây là một vấn đề nghiêm trọng về hiệu suất, nên chúng tôi bắt đầu cảnh báo nhà phát triển về việc sử dụng sai tệp, bắt đầu từ Bản cập nhật tính năng 3 của Android Studio Narwhal. Kể từ phiên bản 9.0 của Trình bổ trợ Android cho Gradle, chúng tôi sẽ không còn hỗ trợ tệp proguard-android.txt lỗi thời nữa. Vì vậy, hãy nhớ nâng cấp lên phiên bản được tối ưu hoá.
Cách viết quy tắc trong Keep
Quy tắc giữ lại bao gồm 3 phần chính:
- Một lựa chọn như
-keephoặc-keepclassmembers - Đối tượng sửa đổi không bắt buộc như
allowshrinking - Một quy cách lớp xác định mã cần khớp
Để biết cú pháp và ví dụ đầy đủ, hãy tham khảo hướng dẫn về cách thêm Quy tắc giữ lại.
Các mẫu phản quy tắc của Keep
Điều quan trọng là bạn phải biết về các phương pháp hay nhất, cũng như các mẫu chống lại. Những mẫu chống này thường phát sinh từ sự hiểu lầm hoặc các lối tắt khắc phục sự cố và có thể gây ra hậu quả nghiêm trọng cho hiệu suất của bản dựng phát hành.
Tuỳ chọn chung
Đây là các cờ chuyển đổi toàn cầu mà bạn không bao giờ được dùng trong bản phát hành. Chúng chỉ dùng để gỡ lỗi tạm thời nhằm cô lập một vấn đề.
Việc sử dụng -dontotptimize sẽ vô hiệu hoá hiệu quả các hoạt động tối ưu hoá hiệu suất của R8, dẫn đến ứng dụng chạy chậm hơn.
Khi sử dụng -dontobfuscate, bạn sẽ tắt tất cả các thao tác đổi tên và khi sử dụng -dontshrink, bạn sẽ tắt tính năng xoá mã không dùng đến. Cả hai quy tắc chung này đều làm tăng kích thước ứng dụng.
Tránh sử dụng các cờ chung này trong môi trường sản xuất bất cứ khi nào có thể để mang lại trải nghiệm người dùng ứng dụng hiệu quả hơn.
Quy tắc lưu giữ quá rộng
Cách dễ nhất để vô hiệu hoá các lợi ích của R8 là viết các Quy tắc giữ lại quá rộng. Các quy tắc như quy tắc dưới đây hướng dẫn trình tối ưu hoá R8 không rút gọn, không làm rối mã nguồn và không tối ưu hoá bất kỳ lớp nào trong gói này hoặc bất kỳ lớp nào trong các gói con của gói này. Điều này sẽ loại bỏ hoàn toàn các lợi ích của R8 đối với toàn bộ gói đó. Hãy thử viết các Quy tắc giữ lại hẹp và cụ thể.
-keep class com.example.package.** { *;} // WIDE KEEP RULES CAUSE PROBLEMS
Toán tử đảo ngược (!)
Toán tử đảo ngược (!) có vẻ là một cách hiệu quả để loại trừ một gói khỏi quy tắc. Nhưng không đơn giản như vậy. Hãy xem ví dụ sau:
-keep class !com.example.my_package.** { *; } // USE WITH CAUTION
Bạn có thể cho rằng quy tắc này có nghĩa là "không giữ lại các lớp trongcom.example.package". Nhưng thực tế, quy tắc này có nghĩa là "giữ lại mọi lớp, phương thức và thuộc tính trong toàn bộ ứng dụng không nằm trong com.example.package". Nếu bạn thấy điều này bất ngờ, tốt nhất là bạn nên kiểm tra xem có phủ định nào trong cấu hình R8 của mình hay không.
Các quy tắc dư thừa cho thành phần Android
Một lỗi phổ biến khác là thêm Keep Rules theo cách thủ công cho Activities, Services hoặc BroadcastReceivers của ứng dụng. Đây là không cần thiết. Tệp proguard-android-optimize.txt mặc định đã bao gồm các quy tắc có liên quan để những thành phần Android tiêu chuẩn này hoạt động ngay khi xuất xưởng.
Ngoài ra, nhiều thư viện có Quy tắc giữ lại riêng. Vì vậy, bạn không cần phải tự viết các quy tắc cho những trường hợp này. Trong trường hợp có vấn đề với Keep Rules (Quy tắc giữ lại) của một thư viện mà bạn đang sử dụng, tốt nhất là bạn nên liên hệ với tác giả của thư viện đó để xem vấn đề là gì.
Các phương pháp hay nhất về Quy tắc
Bây giờ bạn đã biết những điều cần tránh, hãy cùng tìm hiểu các phương pháp hay nhất.
Viết Quy tắc hẹp cho Keep
Các quy tắc giữ lại hiệu quả phải càng hẹp và cụ thể càng tốt. Họ chỉ nên giữ lại những gì cần thiết, cho phép R8 tối ưu hoá mọi thứ khác.
| Quy tắc | Chất lượng |
|---|---|
| Thấp: Giữ lại toàn bộ gói và các gói con của gói đó |
| Thấp: Giữ nguyên toàn bộ lớp có khả năng vẫn quá rộng |
| Cao: Chỉ giữ lại các phương thức và thuộc tính có liên quan từ một lớp cụ thể |
Sử dụng tổ tiên chung
Thay vì viết các Quy tắc giữ riêng biệt cho nhiều mô hình dữ liệu khác nhau, hãy viết một quy tắc nhắm đến một giao diện hoặc lớp cơ sở chung. Quy tắc bên dưới yêu cầu R8 giữ lại mọi thành phần của các lớp triển khai giao diện này và có khả năng mở rộng cao.
# Keep all fields of any class that implements SerializableModel -keepclassmembers class * implements com.example.models.SerializableModel { <fields>; }
Sử dụng chú thích để nhắm đến nhiều lớp học
Tạo chú thích tuỳ chỉnh (ví dụ: @Serialize) và dùng chú thích đó để "gắn thẻ" cho các lớp cần giữ lại trường. Đây là một mẫu khác rõ ràng, khai báo và có khả năng mở rộng cao. Bạn cũng có thể tạo Quy tắc giữ lại cho các chú thích đã có từ những khung hình mà bạn đang sử dụng.
# Keep all fields of any class annotated with @Serialize -keepclassmembers class * { @com.example.annotations.Serialize <fields>; }
Chọn chế độ giữ lại phù hợp
Lựa chọn giữ lại là phần quan trọng nhất của quy tắc. Việc chọn sai có thể vô tình tắt tính năng tối ưu hoá.
| Lựa chọn giữ lại | Chức năng |
-keep | Ngăn việc xoá hoặc đổi tên lớp và các thành phần được đề cập trong khai báo . |
-keepclassmembers | Ngăn việc xoá hoặc đổi tên các thành phần được chỉ định, nhưng cho phép xoá chính lớp đó, nhưng chỉ trên những lớp không bị xoá theo cách khác. |
-keepclasseswithmembers | Kết hợp: Giữ lại lớp và các thành phần của lớp đó, chỉ khi tất cả các thành phần được chỉ định đều có mặt. |
Bạn có thể tìm hiểu thêm về lựa chọn giữ lại trong tài liệu về Lựa chọn giữ lại của chúng tôi.
Cho phép tối ưu hoá bằng Hệ số điều chỉnh
Các đối tượng sửa đổi như allowshrinking và allowobfuscation nới lỏng một quy tắc -keep rộng, giúp R8 có lại khả năng tối ưu hoá. Ví dụ: nếu một thư viện cũ buộc bạn phải sử dụng -keep trên toàn bộ lớp, thì bạn có thể lấy lại một số hoạt động tối ưu hoá bằng cách cho phép rút gọn và làm rối mã nguồn:
# Keep this class, but allow R8 to remove it if it's unused and allow R8 to rename it. -keep,allowshrinking,allowobfuscation class com.example.LegacyClass
Thêm các lựa chọn chung để tối ưu hoá bổ sung
Ngoài Quy tắc giữ lại, bạn có thể thêm các cờ chung vào tệp cấu hình R8 để khuyến khích tối ưu hoá nhiều hơn nữa.
-repackageclasses là một lựa chọn mạnh mẽ, hướng dẫn R8 di chuyển tất cả các lớp bị làm rối mã nguồn vào một gói duy nhất. Việc này giúp tiết kiệm đáng kể dung lượng trong tệp DEX bằng cách xoá các chuỗi tên gói dư thừa.
-allowaccessmodification cho phép R8 mở rộng quyền truy cập (ví dụ: private thành public) để bật tính năng nội tuyến linh hoạt hơn. Giờ đây, chế độ này được bật theo mặc định khi sử dụng proguard-android-optimize.txt.
Cảnh báo: Tác giả thư viện không bao giờ được thêm các cờ tối ưu hoá chung này vào quy tắc của bên sử dụng thư viện, vì các cờ này sẽ được áp dụng bắt buộc cho toàn bộ ứng dụng.
Để làm rõ hơn, trong phiên bản 9.0 của Trình bổ trợ Android cho Gradle, chúng tôi sẽ bắt đầu bỏ qua hoàn toàn các cờ tối ưu hoá chung từ các thư viện.
Các phương pháp hay nhất cho thư viện
Mọi ứng dụng Android đều dựa vào các thư viện theo cách này hay cách khác. Vậy hãy cùng thảo luận về các phương pháp hay nhất cho thư viện.
Dành cho nhà phát triển thư viện
Nếu thư viện của bạn sử dụng tính năng phản chiếu hoặc JNI, thì bạn có trách nhiệm cung cấp các Quy tắc lưu giữ cần thiết cho người dùng. Các quy tắc này được đặt trong tệp consumer-rules.pro, sau đó tự động được gói bên trong tệp AAR của thư viện.
android {
defaultConfig {
consumerProguardFiles("consumer-rules.pro")
}
...
}Dành cho người dùng thư viện
Lọc ra các Quy tắc Keep có vấn đề
Nếu phải dùng một thư viện có chứa các Quy tắc lưu giữ gây ra vấn đề, bạn có thể lọc các quy tắc đó trong tệp build.gradle.kts bắt đầu từ AGP 9.0. Điều này cho biết R8 sẽ bỏ qua các quy tắc đến từ một phần phụ thuộc cụ thể.
release {
optimization.keepRules {
// Ignore all consumer rules from this specific library
it.ignoreFrom("com.somelibrary:somelibrary")
}
}Quy tắc giữ lại tốt nhất là không có quy tắc giữ lại
Chiến lược cấu hình R8 tối ưu là loại bỏ hoàn toàn nhu cầu viết Quy tắc giữ lại. Đối với nhiều ứng dụng, bạn có thể đạt được điều này bằng cách chọn các thư viện hiện đại ưu tiên tạo mã hơn là phản chiếu.Với tính năng tạo mã, trình tối ưu hoá có thể dễ dàng xác định mã nào thực sự được dùng trong thời gian chạy và mã nào có thể bị xoá. Ngoài ra, việc không sử dụng bất kỳ tính năng phản chiếu động nào có nghĩa là không có điểm truy cập "ẩn", và do đó, không cần Quy tắc giữ lại. Khi chọn một thư viện mới, hãy luôn ưu tiên giải pháp sử dụng tính năng tạo mã hơn là phản chiếu.
Để biết thêm thông tin về cách chọn thư viện, hãy xem phần chọn thư viện một cách khôn ngoan.
Gỡ lỗi và khắc phục sự cố về cấu hình R8
Khi R8 xoá mã mà lẽ ra phải giữ lại hoặc tệp APK của bạn lớn hơn dự kiến, hãy dùng các công cụ này để chẩn đoán vấn đề.
Tìm các quy tắc Keep trùng lặp và quy tắc Keep chung
Vì R8 hợp nhất các quy tắc từ hàng chục nguồn, nên bạn khó biết được bộ quy tắc "cuối cùng" là gì. Việc thêm cờ này vào tệp proguard-rules.pro sẽ tạo ra một báo cáo đầy đủ:
# Outputs the final, merged set of rules to the specified file -printconfiguration build/outputs/logs/configuration.txt
Bạn có thể tìm kiếm trong tệp này để tìm các quy tắc dư thừa hoặc theo dõi một quy tắc có vấn đề (chẳng hạn như -dontoptimize) trở lại thư viện cụ thể đã bao gồm quy tắc đó.
Hỏi R8: Tại sao bạn giữ lại nội dung này?
Nếu một lớp mà bạn dự kiến sẽ bị xoá vẫn còn trong ứng dụng, R8 có thể cho bạn biết lý do. Chỉ cần thêm quy tắc này:
# Asks R8 to explain why it's keeping a specific class class com.example.MyUnusedClass -whyareyoukeeping
Trong quá trình tạo bản dựng, R8 sẽ in chính xác chuỗi tham chiếu khiến công cụ này giữ lại lớp đó, cho phép bạn theo dõi tham chiếu và điều chỉnh các quy tắc của mình.
Để xem hướng dẫn đầy đủ, hãy xem phần khắc phục sự cố R8.
Các bước tiếp theo
R8 là một công cụ mạnh mẽ giúp nâng cao hiệu suất của ứng dụng Android. Hiệu quả của công cụ này phụ thuộc vào việc bạn hiểu đúng cách thức hoạt động của công cụ này với tư cách là một công cụ phân tích tĩnh.
Bằng cách viết các quy tắc cụ thể ở cấp thành viên, tận dụng tổ tiên và chú thích, đồng thời cẩn thận chọn các lựa chọn giữ lại phù hợp, bạn có thể giữ lại chính xác những gì cần thiết. Phương pháp tiên tiến nhất là loại bỏ hoàn toàn nhu cầu về các quy tắc bằng cách chọn các thư viện hiện đại dựa trên codegen thay vì các thư viện dựa trên phản chiếu trước đó.
Trong tuần diễn ra Performance Spotlight Week, hãy nhớ xem video Spotlight Week hôm nay trên YouTube và tiếp tục tham gia thử thách R8 của chúng tôi. Sử dụng #optimizationEnabled cho mọi câu hỏi về việc bật hoặc khắc phục sự cố R8. Chúng tôi sẵn sàng trợ giúp.
Đã đến lúc bạn tự mình trải nghiệm những lợi ích này.
Chúng tôi thách thức bạn bật chế độ đầy đủ của R8 cho ứng dụng của mình ngay hôm nay.
- Hãy làm theo hướng dẫn dành cho nhà phát triển của chúng tôi để bắt đầu: Bật tính năng tối ưu hoá ứng dụng.
- Kiểm tra xem bạn có còn dùng
proguard-android.txthay không và thay thế bằngproguard-android-optimize.txt. - Sau đó, hãy đo lường mức tác động. Đừng chỉ cảm nhận sự khác biệt, hãy xác minh sự khác biệt đó. Đo lường mức tăng hiệu suất bằng cách điều chỉnh mã từ ứng dụng mẫu Macrobenchmark trên GitHub để đo thời gian khởi động trước và sau khi điều chỉnh.
Chúng tôi tin rằng bạn sẽ thấy hiệu suất của ứng dụng được cải thiện đáng kể.
Nhân tiện, hãy dùng thẻ mạng xã hội #AskAndroid để đặt câu hỏi. Trong suốt tuần, các chuyên gia của chúng tôi sẽ theo dõi và trả lời các câu hỏi của bạn.
Hãy theo dõi vào ngày mai, chúng ta sẽ nói về tính năng Tối ưu hoá theo cấu hình với Cấu hình cơ sở và Cấu hình khởi động, chia sẻ cách cải thiện hiệu suất kết xuất của Compose trong các bản phát hành gần đây và chia sẻ những điểm cần cân nhắc về hiệu suất đối với hoạt động ở chế độ nền.
Tiếp tục đọc
-
Tin tức về sản phẩm
Giờ đây, việc kiểm thử các lượt tương tác trên nhiều thiết bị trở nên dễ dàng hơn bao giờ hết nhờ Trình mô phỏng Android.
Steven Jenkins • Đọc trong 2 phút
-
Tin tức về sản phẩm
Mỗi nhà phát triển đều có quy trình làm việc và nhu cầu riêng về AI. Do đó, bạn cần có thể chọn cách AI hỗ trợ quá trình phát triển của mình. Vào tháng 1, chúng tôi đã giới thiệu khả năng chọn bất kỳ mô hình AI cục bộ hoặc từ xa nào để hỗ trợ chức năng AI trong Android Studio
Matthew Warner • Đọc trong 2 phút
-
Tin tức về sản phẩm
Android Studio Panda 3 hiện đã ổn định và sẵn sàng để bạn sử dụng trong bản phát hành chính thức. Bản phát hành này giúp bạn kiểm soát và tuỳ chỉnh quy trình làm việc dựa trên AI một cách hiệu quả hơn, giúp việc tạo ứng dụng Android chất lượng cao trở nên dễ dàng hơn bao giờ hết.
Matt Dyor • Đọc trong 3 phút
Nhận thông tin cập nhật
Nhận thông tin chi tiết mới nhất về hoạt động phát triển trên Android trong hộp thư đến của bạn mỗi tuần.