使用預設設定啟用應用程式最佳化功能時,R8 會執行全面最佳化,以便充分發揮效能優勢。R8 會對程式碼進行重大修改,包括重新命名、移動及移除類別欄位和方法。如果這會導致錯誤,您必須編寫保留規則,指定要保留的程式碼部分。
在下列情況下,R8 可能會錯誤移除或修改程式碼:
- 反映:使用反映功能存取的程式碼,例如使用
Class.forName()
或Method.invoke()
。R8 通常無法判斷哪些類別或方法會以這種方式存取。 - 序列化:序列化和反序列化所需的類別或欄位,可能會顯示為 R8 未使用的項目 (這是另一種反射形式)。
- Java 原生介面 (JNI):從原生程式碼呼叫的 Java 方法。R8 不會分析原生程式碼,查看可能回呼至 Java 的內容。
本頁面將說明如何限制 R8 的最佳化程度。如要瞭解如何自訂要保留的資源,請參閱「為資源新增保留規則」。
新增保留規則的位置
您應將規則新增至位於模組根目錄中的 proguard-rules.pro
檔案 (檔案可能已在該目錄中,但如果沒有,請建立檔案)。如要套用檔案中的規則,您必須在模組層級的 build.gradle.kts
(或 build.gradle
) 檔案中宣告檔案,如以下程式碼所示:
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' ) } } // ... }
根據預設,您的建構指令碼也會包含 proguard-android-optimize.txt
檔案。這個檔案包含大多數 Android 專案所需的規則,因此請將其保留在建構指令碼中。
如何編寫 Keep 規則
在應用程式編譯期間,R8 會分析應用程式的呼叫圖表,藉此偵測應用程式中需要保留哪些程式碼,這些圖表會從資訊清單項目 (例如活動或服務) 開始,並追蹤每個應用程式和程式庫函式呼叫。R8 會移除未以這種方式直接參照的程式碼,如果執行的程式碼並非此圖表的一部分,可能會導致問題,例如透過反射方式叫用的程式碼。您可以編寫自己的保留規則,向 R8 告知需要保留在應用程式中的程式碼。
如要新增保留規則,請在 proguard-rules.pro
檔案中加入 -keep
程式碼行。
保留規則語法
Keep 規則通常會遵循以下格式:
-<KeepOption> [OptionalModifier,...] <ClassSpecification> [{ OptionalMemberSpecification }]
舉例來說,如要保留特定類別及其所有成員,請使用以下方式:
-keep class com.myapp.MyClass { *; }
如需更多範例,請參閱範例一節。
以下說明保留規則元件的運作方式:
<KeepOption>
可讓您指定要保留的類別層面:Keep 選項 說明 -keep
保留
[{ OptionalMemberSpecification }]
中列出的類別和成員。-keepclassmembers
允許最佳化類別;如果保留類別,請保留
[{ OptionalMemberSpecification }]
中列出的成員。-keepnames
允許移除類別和成員,但不要以其他方式模糊處理或修改。
-keepclassmembernames
允許移除類別和成員,但不要以其他方式模糊處理或修改成員。
-keepclasseswithmembers
如果成員符合指定模式,則不會移除或模糊處理類別。
我們建議您盡量使用
-keepclassmembers
,因為它可啟用最多最佳化功能,然後視需要使用-keepnames
。-keep
不允許任何最佳化,因此請盡量少用。[OptionalModifier],...]
可讓您列出類別的零個或多個 Java 語言修飾符,例如public
或final
。<ClassSpecification>
可讓您指定要將保留規則套用至哪個類別 (或哪個父類別或實作的介面)。在最簡單的情況下,這會是單一完整的類別。[{ OptionalMemberSpecification }]
可讓您將 Keep 行為篩選為僅符合特定模式的類別和方法。一般來說,建議在大多數保留規則中使用此選項,以免保留的資料量超出預期。
Keep 規則範例
以下列舉一些設計良好的保留規則範例。
建構子類別
這個保留規則會封裝在 androidx.room:room-runtime
內,以保留透過反射技術建構的資料庫建構函式。
-keep class * extends androidx.room.RoomDatabase { void <init>(); }
來自 Android 架構的反射 ObjectAnimator
這項保留規則會封裝在 androidx.vectordrawable:vectordrawable-animated
內,讓 ObjectAnimator
能夠透過 JNI 呼叫原生程式碼中的 getter 或 setter。請注意,Compose 中的新動畫系統不需要這類保留規則,這只是規則結構的範例。
-keepclassmembers class androidx.vectordrawable.graphics.drawable.VectorDrawableCompat$* {
void set*(***);
*** get*();
}
JNI 註冊
這項保留規則會封裝在 androidx.graphics:graphics-path
中,用於保留原生方法。如果程式庫是透過 env->RegisterNatives()
手動註冊原生方法,就可能需要這麼做。
-keepclasseswithmembers class androidx.graphics.path.** {
native <methods>;
}