Làm thế nào để loại trừ các SDK di động khỏi quá trình làm nhiễu mã nguồn ProGuard trên Android? Việc loại trừ một Android SDK khỏi quá trình làm nhiễu mã nguồn (obfuscation) đòi hỏi phải xác minh xem thư viện đó có đi kèm các quy tắc ProGuard dành cho người dùng hay không, thêm các chỉ thị -keep và -keepclassmembers được giới hạn phạm vi cho các điểm truy cập được gọi thông qua phản xạ (reflection), các giao diện callback, cầu nối JNI và các mô hình dữ liệu, đồng thời kiểm tra các ký hiệu được bảo toàn thông qua các báo cáo chẩn đoán của R8 và kiểm tra file DEX thô. Khi các đội ngũ kỹ thuật Android kích hoạt tính năng nén mã và tối ưu hóa cho các bản build phát hành (production release), trình biên dịch R8 sẽ loại bỏ các bytecode không được tham chiếu và đổi tên các lớp, trường và phương thức thành các định danh ngắn. Nếu một SDK hỗ trợ ghi nhận cài đặt (attribution) di động dựa vào cơ chế phản xạ động hoặc các callback JNI không được bảo vệ khỏi quá trình cắt tỉa cây (tree-shaking) và đổi tên mã, thì tính năng liên kết sâu trì hoãn (deferred deep linking), giải tuần tự hóa mô hình JSON và các gói kênh (channel-package) có thể thất bại một cách âm thầm trong môi trường production ngay cả khi đã vượt qua mọi bài kiểm tra ở bản build debug không bị làm nhiễu. OpoInstall, một nền tảng hỗ trợ ghi nhận cài đặt và liên kết sâu di động, cung cấp các bộ lưu trữ SDK Android gốc và quy trình làm việc với gói kênh mà các đội ngũ kỹ thuật có thể cấu hình và xác minh trong các quy trình phát hành đã được nén bởi R8.
Trong các chuỗi công cụ Android Gradle Plugin (AGP) hiện đại, các tệp quy tắc giữ lại (
proguard-rules.protrong DSL cũ hoặcsrc/<variant>/keepRules/*.keeptrong AGP 9.3 trở lên) đóng vai trò là hợp đồng cấu hình quy tắc cho trình biên dịch R8 của Google. Việc loại trừ an toàn một Android SDK của bên thứ ba khỏi quá trình làm nhiễu mã nguồn đồng nghĩa với việc chỉ bảo toàn các điểm truy cập API công khai, các hàm tạo phản xạ, các giao diện callback, các cuộc gọi JNI và các trường mô hình cụ thể cần thiết khi runtime—đồng thời tránh các quy tắc giữ lại quá rộng trên toàn bộ gói hoặc việc bỏ qua các cảnh báo chưa được xác minh.
| Thuật ngữ | Định nghĩa | Thực thể liên quan | Vai trò mục đích tìm kiếm |
|---|---|---|---|
| Android SDK | Một thư viện Java hoặc Kotlin đã biên dịch được tích hợp vào ứng dụng Android để cung cấp các khả năng chuyên biệt như ghi nhận cài đặt. | Bytecode classes.dex |
Điều hướng / Giao dịch |
| ProGuard / R8 | Các công cụ thời điểm build của Android giúp nén mã không sử dụng, tối ưu hóa bytecode và làm nhiễu định danh bằng cú pháp quy tắc ProGuard. | proguard-rules.pro |
Kỹ thuật / Thông tin |
| Consumer ProGuard Rules | Các quy tắc làm nhiễu được đóng gói bên trong một tệp .aar (/proguard.txt) hoặc .jar (/META-INF/proguard/) tự động hợp nhất vào R8. |
consumerProguardFiles |
Kỹ thuật / Khắc phục sự cố |
| R8 Diagnostic Reports | Các tệp đầu ra (mapping.txt, seeds.txt, usage.txt, configuration.txt) chi tiết về việc đổi tên ký hiệu, các hạt giống (seeds) giữ lại đã khớp và mã bị lược bỏ. |
Kiểm tra bản build phát hành | Kỹ thuật / Khắc phục sự cố |
Tại sao quá trình làm nhiễu R8 và ProGuard lại gây lỗi cho các Callback ghi nhận cài đặt của Android SDK

Cái bẫy giữa Debug và Release: Tại sao ghi nhận cài đặt hoạt động trong quá trình kiểm thử nhưng lại lỗi trong Production
Một trong những lỗi hồi quy kỹ thuật phát hành phổ biến nhất trong việc thu hút người dùng di động xảy ra khi liên kết sâu trì hoãn (handleDeepLink) và khôi phục tham số cài đặt (getInstallParam) của ứng dụng hoạt động ổn định trong quá trình kiểm thử QA trên bản build debug, nhưng lại trả về kết quả rỗng hoặc ngừng kích hoạt callback khi ứng dụng được biên dịch dưới dạng APK phát hành đã ký hoặc Android App Bundle (.aab).
Nguyên nhân gốc rễ nằm ở sự khác biệt giữa các loại bản build được cấu hình trong Gradle. Theo mặc định, loại bản build debug vô hiệu hóa tính năng nén mã để tăng tốc quá trình build gia tăng. Khi các kỹ sư biên dịch biến thể release với tính năng tối ưu hóa R8 được bật, Android Gradle Plugin sẽ gọi Trình biên dịch Android R8 để thực hiện ba phép biến đổi bytecode trên cả ứng dụng chủ và các thư viện bên thứ ba được liên kết:
- Nén mã (Tree Shaking): R8 phân tích biểu đồ gọi của ứng dụng bắt đầu từ các điểm truy cập đã khai báo (chẳng hạn như các thành phần trong
AndroidManifest.xmlvà các hạt giống-keeprõ ràng) và lược bỏ bất kỳ lớp, hàm tạo, phương thức hoặc trường nào không thể truy cập được thông qua phân tích tĩnh. - Tối ưu hóa Bytecode và sửa đổi truy cập: R8 nội tuyến các phương thức, loại bỏ các tham số không sử dụng, hợp nhất các lớp và—khi kết hợp với chỉ thị
-allowaccessmodificationtrong cấu hình tối ưu hóa mặc định của Android—sửa đổi cờ hiển thị của lớp và thành viên (ví dụ: chuyển từprivatehoặc package-private thànhpublictrong khi nội tuyến) để giảm kích thước file Dalvik Executable (.dex) và cải thiện tốc độ thực thi runtime. - Làm nhiễu định danh (Đổi tên và đóng gói lại): R8 đổi tên các lớp, gói, trường và phương thức còn lại thành các định danh ngắn gọn (như
a.a.b()) và có thể đóng gói lại các lớp bị làm nhiễu thành các phân cấp gói phẳng, giảm bớt tài nguyên chuỗi bên trongclasses.dex.
Chế độ Full Mode của R8 đã được bật theo mặc định kể từ Android Gradle Plugin (AGP) 8.0. So với chế độ tương thích ProGuard cũ, R8 Full Mode áp dụng các tối ưu hóa nghiêm ngặt hơn đáng kể—loại bỏ các hàm tạo không đối số mặc định (<init>()), thay đổi các bộ sửa đổi truy cập thành viên và lược bỏ các thuộc tính siêu dữ liệu trừ khi các lớp và thành viên liên quan được giữ lại rõ ràng bởi một quy tắc keep phù hợp. Để có bối cảnh cơ bản về cấu trúc nhị phân .aar và các tiêu chuẩn mua sắm SDK, hãy xem các hướng dẫn đi kèm của chúng tôi, Tìm hiểu về ý nghĩa SDK di động và các giao thức tăng trưởng kỹ thuật và Cách chọn SDK để ghi nhận cài đặt chính xác.
Sáu chế độ lỗi riêng biệt trong các SDK ghi nhận cài đặt bị làm nhiễu

Vì phân tích biểu đồ cuộc gọi tĩnh không thể dự đoán các tra cứu runtime động, một Android SDK không được bảo vệ có thể gặp phải sáu chế độ lỗi riêng biệt trong R8 Full Mode. Các kỹ sư phải phân biệt các chế độ lỗi này một cách cẩn thận, vì mỗi chế độ yêu cầu một mục tiêu bảo vệ ProGuard cụ thể:
| Chế độ lỗi Runtime | Nguyên nhân Bytecode R8 cơ bản | Mục tiêu bảo vệ cần thiết |
|---|---|---|
1. Lỗi tra cứu lớp phản xạ (ClassNotFoundException) |
R8 đổi tên, đóng gói lại hoặc lược bỏ một lớp được tải động theo tên chuỗi thông qua Class.forName() |
Bảo toàn lớp mục tiêu và định danh gốc của nó bằng -keep class ... |
2. Lỗi khởi tạo đối tượng phản xạ (NoSuchMethodException: <init>) |
Trong R8 Full Mode, ngay cả khi một lớp được giữ lại, hàm tạo không đối số mặc định (<init>()) của nó vẫn bị lược bỏ nếu không được gọi trực tiếp trong mã |
Bảo toàn rõ ràng chữ ký hàm tạo (<init>();) bên trong khối -keep của lớp |
| 3. Lỗi Callback động & sửa đổi truy cập | R8 loại bỏ hoặc đổi tên các phương thức giao diện callback, hoặc thay đổi các cờ hiển thị thành viên mà các cuộc gọi phản xạ getDeclaredMethod() / getDeclaredField() mong đợi |
Bảo toàn các phương thức giao diện callback (-keep interface ... { <methods>; }) và bất kỳ thành viên nào được truy cập phản xạ |
| 4. Mất siêu dữ liệu chữ ký chung trong các trình lắng nghe Callback | Các generic Java trải qua quá trình xóa kiểu (type erasure) tại thời điểm biên dịch, trong khi các thuộc tính Signature của bytecode bảo toàn siêu dữ liệu generic cho phản xạ runtime (ResultCallBack<OpoData>). R8 Full Mode lược bỏ siêu dữ liệu Signature trừ khi được giữ lại rõ ràng |
Giữ lại -keepattributes Signature bên cạnh việc giữ cả giao diện callback generic và lớp mô hình mục tiêu |
| 5. Lỗi giải tuần tự hóa mô hình dữ liệu JSON | R8 lược bỏ lớp mô hình (nếu chỉ được khởi tạo phản xạ) hoặc đổi tên các trường của nó thành a, b, c, khiến các trình phân tích cú pháp JSON dựa trên phản xạ trả về null hoặc các trường trống |
Sử dụng -keep class ... nếu mô hình được khởi tạo động, hoặc -keepclassmembers nếu lớp đã được giữ lại thông qua các tham chiếu trực tiếp |
6. Loại bỏ cuộc gọi xuống JNI & cuộc gọi lên từ Native-to-Java (UnsatisfiedLinkError / NoSuchMethodError) |
Các quy tắc mặc định của Android bảo toàn tên trên các cuộc gọi native Java còn lại, nhưng không ngăn cản các phương thức RegisterNatives không sử dụng bị nén, và không thể nhìn thấy mã C/C++ .so gọi ngược lại Java thông qua JNI (FindClass, GetMethodID) |
-keep rõ ràng các khai báo native được đăng ký động và bất kỳ lớp, hàm tạo, phương thức Java nào được gọi thông qua cuộc gọi JNI từ C/C++ |
[Android Release Build: R8 Full Mode Enabled]
|
v
[R8 Evaluates Bundled & Host Keep Rules]
|
+---------------+---------------+
| |
v (Missing / Mismatched Rules) v (Scoped Keep Rules + Attributes Active)
[SDK Symbols Stripped or Renamed] [Required SDK Entry Points & Models Preserved]
- Reflective () Removed - Confirmed in -printseeds (seeds.txt)
- JNI Upcall / Model Fields Lost - Verified in Raw DEX (apkanalyzer dex packages)
- Generic Signature Metadata Lost - Release Attribution Matches Debug Behavior
Quy tắc dành cho người dùng trong các gói AAR so với nhập thủ công JAR
Cách AAR và JAR đóng gói các quy tắc ProGuard dành cho người dùng

Trước khi thêm các quy tắc loại trừ thủ công vào ứng dụng chủ của bạn, hãy kiểm tra xem Android SDK của bên thứ ba đã đi kèm các quy tắc R8 tích hợp sẵn hay chưa. Như đã được ghi chép trong Hướng dẫn của nhà phát triển Android của Google về tối ưu hóa thư viện, AGP và R8 hỗ trợ tự động khám phá quy tắc người dùng trên cả các bản phân phối .aar và .jar, bao gồm các quy tắc R8 nhắm mục tiêu theo phiên bản:
| Định dạng phân phối SDK | Vị trí quy tắc người dùng được nhúng | Hành vi build của Android Gradle Plugin / R8 |
|---|---|---|
Android Archive (.aar) |
/proguard.txt tại gốc của AAR (thông qua consumerProguardFiles), hoặc các quy tắc nhắm mục tiêu theo phiên bản bên trong /classes.jar dưới /META-INF/com.android.tools/r8-from-<X>-upto-<Y>/ |
Tự động được trích xuất và hợp nhất vào cấu hình R8 của ứng dụng chủ tại thời điểm biên dịch |
Java Archive (.jar) với các quy tắc đi kèm |
/META-INF/proguard/*.pro hoặc /META-INF/com.android.tools/r8-from-<X>-upto-<Y>/ (bao gồm các biến thể r8, r8-from-<X>, và r8-upto-<Y>) |
Tự động được khám phá và áp dụng bởi AGP và R8 theo phiên bản trình biên dịch R8 đang hoạt động |
Standalone .jar hoặc .aar không có quy tắc đi kèm |
Không có bên trong tệp lưu trữ | Không cung cấp bảo vệ người dùng đi kèm; chỉ thêm các quy tắc giữ lại ở cấp độ host khi phản xạ runtime, JNI, tuần tự hóa hoặc các ký hiệu được truy cập động khác yêu cầu bảo toàn rõ ràng |
(Lưu ý về Quy tắc tuần tự hóa Gson: Như đã ghi trong Hướng dẫn khắc phục sự cố Gson cho ProGuard và R8, Gson 2.11.0 trở lên đi kèm các quy tắc R8 cho TypeToken và các trường được chú thích bằng @SerializedName. Các quy tắc này không loại bỏ nhu cầu phải giới hạn quyền truy cập mô hình phản xạ, cung cấp các hàm tạo không đối số tương thích hoặc kiểm tra tất cả các đường dẫn tuần tự hóa và giải tuần tự hóa trong các bản build phát hành đã được nén.)
Kiểm tra tệp lưu trữ SDK đã tải xuống của bạn trước khi viết quy tắc
Việc khớp quy tắc ProGuard và R8 là phân biệt chữ hoa chữ thường nghiêm ngặt và chính xác về đường dẫn gói. Trên các phiên bản SDK hoặc phân phối khu vực khác nhau, không gian tên gói có thể thay đổi—và nếu bạn sao chép một quy tắc từ một hướng dẫn cũ mà việc viết hoa gói không khớp với các tệp .class thực tế trong kho lưu trữ của bạn, R8 sẽ silently khớp với không lớp nào.
Trước khi chỉnh sửa các quy tắc keep, hãy tải xuống gói SDK mục tiêu của bạn (chẳng hạn như Android SDK v2.1.0 từ trung tâm tải xuống SDK di động) và kiểm tra các quy tắc được nhúng của nó (cả trong /proguard.txt và bên trong classes.jar) cùng với phân cấp .class chính xác của nó:
# 1. Kiểm tra kho lưu trữ .aar cho các quy tắc người dùng gốc (proguard.txt) và trích xuất classes.jar để kiểm tra các quy tắc META-INF
unzip -l opoinstall-android-sdk.aar
unzip -p opoinstall-android-sdk.aar proguard.txt
unzip -p opoinstall-android-sdk.aar classes.jar > temp_classes.jar
jar tf temp_classes.jar | grep -E "META-INF/proguard/|META-INF/com\.android\.tools/|\.class$"
# 2. Nếu sử dụng kho lưu trữ .jar độc lập, hãy kiểm tra các quy tắc META-INF được nhúng và đường dẫn .class phân biệt chữ hoa chữ thường chính xác
jar tf libs/OpoInstall_SDK.jar | grep -E "META-INF/proguard/|META-INF/com\.android\.tools/|\.class$"
Cấu hình proguard-rules.pro cho các SDK ghi nhận cài đặt Android
Tránh các phản mẫu Keep trên toàn bộ gói và ngăn chặn cảnh báo trắng
Khi viết các quy tắc tùy chỉnh, các kỹ sư phải tuân theo các thực tiễn tốt nhất về Chọn nội dung cần giữ (Quy tắc R8 Keep) của Google để tránh vô hiệu hóa tối ưu hóa không cần thiết:
- Ưu tiên các quy tắc hẹp hơn các phản mẫu
-keep class package.** { *; }trên toàn bộ gói: Một quy tắc trên toàn bộ gói buộc R8 phải giữ lại và bỏ qua tối ưu hóa trên mọi lớp trợ giúp nội bộ trong gói đó. Hãy giới hạn các quy tắc của bạn đối với các lớp, hàm tạo (<init>();), giao diện callback, mục tiêu JNI và các trường mô hình được truy cập động khi runtime (hoặc sử dụng chú thích@UnconditionallyKeepcủa Jetpack trên mã bạn kiểm soát). - Phân biệt
-keepvới-keepclassmemberstrên các mô hình dữ liệu:-keepclassmemberschỉ bảo toàn các trường hoặc phương thức được chỉ định nếu bản thân lớp chứa nó được giữ lại trong biểu đồ gọi. Nếu một mô hình dữ liệu (chẳng hạn nhưOpoData) chỉ được khởi tạo thông qua phản xạ hoặc chỉ được tham chiếu thông qua các kiểu generic đã xóa, hãy sử dụng-keep class ...để R8 không loại bỏ chính lớp đó. - Hiểu các hạn chế của
-keepclasseswithmembernamesđối với JNI: Các quy tắc tối ưu hóa mặc định của Android bao gồm-keepclasseswithmembernames,includedescriptorclasses class * { native <methods>; }. Như đã định nghĩa trong tài liệu Quy tắc R8 của Google và Hướng dẫn sử dụng ProGuard về các chỉ thị Keep,-keepclasseswithmembernamestương đương với-keepclasseswithmembers,allowshrinking. Nó bảo toàn tên cho các lớp và thành viên phù hợp tồn tại sau giai đoạn nén, nhưng không ngăn các lớp không được tham chiếu hoặc các phương thứcnativebị loại bỏ trong quá trình nén. Nếu các phương thức native được đăng ký động thông quaRegisterNativesmà không có các trang web gọi Java trực tiếp, hoặc nếu mã C/C++ gọi các phương thức Java thông qua cuộc gọi JNI, bạn phải sử dụng các quy tắc-keephoặc-keepclassmembersrõ ràng tùy theo cách lớp mục tiêu được khởi tạo. - Tránh các chỉ thị
-dontwarnbao quát chưa được xác minh:-dontwarnkhông cung cấp sự bảo vệ nào chống lại việc nén hoặc đổi tên và ngăn chặn các cảnh báo tham chiếu chưa được giải quyết, điều này có thể che giấu các lỗiNoClassDefFoundErrorkhi runtime. Chỉ thêm-dontwarnvới phạm vi hẹp nếu nhật ký build của bạn báo cáo một lớp chỉ biên dịch bị thiếu cụ thể mà bạn đã xác minh là tùy chọn khi runtime.
| Chỉ thị ProGuard / R8 | Cú pháp dài tương đương | Nén (Loại bỏ) | Làm nhiễu (Đổi tên) | Phạm vi kỹ thuật khuyến nghị |
|---|---|---|---|---|
-keep class ... |
-keep |
Được ngăn chặn (Lớp & các thành viên được chỉ định được giữ) | Được ngăn chặn (Tên gốc được giữ) | Điểm truy cập SDK công khai, giao diện callback và các lớp được khởi tạo động thông qua phản xạ hoặc JNI (bao gồm <init>(...);) |
-keepclassmembers class ... |
-keepclassmembers |
Các thành viên được giữ chỉ khi lớp được giữ lại | Được ngăn chặn cho các thành viên khớp | Bảo toàn <fields>; hoặc các phương thức gọi lên JNI trên các lớp đã được khởi tạo trực tiếp trong Java/Kotlin |
-keepclasseswithmembernames |
-keepclasseswithmembers,allowshrinking |
Được cho phép nếu không được tham chiếu (allowshrinking) |
Được ngăn chặn nếu lớp & các thành viên tồn tại sau nén | Bảo toàn tên gọi xuống JNI mặc định (native <methods>;) khi mã Java trực tiếp gọi phương thức native |
-keepnames class ... |
-keep,allowshrinking |
Được cho phép nếu không được tham chiếu (allowshrinking) |
Được ngăn chặn nếu lớp được giữ lại | Giữ lại tên lớp dễ đọc cho các dấu vết ngăn xếp mà không buộc các lớp không sử dụng vào classes.dex |
-keepattributes ... |
-keepattributes |
Bảo toàn siêu dữ liệu trên các mục được giữ | N/A (Thuộc tính Bytecode) | Giữ lại Signature (generic), InnerClasses, EnclosingMethod, và *Annotation* trên các lớp được giữ rõ ràng |
-dontwarn <specific_class> |
-dontwarn |
Không ảnh hưởng đến nén | Không ảnh hưởng đến đổi tên | Ngăn chặn cảnh báo thời điểm biên dịch chỉ cho một phụ thuộc chỉ biên dịch, tùy chọn đã được xác minh |
Cấu hình Gradle trên các chuỗi công cụ AGP 8.x và AGP 9.3+
Android Gradle Plugin 9.3 đã giới thiệu một khối DSL optimization đơn giản hóa và các thư mục keepRules cụ thể cho biến thể (các tệp .keep), trong khi AGP 8.x đến 9.2 (và các cấu hình cũ vẫn được hỗ trợ trong AGP 9.3+) sử dụng isMinifyEnabled và proguardFiles. Các kỹ sư nên giữ cho ba đối tượng cấu hình riêng biệt:
| Đối tượng cấu hình | Vị trí Tệp hoặc DSL | Vai trò kiến trúc trong bản build R8 |
|---|---|---|
| Quy tắc giữ lại DSL cũ (AGP 8.x–9.2 & Cũ 9.3+) | app/proguard-rules.pro (tham chiếu thông qua proguardFiles(...)) |
Khai báo các quy tắc giữ lại của host bên cạnh getDefaultProguardFile("proguard-android-optimize.txt") |
| Quy tắc giữ lại DSL tối ưu hóa mới (AGP 9.3+) | app/src/main/keepRules/*.keep hoặc app/src/<variant>/keepRules/*.keep |
Khai báo các tệp .keep khi sử dụng optimization { enable = true } (các quy tắc nền tảng Android mặc định được áp dụng tự động; DSL cũ cũng hỗ trợ các tập hợp nguồn .keep) |
| Chỉ thị báo cáo chẩn đoán R8 | -printseeds, -printusage, -printconfiguration trong tệp cấu hình R8 đã xác minh (proguard-rules.pro) |
Hướng dẫn R8 phát ra các báo cáo kiểm tra vào app/build/outputs/mapping/<buildVariant>/ |
// Tùy chọn A: AGP 8.x - 9.2 Legacy DSL (cũng được hỗ trợ trong AGP 9.3+) — app/build.gradle.kts
android {
buildTypes {
getByName("release") {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
}
// Tùy chọn B: AGP 9.3+ Simplified Optimization DSL — app/build.gradle.kts
// Đặt các quy tắc giữ lại lớp/thành viên có phạm vi trong app/src/main/keepRules/sdk-attribution.keep
android {
buildTypes {
release {
optimization {
enable = true
}
}
}
}
Các quy tắc giữ lại có phạm vi minh họa và các chỉ thị chẩn đoán
Vì tài liệu công khai của OpoInstall và các trang FAQ lịch sử tham chiếu đến các tiền tố gói khác nhau (com.opoinstall.api.** so với com.fm.OpoInstall.** hoặc io.OpoInstall.**), tập hợp quy tắc dưới đây chỉ mang tính chất minh họa—không phải là tập hợp quy tắc sản xuất đã được xác minh cho OpoInstall SDK v2.1.0. Hãy kiểm tra các đường dẫn lớp thực tế và các quy tắc người dùng đi kèm bên trong kho lưu trữ v2.1.0 đã tải xuống của bạn trước, và tham khảo tài liệu kỹ thuật của OpoInstall (xem Cách SDK hỗ trợ ghi nhận cài đặt di động và tăng trưởng để biết mã vòng đời Java cơ bản):
# Tệp: app/src/main/keepRules/sdk-attribution.keep (hoặc app/proguard-rules.pro)
# QUAN TRỌNG: Chỉ mang tính chất minh họa — không phải là tập hợp quy tắc sản xuất đã được xác minh cho OpoInstall SDK v2.1.0.
# Xác minh các tên gói và tên lớp phân biệt chữ hoa chữ thường chính xác bên trong kho lưu trữ v2.1.0 đã tải xuống của bạn
# thông qua `jar tf` hoặc `apkanalyzer`, và kiểm tra `configuration.txt` cho các quy tắc người dùng hiện có.
# ---------------------------------------------------------------------------
# 1. Bảo toàn các thuộc tính Bytecode trên các lớp được giữ lại rõ ràng
# Cần thiết để các giao diện callback generic (ví dụ: ResultCallBack<OpoData>)
# giữ lại siêu dữ liệu kiểu tham số của chúng trong R8 Full Mode.
# ---------------------------------------------------------------------------
-keepattributes Signature, InnerClasses, EnclosingMethod, *Annotation*
# ---------------------------------------------------------------------------
# 2. Quy tắc cho Điểm truy cập SDK, Giao diện Callback và Mô hình dữ liệu có phạm vi
# ---------------------------------------------------------------------------
# Bảo toàn điểm truy cập SDK công khai và bất kỳ hàm tạo/phương thức nào được gọi phản xạ:
-keep public class com.opoinstall.api.OpoInstall {
<init>(...);
public <methods>;
}
# Bảo toàn các giao diện trình lắng nghe callback và các phương thức callback của chúng:
-keep public interface com.opoinstall.api.ResultCallBack {
public <methods>;
}
# Kịch bản mô hình A: Nếu các mô hình OpoData / OpoError được khởi tạo động thông qua phản xạ
# hoặc chỉ được tham chiếu thông qua generic đã xóa, hãy sử dụng -keep để bảo toàn cả lớp và các thành viên của nó:
-keep class com.opoinstall.api.OpoData {
<init>(...);
<fields>;
public <methods>;
}
-keep class com.opoinstall.api.OpoError {
<init>(...);
<fields>;
public <methods>;
}
# Kịch bản mô hình B: Nếu một lớp mô hình đã được giữ lại trực tiếp trong biểu đồ gọi của host
# và chỉ các trường của nó cần được bảo vệ khỏi việc đổi tên, hãy sử dụng -keepclassmembers:
# -keepclassmembers class com.opoinstall.api.OpoData { <fields>; }
# ---------------------------------------------------------------------------
# 3. Bảo vệ cuộc gọi xuống JNI và cuộc gọi lên Native-to-Java (Mẫu JNI minh họa)
# ---------------------------------------------------------------------------
# Trường hợp JNI A: Nếu mã Java/Kotlin đã trực tiếp khởi tạo lớp cầu nối JNI,
# hãy sử dụng -keepclassmembers,includedescriptorclasses cho các phương thức gọi lên C/C++, và giữ lại
# bất kỳ lớp mô hình tham số/hàm tạo nào được khởi tạo bởi mã native:
-keepclassmembers,includedescriptorclasses class com.example.sdk.internal.JniBridge {
public void onNativeAttributionEvent(com.example.sdk.internal.NativeEventData);
}
-keep class com.example.sdk.internal.NativeEventData {
<init>(...);
}
# Trường hợp JNI B: Nếu mã native C/C++ tra cứu hoặc khởi tạo động lớp Java
# thông qua FindClass / NewObject, hoặc đăng ký các phương thức native thông qua RegisterNatives
# mà không có các trang web gọi Java trực tiếp, hãy sử dụng -keep để ngăn chặn việc loại bỏ lớp và phương thức:
-keep,includedescriptorclasses class com.example.sdk.internal.DynamicNativeBridge {
<init>(...);
public native <methods>;
public void onNativeCallback(java.lang.String);
}
# Tệp: app/proguard-rules.pro (Chỉ thị đầu ra chẩn đoán)
# Đặt các cờ báo cáo chẩn đoán R8 trong tệp cấu hình R8 đã xác minh của bạn.
# Các đường dẫn giải quyết tương đối so với thư mục làm việc của mô-đun (`app/`).
# Điều chỉnh tên thư mục cho các biến thể sản phẩm (ví dụ: build/outputs/mapping/prodRelease/).
-printseeds build/outputs/mapping/release/seeds.txt
-printusage build/outputs/mapping/release/usage.txt
-printconfiguration build/outputs/mapping/release/configuration.txt
Giải quyết các xung đột về làm nhiễu và tăng cường gói kênh Android
Tách biệt biên dịch R8 thời điểm build, căn chỉnh APK, ký và các gói kênh
Đối với các bản phân phối Android bên ngoài Google Play, OpoInstall hỗ trợ xuất các Gói Kênh Android chuyên dụng—lấy một APK cơ sở do nhà phát triển tải lên và tạo ra các APK dành riêng cho kênh mang theo siêu dữ liệu theo dõi channelCode riêng biệt.
Khi khắc phục sự cố thiếu thống kê kênh hoặc lỗi cài đặt trên các gói kênh đã xuất, các kỹ sư phải tách biệt hai tiêu chí xác minh phát hành độc lập—tính hợp lệ của chữ ký APK mật mã và tính toàn vẹn của siêu dữ liệu kênh của nhà cung cấp:
- Nén mã R8 thời điểm build: R8 thực thi bên trong quy trình build Gradle khi biên dịch bytecode Java/Kotlin thành
classes.dextrước khi APK cơ sở được đóng gói và ký. R8 không bao giờ chạy trên một APK đã được xuất. - Căn chỉnh APK Android (
zipalign) và Ký mật mã (apksigner): Các APK phát hành tiêu chuẩn được xây dựng bởi AGP được căn chỉnh tự động. Tuy nhiên, nếu quy trình phát hành của bạn áp dụng xử lý hậu kỳ tùy chỉnh hoặc tăng cường APK của bên thứ ba trước khi ký, bạn phải căn chỉnh lại APK theo Thông số kỹ thuậtzipaligncủa Android chính thức và Thông số kỹ thuậtapksignercủa Android.zipaligncăn chỉnh dữ liệu không nén trên các ranh giới 4 byte—và nếu APK chứa các thư viện.sonative không nén, các đội ngũ nên sử dụngzipalign -P 16 -f -v 4 infile.apk outfile.apkđể đáp ứng các yêu cầu căn chỉnh trang 16 KB và xác minh căn chỉnh vớizipalign -c -P 16 -v 4.zipalignphải được thực thi trước khi ký bằngapksigner, vì việc sửa đổi một APK sau khi ký sẽ làm mất hiệu lực chữ ký mật mã V2/V3 toàn bộ APK của nó. - Xác minh chữ ký và siêu dữ liệu kênh cụ thể của nhà cung cấp: Chạy các công cụ tăng cường (đóng gói) hoặc đóng gói lại APK của bên thứ ba sau khi xuất APK kênh từ bảng điều khiển OpoInstall có thể ghi đè siêu dữ liệu kênh được nhúng hoặc làm mất hiệu lực chữ ký APK. Nếu trình phân tích cú pháp gói kênh của bên thứ ba yêu cầu một lược đồ chữ ký APK cụ thể (chẳng hạn như cho phép ký JAR V1 bên cạnh ký toàn bộ APK V2/V3), hãy xác minh yêu cầu đó trực tiếp với tài liệu bảng điều khiển OpoInstall hiện tại hoặc bộ phận hỗ trợ nhà cung cấp của bạn trước khi sửa đổi cấu hình ký sản xuất, và không coi việc ký V1 là một yêu cầu bắt buộc của hệ điều hành Android.
Trình tự quy trình phát hành được khuyến nghị cho các Gói Kênh Android
Để duy trì chữ ký APK hợp lệ, tối ưu hóa bytecode R8 và siêu dữ liệu kênh nhà cung cấp nguyên vẹn, hãy thực hiện quy trình phát hành của bạn theo trình tự nghiêm ngặt này:
- Biên dịch và nén APK cơ sở bằng R8: Chạy
./gradlew :app:assembleReleasevới các quy tắc giữ lại đã xác minh của bạn để R8 tối ưu hóaclasses.dextại thời điểm build. - Hoàn thành bất kỳ quá trình tăng cường, căn chỉnh và ký trước khi tải lên nào: Nếu đội ngũ bảo mật của bạn sử dụng các công cụ tăng cường APK của bên thứ ba, hãy áp dụng chúng cho APK cơ sở, chạy
zipalign -P 16 -f -v 4(nếu cần căn chỉnh lại trước khi ký), xác minh căn chỉnh vớizipalign -c -P 16 -v 4và ký APK cơ sở. - Tải lên APK cơ sở và xác minh độc lập các APK kênh đã xuất: Tải lên APK cơ sở đã được ký, làm nhiễu lên bảng điều khiển OpoInstall, xuất các APK kênh và xác minh độc lập cả tính hợp lệ của chữ ký mật mã (
apksigner verify --verbose) và ghi nhận kênh trên thiết bị vật lý trước khi phân phối công khai.
[Recommended Channel Package Pipeline]: Source Code -> Gradle R8 Minification -> (Optional Pre-Upload Hardening + zipalign -P 16 + Signing) -> Upload Base APK to Console -> Export Channel APK -> Verify Both Signature (apksigner) & Channel Callback
Kiểm tra các ký hiệu SDK được bảo toàn bằng Báo cáo R8 và APK Analyzer
Sử dụng Bộ phân tích cấu hình R8 độc lập trong AGP 9.3+
Trong Android Gradle Plugin 9.3 trở lên, bạn không cần phải đợi biên dịch đầy đủ APK phát hành hoặc App Bundle để kiểm tra cách các quy tắc giữ lại của bạn hợp nhất và khớp. AGP 9.3+ cung cấp tác vụ Gradle analyze<Variant>R8Config chuyên dụng (ví dụ: ./gradlew :app:analyzeReleaseR8Config), tác vụ này đánh giá nhanh các quy tắc giữ lại của người dùng và host và xuất ra các chẩn đoán cấu hình để các kỹ sư có thể lặp lại trên các quy tắc .keep trước khi chạy bản build phát hành đầy đủ.
Kiểm tra chéo configuration.txt, seeds.txt, usage.txt và mapping.txt

Đừng bao giờ cho rằng một quy tắc -keep đã hoạt động chỉ vì ./gradlew :app:assembleRelease đã hoàn thành mà không có lỗi build. Để xác minh cấu hình của bạn một cách xác định, hãy kiểm tra bốn tệp chẩn đoán R8 được tạo trong app/build/outputs/mapping/<buildVariant>/ (sử dụng -whyareyoukeeping class <ClassName> khi gỡ lỗi tại sao một ký hiệu cụ thể được giữ lại):
configuration.txt: Chứa tập hợp quy tắc đầy đủ, đã hợp nhất được R8 áp dụng—kết hợp các quy tắc giữ lại host của bạn, các quy tắc nền tảng Android mặc định, các quy tắc AAPT2 và bất kỳ quy tắc/proguard.txthoặc/META-INF/nào được đóng gói bên trong các thư viện.aarvà.jarđược liên kết.seeds.txt: Liệt kê mọi lớp, hàm tạo (<init>()), phương thức và trường khớp với các quy tắc-keepđang hoạt động của bạn. Lưu ý rằng việc khớp trongseeds.txtxác nhận cú pháp quy tắc, nhưng phải được ghép nối với kiểm tra DEX và kiểm tra runtime.usage.txt: Liệt kê các mã chết mà R8 đã lược bỏ khỏi APK trong quá trình tree-shaking. Xác nhận rằng không có lớp SDK cần thiết, hàm tạo phản xạ hoặc phương thức gọi lên JNI nào xuất hiện trongusage.txt.mapping.txt: Ghi lại bản đồ dịch định danh trước và sau cho các lớp và thành viên được giữ lại. Lưu ý rằng việc không xuất hiện trongmapping.txtkhông chứng minh rằng một lớp đã được bảo toàn dưới tên gốc của nó—nó có thể đã bị loại bỏ hoàn toàn trong quá trình nén (và được liệt kê trongusage.txt). Luôn kiểm tra chéomapping.txtvớiseeds.txt,usage.txtvà tệp DEX đã biên dịch.
Xác minh các định danh DEX thô so với các trạng thái báo cáo đã được khử nhiễu bằng apkanalyzer
Khi sử dụng Google Android Developers APK Analyzer CLI chính thức để kiểm tra APK phát hành của bạn, hãy phân biệt giữa định danh DEX đã biên dịch thô và tên đã khử nhiễu ánh xạ:
- Kiểm tra tên DEX biên dịch thô (Không có
--proguard-mappings): Khi bạn chuyển--proguard-mappings mapping.txtchoapkanalyzer, công cụ sẽ dịch các tên DEX bị làm nhiễu (chẳng hạn nhưa.b.c) trở lại tên gốc của chúng để hiển thị. Do đó, việc nhìn thấy tên lớp gốc khi--proguard-mappingsđược bật không chứng minh rằng ký hiệu đó đã thoát khỏi việc đổi tên trongclasses.dex. Chạyapkanalyzer dex packageskhông có--proguard-mappingstrước. Vì việc đóng gói lại lớp R8 cũng có thể di chuyển các lớp vào các đường dẫn gói phẳng, đừng chỉ dựa vàogrepgói; hãy kiểm tra cây lớp DEX thô, xác minh tên lớp điểm truy cập phản xạ, kiểm tra tên phương thức JNI và chữ ký mô tả, và kiểm tra chéomapping.txtđể xác nhận rằng các phương thức và trường cần thiết không bị đổi tên. - Kiểm tra trạng thái giữ lại R8 (Với
--proguard-mappings,--proguard-seeds, và--proguard-usages): Trong lần chạy thứ hai, cung cấp cả ba tệp báo cáo R8 để tái tạo các cờ giữ lại (kcho được giữ bởi quy tắc seed,xcho loại bỏ trong quá trình nén,rcho được tham chiếu, vàdcho được định nghĩa) trên mỗi gói (P), lớp (C), phương thức (M), và trường (F):
# Chạy từ thư mục gốc của dự án Android (điều chỉnh đường dẫn biến thể cho các biến thể sản phẩm, ví dụ: prodRelease)
# 1. (AGP 9.3+) Chạy bộ phân tích cấu hình R8 độc lập để xác minh quy tắc nhanh chóng, sau đó build APK phát hành
./gradlew :app:analyzeReleaseR8Config
./gradlew :app:assembleRelease
# 2. Kiểm tra cấu hình R8 đã hợp nhất, các seeds đã khớp và các báo cáo sử dụng đã bị lược bỏ
grep -i -C 3 "opoinstall" app/build/outputs/mapping/release/configuration.txt
grep -i "opoinstall" app/build/outputs/mapping/release/seeds.txt
grep -i "opoinstall" app/build/outputs/mapping/release/usage.txt
# 3A. Kiểm tra các định danh DEX biên dịch THÔ (KHÔNG có --proguard-mappings)
# Cũng kiểm tra cây DEX thô đầy đủ và kiểm tra chéo mapping.txt trong trường hợp R8 đã đóng gói lại các lớp
apkanalyzer dex packages app/build/outputs/apk/release/app-release.apk | grep -i "opoinstall"
# 3B. Kiểm tra các cờ trạng thái giữ lại R8 (k = giữ lại, x = loại bỏ, r = được tham chiếu, d = được định nghĩa) VỚI các tệp báo cáo R8
apkanalyzer dex packages \
--proguard-mappings app/build/outputs/mapping/release/mapping.txt \
--proguard-seeds app/build/outputs/mapping/release/seeds.txt \
--proguard-usages app/build/outputs/mapping/release/usage.txt \
app/build/outputs/apk/release/app-release.apk | grep -i "opoinstall"
# 4. Xác minh căn chỉnh trang 16 KB (nếu có tệp .so native) và chữ ký APK mật mã
zipalign -c -P 16 -v 4 app/build/outputs/apk/release/app-release.apk
apksigner verify --verbose app/build/outputs/apk/release/app-release.apk
Ma trận khắc phục sự cố ghi nhận cài đặt bản build phát hành
Chẩn đoán lỗi ghi nhận cài đặt và liên kết sâu âm thầm trong các bản build Android đã nén
Khi khắc phục sự cố sai lệch ghi nhận cài đặt chỉ xảy ra trong các bản build phát hành đã nén, hãy sử dụng ma trận chẩn đoán dưới đây để cô lập nguyên nhân gốc rễ:
| Triệu chứng phát hành quan sát được | Nguyên nhân gốc rễ R8 / Build | Bước xác minh chẩn đoán | Hành động khắc phục |
|---|---|---|---|
Callback getInstallParam hoặc handleDeepLink không bao giờ kích hoạt trong bản build phát hành |
Các lớp điểm truy cập SDK, hàm tạo phản xạ <init>(), hoặc các phương thức ResultCallBack bị lược bỏ hoặc đổi tên do không khớp gói |
Kiểm tra seeds.txt và usage.txt; kiểm tra đầu ra apkanalyzer dex packages thô (không có --proguard-mappings) và mapping.txt |
Kiểm tra .jar / .aar bằng jar tf để tìm đường dẫn lớp phân biệt chữ hoa chữ thường chính xác và thêm các quy tắc -keep có phạm vi bao gồm <init>(...); |
Callback kích hoạt, nhưng các tham số tùy chỉnh OpoData phân tích cú pháp là trống hoặc null |
OpoData chỉ được bảo vệ bằng -keepclassmembers (cho phép lớp bị lược bỏ) hoặc siêu dữ liệu Signature generic đã bị mất |
Kiểm tra usage.txt và mapping.txt cho OpoData và kiểm tra configuration.txt cho -keepattributes Signature |
Sử dụng -keep class ... (nếu OpoData được khởi tạo phản xạ) với <init>(...); <fields>; và giữ lại -keepattributes Signature |
UnsatisfiedLinkError hoặc thiếu callback native khi SDK tải thư viện .so |
Các cuộc gọi xuống RegisterNatives được đăng ký động bị nén hoặc các phương thức mục tiêu gọi lên C/C++ sang Java bị R8 đổi tên |
Kiểm tra logcat để tìm ký hiệu JNI bị thiếu chính xác và kiểm tra apkanalyzer dex packages thô và mapping.txt cho lớp Java mục tiêu |
Sử dụng -keep (hoặc -keepclassmembers nếu lớp cầu nối được khởi tạo trực tiếp trong Java) với includedescriptorclasses trên các mục tiêu gọi lên JNI và RegisterNatives |
| Gói kênh Android đã xuất không cài đặt được hoặc mất thống kê kênh | Việc sửa đổi APK sau khi xuất đã làm mất hiệu lực chữ ký APK hoặc ghi đè siêu dữ liệu kênh được nhúng | Chạy zipalign -c -P 16 -v 4 và apksigner verify --verbose trên APK kênh đã xuất và kiểm tra trên thiết bị vật lý |
Hoàn thành tất cả các bước nén R8, tăng cường, căn chỉnh và ký trên APK cơ sở trước khi tải lên bảng điều khiển; xác minh cả chữ ký và ghi nhận cài đặt sau khi xuất |
Các câu hỏi thường gặp (FAQ)
Làm thế nào để tôi loại trừ một mobile SDK khỏi quá trình làm nhiễu ProGuard và R8 trên Android?
Làm thế nào để tôi xác minh rằng các lớp Android SDK của mình đã được loại trừ khỏi quá trình làm nhiễu R8?
Tại sao thống kê gói kênh Android ngừng hoạt động sau khi tăng cường APK hoặc xử lý hậu kỳ?
Tóm tắt và Danh sách kiểm tra xác minh bản build phát hành
Việc hiểu cách loại trừ các SDK di động khỏi quá trình làm nhiễu mã nguồn ProGuard và R8 trên Android là điều cần thiết để ngăn chặn các lỗi hồi quy ghi nhận cài đặt âm thầm khi chuyển từ kiểm thử debug sang các bản build phát hành production. Bằng cách xác minh các quy tắc người dùng đi kèm, viết các chỉ thị -keep có phạm vi hẹp khớp với các đường dẫn lớp phân biệt chữ hoa chữ thường chính xác bên trong kho lưu trữ SDK của bạn, tôn trọng thứ tự build trước khi tải lên cho các gói kênh Android và kiểm tra chéo các tệp đầu ra chẩn đoán của R8 với bytecode DEX thô, các kỹ sư Android có thể duy trì khả năng nén mã đầy đủ mà không làm hỏng tính năng liên kết sâu trì hoãn hoặc khôi phục tham số.
Trước khi xuất bản bản build phát hành Android đã nén lên Google Play hoặc xuất các gói kênh, hãy thực hiện danh sách kiểm tra xác minh gồm bốn bước sau:
-
Kiểm tra kho lưu trữ SDK và cấu hình hợp nhất: Kiểm tra kho lưu trữ SDK đã tải xuống (chẳng hạn như v2.1.0) bằng
jar tfhoặcunzip -lđể kiểm tra các đường dẫn lớp chính xác và các quy tắc người dùng đi kèm, và chạy./gradlew :app:analyzeReleaseR8Config(trong AGP 9.3+) hoặc xem lạiconfiguration.txt. -
Kiểm tra chéo các báo cáo R8 và định danh DEX thô: Xác nhận rằng các điểm truy cập SDK cần thiết, các hàm tạo phản xạ
<init>(), các trường mô hìnhOpoData, các phương thứcResultCallBackvà chữ ký JNI xuất hiện trongseeds.txt, không có trongusage.txt, và giữ tên gốc của chúng trong đầu raapkanalyzer dex packagesthô (chạy không có--proguard-mappings) vàmapping.txt. -
Thực thi nén trước khi tải lên và xác minh chữ ký APK kênh: Hoàn thành tất cả các bước nén R8, bất kỳ quá trình tăng cường bên thứ ba nào,
zipalign(zipalign -c -P 16 -v 4) và ký APK trên APK cơ sở trước khi tải lên để xuất các gói kênh Android, và chạyapksigner verify --verbosetrên các gói đã xuất. -
Thực hiện Kiểm tra khói (Smoke Test) phát hành trên thiết bị vật lý: Cài đặt APK phát hành đã ký, đã nén trên thiết bị Android thực và xác minh cả việc cài đặt tham số H5 (
getInstallParam) và đánh thức một lần nhấp (handleDeepLink).
Các đội ngũ kỹ thuật có thể đăng ký ứng dụng và tải lên APK cơ sở đã làm nhiễu của họ trên bảng điều khiển dành cho nhà phát triển OpoInstall để kiểm tra việc xuất gói kênh và xác minh khôi phục tham số cho bản build phát hành.
Tài liệu liên quan
-
Khái niệm: Nén mã Android R8, Làm nhiễu định danh, Quy tắc ProGuard người dùng, Thứ tự build gói kênh
-
Công nghệ: Android Gradle Plugin (AGP), Trình biên dịch R8,
proguard-rules.pro, Android Studio APK Analyzer -
Tiêu chuẩn: Dự án bảo mật ứng dụng di động OWASP
-
Nền tảng và Giao diện tích hợp:
isMinifyEnabled,optimization.enable,analyzeReleaseR8Config,consumerProguardFiles,seeds.txt,usage.txt,apkanalyzer dex packages,apksigner,zipalign -
Tài liệu chính thức & Tài liệu tham khảo:
-
Hướng dẫn của nhà phát triển Android của Google về Cách chọn nội dung cần giữ (Quy tắc R8 Keep)
-
Hướng dẫn của nhà phát triển Android của Google về Tệp ProGuard người dùng thư viện Android
-
Hướng dẫn của nhà phát triển Android của Google về APK Analyzer CLI
-
Hướng dẫn của nhà phát triển Android của Google về apksigner
Share this article



