Tối ưu hoá cho tác giả thư viện

Là tác giả thư viện, bạn phải đảm bảo rằng nhà phát triển ứng dụng có thể dễ dàng tích hợp thư viện của bạn vào ứng dụng của họ trong khi vẫn duy trì trải nghiệm chất lượng cao cho người dùng cuối. Bạn nên đảm bảo rằng thư viện của mình tương thích với tính năng tối ưu hoá Android mà không cần thiết lập thêm hoặc ghi nhận rằng thư viện đó có thể không phù hợp để sử dụng trên Android.

Tài liệu này nhắm đến các nhà phát triển thư viện đã phát hành, nhưng cũng có thể hữu ích cho các nhà phát triển mô-đun thư viện nội bộ trong một ứng dụng lớn, được mô-đun hoá.

Nếu bạn là nhà phát triển ứng dụng và muốn tìm hiểu cách tối ưu hoá ứng dụng Android, hãy xem bài viết Bật tính năng tối ưu hoá ứng dụng. Để tìm hiểu về những thư viện phù hợp để sử dụng, hãy xem phần Chọn thư viện một cách khôn ngoan.

Sử dụng codegen thay vì phản chiếu

Khi có thể, hãy sử dụng tính năng tạo mã (codegen) thay vì phản chiếu. Tạo mã và phản chiếu đều là những phương pháp phổ biến để tránh mã nguyên mẫu khi lập trình, nhưng codegen tương thích hơn với trình tối ưu hoá ứng dụng như R8:

  • Với codegen, mã được phân tích và sửa đổi trong quá trình tạo bản dựng. Vì không có bất kỳ sửa đổi lớn nào sau thời gian biên dịch, trình tối ưu hoá sẽ biết mã nào cần thiết và mã nào có thể xoá một cách an toàn.
  • Với tính năng phản chiếu, mã được phân tích và thao tác trong thời gian chạy. Vì mã này chưa thực sự hoàn tất cho đến khi thực thi, nên trình tối ưu hoá không biết mã nào có thể được xoá một cách an toàn. Việc này có thể xoá mã được sử dụng động thông qua phản chiếu trong thời gian chạy, gây ra sự cố ứng dụng cho người dùng.

Nhiều thư viện hiện đại sử dụng codegen thay vì phản chiếu. Xem KSP để biết một điểm truy cập phổ biến, được Room, Dagger2 và nhiều ứng dụng khác sử dụng.

Trường hợp có thể phản chiếu

Nếu phải sử dụng tính năng phản chiếu, bạn chỉ nên phản chiếu vào một trong các thành phần sau:

  • Các loại mục tiêu cụ thể (các trình triển khai giao diện hoặc lớp con cụ thể)
  • Mã sử dụng chú giải thời gian chạy cụ thể

Việc sử dụng tính năng phản chiếu theo cách này sẽ giới hạn chi phí thời gian chạy và cho phép ghi các quy tắc giữ lại của người dùng được nhắm mục tiêu.

Hình thức phản chiếu cụ thể và có mục tiêu này là một mẫu mà bạn có thể thấy trên cả khung Android (ví dụ: khi tăng cường các hoạt động, thành phần hiển thị và đối tượng có thể vẽ) và thư viện AndroidX (ví dụ: khi tạo WorkManager ListenableWorkers hoặc RoomDatabases). Ngược lại, tính năng phản chiếu mở của Gson không phù hợp để sử dụng trong các ứng dụng Android.

Viết quy tắc giữ lại của người dùng

Thư viện nên đóng gói các quy tắc giữ lại "người dùng", sử dụng cùng định dạng với quy tắc giữ lại ứng dụng. Các quy tắc này được đóng gói vào cấu phần phần mềm thư viện (AAR hoặc JAR) và được sử dụng tự động trong quá trình tối ưu hoá ứng dụng Android khi thư viện được sử dụng.

Thư viện AAR

Để thêm quy tắc người dùng cho thư viện AAR, hãy sử dụng tuỳ chọn consumerProguardFiles trong tập lệnh bản dựng của mô-đun thư viện Android. Để biết thêm thông tin, hãy xem hướng dẫn tạo mô-đun thư viện.

