根據預設,R8 會進行許多最佳化調整,以提升效能和大小,但這些最佳化調整可能不會立即對應用程式生效。如果您是首次在大型應用程式中啟用 R8 (或啟用完整模式),請嘗試逐步採用最佳化功能:暫時關閉模糊處理功能,並一次為部分程式碼啟用 R8,而不是為應用程式中的所有程式碼啟用。建議您在本地開發期間採取這種逐步做法,但您也可以在內部品質確保測試期間,甚至在實際工作環境中逐步推出。具體步驟取決於您預期的時間軸,以及對預先發布版測試涵蓋範圍的信心。
限制最佳化次數
R8 會執行多種最佳化作業,包括移除程式碼、重寫程式碼及移除資源。以下概略說明最佳化類型:
- 程式碼縮減 (或 tree shaking):移除未參照的程式碼
- 模糊處理 (或 ID 壓縮):縮短類別和方法的名稱
- 最佳化:重新編寫程式碼,例如內嵌
為減少錯誤發生的機率,建議您先啟用部分最佳化功能。
僅啟用 tree shaking (移除沒用到的程式碼)
程式碼縮減 (也稱為 tree shaking) 是指移除未參照的程式碼。建議您先從 tree shaking (移除沒用到的程式碼) 開始,因為這是最簡單的方法。
如要只啟用 tree shaking (移除沒用到的程式碼),請在 proguard-rules.pro 檔案中加入以下內容,關閉其他類型的最佳化功能。關閉模糊處理功能是關鍵,因為這樣可以讓堆疊追蹤更容易閱讀。
-dontobfuscate // Use temporarily to turn off identifier minification
-dontoptimize // Use temporarily to turn off optimization
最後,您不會想發布這項設定,因為這會大幅限制 R8 最佳化程式碼的能力,但如果首次在大型程式碼集中採用 R8,且有問題需要修正,這會是很好的起點。
使用相容模式
根據預設,R8 會以完整模式執行。完整模式可大幅提升效能並節省大小,但您可以在首次啟用縮減功能時暫時停用完整模式,改用相容模式。
如要使用相容模式,請在 gradle.properties 檔案中使用下列設定:
android.enableR8.fullMode = false // Use temporarily to disable full mode
啟用其餘最佳化功能
確認 tree shaking (移除沒用到的程式碼) 適用於應用程式後,即可移除上述設定,重新啟用模糊化、最佳化和 R8 完整模式。請注意,模糊處理可能會增加偵錯難度,因此建議您先解決 tree shaking (移除沒用到的程式碼) 問題。
如要進一步瞭解如何對堆疊追蹤進行去模糊化,請參閱「復原原始堆疊追蹤」。
限制最佳化範圍
完整最佳化的建構作業會最佳化每個程式庫和套件中的所有程式碼,因此首次啟用 R8 時,通常會遇到問題。如果您發現應用程式某個部分的最佳化功能有問題,請勿完全關閉 R8,否則其他部分也會失去最佳化功能。請改為暫時停用 R8,只針對造成問題的應用程式部分停用。
使用套件層級的保留規則
建議您使用套件層級的保留規則,暫時停用應用程式部分區域的 R8。您應一律在稍後修正這些最佳化問題;這通常是解決問題區域的臨時解決方案。
舉例來說,如果應用程式的某個部分大量使用 Gson,並導致最佳化問題,理想的修正方式是新增更多指定保留規則,或改用程式碼產生解決方案。不過,如要解除封鎖應用程式其餘部分的最佳化功能,您可以將定義 Gson 類型的程式碼放在專屬子套件中,並在 proguard-rules.pro 檔案中加入類似以下的規則:
-keep class com.myapp.json.** { *; }
如果您使用的某些程式庫反映到內部元件,您也可以為整個程式庫新增保留規則。您需要檢查程式庫的程式碼或 JAR/AAR,找出要保留的適當套件。同樣地,我們不建議長期維持這種做法,但這可以讓應用程式的其他部分順利進行最佳化:
-keep class com.somelibrary.** { *; }
移除套件範圍的保留規則
當應用程式能以套件範圍的保留規則正常運作時,請返回並新增指定保留規則,或移除一開始需要保留規則的反射用法或程式庫。
舉例來說,在 AndroidX 中,保留擴充特定類別的所有規則非常常見,因為這樣就能只保留相關類別。一般來說,反射應只以擴充特定抽象類別、實作特定介面,或具有特定執行階段註解的類別或方法為目標。這些都是支援的保留規則定義方式,因此您不需要在最終的完整最佳化應用程式中,使用套件層級的保留規則。
如果程式碼集有反射,您可以使用 Jetpack Keep 取代套件層級的保留規則。產生的規則是有條件的:只有在 R8 保留進行呼叫的程式碼時,才會保留反射呼叫的目標。如要遷移套件,請使用 Jetpack Keep Lint 檢查尋找並註解其反射呼叫,然後移除套件範圍規則。