Khi bạn bật tính năng tối ưu hoá ứng dụng bằng chế độ cài đặt mặc định, R8 sẽ thực hiện các hoạt động tối ưu hoá chuyên sâu để tối đa hoá lợi ích về hiệu suất. R8 thực hiện các sửa đổi đáng kể đối với mã, bao gồm cả việc đổi tên, di chuyển và xoá các trường và phương thức của lớp. Nếu việc này gây ra lỗi, bạn cần chỉ định những phần mã cần giữ lại bằng cách viết quy tắc giữ lại.
R8 có thể xoá hoặc sửa đổi mã không chính xác trong các trường hợp sau:
- Phản chiếu: mã được truy cập bằng tính năng phản chiếu, ví dụ: sử dụng
Class.forName()
hoặcMethod.invoke()
. R8 thường không thể biết lớp hoặc phương thức nào sẽ được truy cập theo cách này. - Tuần tự hoá: các lớp hoặc trường cần thiết cho quá trình tuần tự hoá và huỷ tuần tự hoá có vẻ như không được sử dụng cho R8 (đây là một hình thức phản chiếu khác).
- Giao diện gốc Java (JNI): Các phương thức Java được gọi từ mã gốc. R8 không phân tích mã gốc để xem mã gốc có thể gọi lại vào Java hay không.
Trang này trình bày cách giới hạn phạm vi tối ưu hoá của R8. Để tìm hiểu cách tuỳ chỉnh tài nguyên cần giữ lại, hãy xem phần Thêm quy tắc giữ lại cho tài nguyên.
Vị trí thêm quy tắc giữ lại
Bạn nên thêm các quy tắc vào tệp proguard-rules.pro
nằm trong thư mục gốc của mô-đun (tệp có thể đã có sẵn, nhưng nếu không, hãy tạo tệp đó). Để áp dụng các quy tắc trong tệp, bạn phải khai báo tệp đó trong tệp build.gradle.kts
(hoặc build.gradle
) cấp mô-đun như trong mã sau:
Kotlin
android { buildTypes { release { isMinifyEnabled = true isShrinkResources = true proguardFiles( // Default file with default optimization rules. getDefaultProguardFile("proguard-android-optimize.txt"), // File with your custom rules. "proguard-rules.pro" ) ... } } ... }
Groovy
android { buildTypes { release { minifyEnabled true shrinkResources true proguardFiles( // Default file with default optimization rules. getDefaultProguardFile('proguard-android-optimize.txt'), // File with your custom rules. 'proguard-rules.pro' ) } } // ... }
Theo mặc định, tập lệnh bản dựng của bạn cũng bao gồm tệp proguard-android-optimize.txt
. Tệp này bao gồm các quy tắc bắt buộc đối với hầu hết các dự án Android, vì vậy, bạn nên giữ tệp này trong tập lệnh bản dựng.
Cách viết quy tắc giữ lại
Trong quá trình biên dịch ứng dụng, R8 sẽ phát hiện mã cần được giữ lại trong ứng dụng bằng cách phân tích biểu đồ lệnh gọi của ứng dụng, bắt đầu từ các mục nhập tệp kê khai (chẳng hạn như hoạt động hoặc dịch vụ) và theo dõi qua mọi lệnh gọi hàm ứng dụng và thư viện. R8 xoá mã không được tham chiếu trực tiếp theo cách này, điều này có thể gây ra sự cố nếu mã được thực thi không thuộc biểu đồ này, ví dụ: mã được gọi bằng tính năng phản chiếu. Bằng cách viết quy tắc giữ lại của riêng mình, bạn có thể thông báo cho R8 về mã cần giữ lại trong ứng dụng.
Để thêm quy tắc giữ lại, hãy thêm dòng -keep
trong tệp proguard-rules.pro
.
Giữ lại cú pháp quy tắc
Quy tắc giữ thường tuân theo định dạng sau:
-<KeepOption> [OptionalModifier,...] <ClassSpecification> [{ OptionalMemberSpecification }]
Ví dụ: để giữ lại một lớp cụ thể và tất cả thành viên của lớp đó, hãy sử dụng mã sau:
-keep class com.myapp.MyClass { *; }
Để xem thêm ví dụ, hãy xem phần ví dụ.
Dưới đây là chức năng của các thành phần quy tắc giữ lại:
<KeepOption>
cho phép bạn chỉ định những khía cạnh của một lớp cần giữ lại:Tuỳ chọn giữ lại Mô tả -keep
Duy trì lớp và các thành viên được liệt kê trong
[{ OptionalMemberSpecification }]
.-keepclassmembers
Cho phép tối ưu hoá lớp; nếu lớp được giữ nguyên, hãy giữ nguyên các thành viên được liệt kê trong
[{ OptionalMemberSpecification }]
.-keepnames
Cho phép xoá lớp và thành viên, nhưng không làm rối mã nguồn hoặc sửa đổi theo cách khác.
-keepclassmembernames
Cho phép xoá lớp và thành viên, nhưng không làm rối mã nguồn hoặc sửa đổi thành viên theo cách khác.
-keepclasseswithmembers
Không xoá hoặc làm rối mã nguồn của các lớp nếu các thành viên khớp với mẫu đã chỉ định.
Bạn nên sử dụng
-keepclassmembers
vì lớp này cho phép tối ưu hoá nhiều nhất, sau đó là-keepnames
nếu cần.-keep
không cho phép bất kỳ tính năng tối ưu hoá nào, vì vậy, hãy cố gắng sử dụng tính năng này một cách tiết kiệm.[OptionalModifier],...]
cho phép bạn liệt kê không có hoặc nhiều đối tượng sửa đổi ngôn ngữ Java của một lớp, ví dụ:public
hoặcfinal
.<ClassSpecification>
cho phép bạn chỉ định lớp (hoặc siêu lớp hoặc giao diện đã triển khai) mà quy tắc giữ lại sẽ áp dụng. Trong trường hợp đơn giản nhất, đây là một lớp đủ điều kiện.[{ OptionalMemberSpecification }]
cho phép bạn lọc hành vi giữ lại để chỉ các lớp và phương thức khớp với một số mẫu nhất định. Nhìn chung, bạn nên sử dụng tính năng này trong hầu hết các quy tắc giữ lại để tránh giữ lại nhiều hơn dự kiến.
Giữ lại ví dụ về quy tắc
Sau đây là một số ví dụ về quy tắc giữ lại được thiết kế tốt.
Tạo lớp con
Quy tắc giữ này được đóng gói bên trong androidx.room:room-runtime
để giữ cho các hàm khởi tạo cơ sở dữ liệu được tạo bản sao bằng tính năng phản chiếu.
-keep class * extends androidx.room.RoomDatabase { void <init>(); }
Phản chiếu từ Khung Android ObjectAnimator
Quy tắc giữ này được đóng gói bên trong androidx.vectordrawable:vectordrawable-animated
để cho phép ObjectAnimator
gọi vào phương thức getter hoặc setter từ mã gốc bằng JNI. Xin lưu ý rằng các hệ thống ảnh động mới hơn trong Compose không yêu cầu các quy tắc giữ nguyên như thế này, đây chỉ là một ví dụ về cấu trúc quy tắc.
-keepclassmembers class androidx.vectordrawable.graphics.drawable.VectorDrawableCompat$* {
void set*(***);
*** get*();
}
Đăng ký JNI
Quy tắc giữ này được đóng gói bên trong androidx.graphics:graphics-path
, dùng để giữ các phương thức gốc. Điều này có thể cần thiết nếu thư viện của bạn đăng ký các phương thức gốc theo cách thủ công bằng env->RegisterNatives()
.
-keepclasseswithmembers class androidx.graphics.path.** {
native <methods>;
}