Kotlin

android {
    defaultConfig {
        consumerProguardFiles("consumer-proguard-rules.pro")
    }
    ...
}

Groovy

android {
    defaultConfig {
        consumerProguardFiles 'consumer-proguard-rules.pro'
    }
    ...
}

Thư viện JAR

Để gói các quy tắc với thư viện Kotlin/Java được vận chuyển dưới dạng JAR, hãy đặt tệp quy tắc vào thư mục META-INF/proguard/ của JAR cuối cùng, với bất kỳ tên tệp nào. Ví dụ: nếu mã của bạn trong <libraryroot>/src/main/kotlin, hãy đặt tệp quy tắc của người dùng tại <libraryroot>/src/main/resources/META-INF/proguard/consumer-proguard-rules.pro và các quy tắc sẽ được đóng gói ở đúng vị trí trong tệp JAR đầu ra.

Xác minh rằng tệp JAR cuối cùng gói các quy tắc chính xác bằng cách kiểm tra xem các quy tắc có nằm trong thư mục META-INF/proguard hay không.

Hỗ trợ nhiều trình rút gọn (nâng cao)

Bạn có thể điều chỉnh các quy tắc cho mục tiêu đó để nhắm đến các trình rút gọn cụ thể (R8 hoặc ProGuard), cũng như các phiên bản trình rút gọn cụ thể. Điều này cho phép thư viện của bạn hoạt động tối ưu trong các dự án sử dụng phiên bản trình rút gọn mới, đồng thời cho phép tiếp tục sử dụng các quy tắc hiện có trong các dự án có phiên bản trình rút gọn cũ.

Để chỉ định các quy tắc rút gọn được nhắm mục tiêu, bạn cần đưa các quy tắc đó vào các vị trí cụ thể bên trong thư viện AAR hoặc JAR, như mô tả bên dưới.

In an AAR library:
    consumer-proguard-rules.pro (legacy location)
    classes.jar
    └── META-INF
        └── com.android.tools (targeted shrink rules location)
            ├── r8-from-<X>-upto-<Y>/<R8-rules-file>
            └── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>

In a JAR library:
    META-INF
    ├── proguard/<ProGuard-rules-file> (legacy location)
    └── com.android.tools (targeted shrink rules location)
        ├── r8-from-<X>-upto-<Y>/<R8-rules-file>
        └── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>

Điều đó có nghĩa là các quy tắc rút gọn được nhắm mục tiêu được lưu trữ trong thư mục META-INF/com.android.tools của tệp JAR hoặc trong thư mục META-INF/com.android.tools bên trong classes.jar của tệp AAR.

Trong thư mục đó, có thể có nhiều thư mục có tên ở dạng r8-from-<X>-upto-<Y> hoặc proguard-from-<X>-upto-<Y> để cho biết các phiên bản trình rút gọn mà quy tắc bên trong thư mục được viết cho. Xin lưu ý rằng các phần -from-<X> và -upto-<Y> là không bắt buộc, phiên bản <Y>riêng biệt và phạm vi phiên bản phải liên tục.

Ví dụ: r8-upto-8.0.0, r8-from-8.0.0-upto-8.2.0r8-from-8.2.0 tạo thành một bộ quy tắc rút gọn được nhắm mục tiêu hợp lệ. Các quy tắc trong thư mục r8-from-8.0.0-upto-8.2.0 sẽ được R8 sử dụng từ phiên bản 8.0.0 trở lên nhưng không bao gồm phiên bản 8.2.0.

Dựa vào thông tin đó, trình bổ trợ Android cho Gradle sẽ chọn các quy tắc từ các thư mục R8 trùng khớp. Nếu một thư viện không chỉ định các quy tắc rút gọn mục tiêu, thì trình bổ trợ Android cho Gradle sẽ chọn các quy tắc từ các vị trí cũ (proguard.txt cho AAR hoặc META-INF/proguard/<ProGuard-rules-file> cho JAR).