選擇適當的程式庫
透過集合功能整理內容
你可以依據偏好儲存及分類內容。
如要啟用應用程式最佳化功能,您必須使用與 Android 最佳化相容的程式庫。如果程式庫未針對 Android 最佳化進行設定 (例如,如果使用反射而未綁定相關的保留規則),可能就不適合用於 Android 應用程式。本頁說明為何某些程式庫更適合用於應用程式最佳化,並提供一般提示協助您做出選擇。
優先使用 codegen 而非反射
一般來說,您應選擇使用程式碼產生 (codegen) 而非反射的程式庫。有了 codegen,最佳化工具就能更輕鬆地判斷在執行階段實際使用的程式碼,以及可移除的程式碼。很難判斷程式庫是否使用 codegen 或反射,但還是有一些徵兆,請參閱提示瞭解如何判斷。
如要進一步瞭解 codegen 與反射的差異,請參閱「程式庫作者的最佳化」。
選擇程式庫時的一般訣竅
請參考下列提示,確保您的程式庫與應用程式最佳化相容。
檢查最佳化問題
考慮採用新程式庫時,請查看程式庫的問題追蹤器和線上討論,確認是否有與縮減或設定應用程式最佳化相關的問題。如果有,請嘗試尋找該程式庫的替代方案。請注意以下事項:
- AndroidX 程式庫和 Hilt 等程式庫可有效提升應用程式效能,因為這些程式庫使用 codegen 而非反射。使用反射時,會提供最少的保留規則,只保留所需的程式碼。
- 序列化程式庫經常使用反射,以便在例項化或序列化物件時避免使用樣板程式碼。請尋找使用 codegen 的程式庫,以避免這些問題,例如使用 Kotlin 序列化。
- 請盡量避免使用含有套件級別保留規則的程式庫。套件層級的保留規則有助於解決錯誤,但最終應精簡廣泛的保留規則,只保留所需的程式碼。詳情請參閱「逐步採用最佳化功能」。
在新增資料庫後啟用最佳化功能
新增程式庫後,請啟用最佳化功能,並檢查是否有錯誤。如果發生錯誤,請尋找該程式庫的替代方案,或撰寫保留規則。如果程式庫與最佳化不相容,請回報該程式庫的錯誤。
規則屬於外加
請注意,保留規則是外加規則,也就是說,程式庫依附元件中包含的特定規則無法移除,且可能會影響應用程式其他部分的編譯。舉例來說,如果程式庫包含停用程式碼最佳化的規則,該規則會停用整個專案的最佳化功能。
檢查是否使用反射 (進階)
您或許可以透過檢查程式庫的程式碼,判斷該程式庫是否使用反射功能。如果程式庫使用反射,請確認它提供相關的保留規則。如果程式庫執行下列操作,可能會使用反射功能:
- 使用
kotlin.reflect
或 java.lang.reflect
套件的類別或方法
- 使用
Class.forName
或 classLoader.getClass
函式
- 在執行階段讀取註解,例如使用
val value = myClass.getAnnotation()
或 val value =
myMethod.getAnnotation()
儲存註解值,然後使用 value
執行某項操作
使用方法名稱做為字串呼叫方法,例如:
// Calls the private `processData` API with reflection
myObject.javaClass.getMethod("processData", DataType::class.java)
?.invoke(myObject, data)
篩除不良的保留規則 (進階)
請避免使用含有保留規則的程式庫,因為這些規則會保留應移除的程式碼。不過,如果您必須使用這些規則,可以篩除規則,如以下程式碼所示:
// If you're using AGP 8.4 and higher
buildTypes {
release {
optimization.keepRules {
it.ignoreFrom("com.somelibrary:somelibrary")
}
}
}
// If you're using AGP 7.3-8.3
buildTypes {
release {
optimization.keepRules {
it.ignoreExternalDependencies("com.somelibrary:somelibrary")
}
}
}
個案研究:為什麼 Gson 會在最佳化後發生錯誤
Gson 是序列化程式庫,因為大量使用反射,經常會導致應用程式最佳化問題。以下程式碼片段顯示 Gson 的一般用法,這可能會輕易導致執行階段發生當機。請注意,當您使用 Gson 取得 User 物件清單時,請勿呼叫建構函式或將工廠傳遞至 fromJson()
函式。在未使用下列任一項目的情況下,建構或使用應用程式定義的類別,表示程式庫可能會使用開放式反射:
- 實作程式庫的應用程式類別,或標準介面或類別
- 程式碼產生外掛程式,例如 KSP
class User(val name: String)
class UserList(val users: List<User>)
// This code runs in debug mode, but crashes when optimizations are enabled
Gson().fromJson("""[{"name":"myname"}]""", User::class.java).toString()
當 R8 分析這段程式碼,但未在任何地方看到 UserList
或 User
例項化時,它可能會重新命名欄位,或移除似乎未使用的建構函式,導致應用程式當機。如果您以類似方式使用任何其他程式庫,請確認這些程式庫不會干擾應用程式最佳化作業,如果會干擾,請避免使用。
請注意,Room 和 Hilt 都會建構應用程式定義的類型,但會使用 codegen 避免需要使用反射。
這個頁面中的內容和程式碼範例均受《內容授權》中的授權所規範。Java 與 OpenJDK 是 Oracle 和/或其關係企業的商標或註冊商標。
上次更新時間:2025-07-27 (世界標準時間)。
[[["容易理解","easyToUnderstand","thumb-up"],["確實解決了我的問題","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["缺少我需要的資訊","missingTheInformationINeed","thumb-down"],["過於複雜/步驟過多","tooComplicatedTooManySteps","thumb-down"],["過時","outOfDate","thumb-down"],["翻譯問題","translationIssue","thumb-down"],["示例/程式碼問題","samplesCodeIssue","thumb-down"],["其他","otherDown","thumb-down"]],["上次更新時間:2025-07-27 (世界標準時間)。"],[],[],null,["# Choose libraries wisely\n\nTo enable app optimization, you must use libraries that are compatible with\nAndroid optimization. If a library isn't configured for Android optimization---for\nexample, if it uses\n[reflection](https://en.wikipedia.org/wiki/Reflective_programming)\nwithout bundling associated keep rules---it might not be a good fit for an\nAndroid app. This page explains why some libraries are better suited for app\noptimization and provides general tips to help you choose.\n\nPrefer codegen over reflection\n------------------------------\n\nGenerally, you should choose libraries that use\n[code generation (*codegen*)](https://en.wikipedia.org/wiki/Code_generation_(compiler))\ninstead of reflection. With codegen, the optimizer can more easily determine\nwhat code is actually used at runtime and what code can be removed. It can be\ndifficult to tell whether a library uses codegen or reflection, but there are\nsome signs---see the [tips](#tips) for help.\n\nFor more information about codegen versus reflection, see\n[Optimization for library authors](/topic/performance/app-optimization/library-optimization#use-codegen).\n\nGeneral tips when choosing libraries\n------------------------------------\n\nUse these tips to help ensure that your libraries are compatible with app\noptimization.\n\n### Check for optimization issues\n\nWhen considering a new library, look through the library's issue tracker and\nonline discussions to check if there are issues related to minification or\nconfiguring app optimization. If there are, you should try to look for\nalternatives to that library. Keep in mind the following:\n\n- The [AndroidX libraries](/jetpack/androidx) and libraries such as [Hilt](/training/dependency-injection/hilt-android) work well with app optimization because they use codegen instead of reflection. When they do use reflection, they provide minimal keep rules to keep only the code that is needed.\n- Serialization libraries frequently use reflection to avoid boilerplate code when instantiating or serializing objects. Instead of reflection-based approaches (such as Gson for JSON), look for libraries that use codegen to avoid these problems, for example by using [Kotlin Serialization](https://github.com/Kotlin/kotlinx.serialization) instead.\n- Libraries that include package-wide keep rules should be avoided if possible. Package-wide keep rules can help resolve errors, but broad keep rules should eventually be refined to keep only the code that is needed. For more information, see [Adopt optimizations incrementally](/topic/performance/app-optimization/adopt-optimizations-incrementally).\n\n### Enable optimization after adding a new library\n\nWhen you add a new library, enable optimization afterwards and check if there\nare errors. If there are errors, look for alternatives to that library or write\nkeep rules. If a library isn't compatible with optimization, file a bug with\nthat library.\n\n### Rules are additive\n\nBe aware that keep rules are additive. This means that certain rules that a\nlibrary dependency includes cannot be removed and might impact the compilation\nof other parts of your app. For example, if a library includes a rule to disable\ncode optimizations, that rule disables optimizations for your entire project.\n\n### Check for use of reflection (advanced)\n\nYou might be able to tell if a library uses reflection from inspecting its code.\nIf the library uses reflection, check that it provides associated keep rules. A\nlibrary is probably using reflection if it does the following:\n\n- Uses classes or methods from the `kotlin.reflect` or `java.lang.reflect` packages\n- Uses the functions `Class.forName` or `classLoader.getClass`\n- Reads annotations at runtime, for example if it stores an annotation value using `val value = myClass.getAnnotation()` or `val value =\n myMethod.getAnnotation()` and then does something with `value`\n- Calls methods using the method name as a string, for example:\n\n // Calls the private `processData` API with reflection\n myObject.javaClass.getMethod(\"processData\", DataType::class.java)\n ?.invoke(myObject, data)\n\n### Filter out bad keep rules (advanced)\n\nYou should avoid libraries with keep rules that retain code that should really\nbe removed. But if you must use them, you can filter the rules out as shown in\nthe following code: \n\n // If you're using AGP 8.4 and higher\n buildTypes {\n release {\n optimization.keepRules {\n it.ignoreFrom(\"com.somelibrary:somelibrary\")\n }\n }\n }\n\n // If you're using AGP 7.3-8.3\n buildTypes {\n release {\n optimization.keepRules {\n it.ignoreExternalDependencies(\"com.somelibrary:somelibrary\")\n }\n }\n }\n\nCase study: Why Gson breaks with optimizations\n----------------------------------------------\n\nGson is a serialization library that often causes issues with app optimization\nbecause it heavily uses reflection. The following code snippet shows how Gson is\ntypically used, which can easily cause crashes at runtime. Notice that when you\nuse Gson to get a list of User objects, you don't call the constructor or pass a\nfactory to the `fromJson()` function. Constructing or consuming app-defined\nclasses without either of the following is a sign that a library might be using\nopen-ended reflection:\n\n- App class implementing a library, or standard interface or class\n- Code generation plugin like [KSP](https://github.com/google/ksp)\n\n class User(val name: String)\n class UserList(val users: List\u003cUser\u003e)\n\n // This code runs in debug mode, but crashes when optimizations are enabled\n Gson().fromJson(\"\"\"[{\"name\":\"myname\"}]\"\"\", User::class.java).toString()\n\nWhen R8 analyzes this code and doesn't see the `UserList` or `User` instantiated\nanywhere, it can rename fields, or remove constructors which don't seem to be\nused, causing your app to crash. If you are using any other libraries in similar\nways, you should check that they won't interfere with app optimization, and if\nthey do, avoid them.\n\nNote that [Room](/training/data-storage/room) and\n[Hilt](/training/dependency-injection/hilt-android) both construct app defined\ntypes, but use codegen to avoid the need for reflection."]]