明智地选择库
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
如需启用应用优化,您必须使用与 Android 优化兼容的库。如果某个库未针对 Android 优化进行配置(例如,如果它使用 reflection 但未捆绑关联的 keep 规则),则可能不适合 Android 应用。本页将说明为什么某些库更适合应用优化,并提供一些常规提示来帮助您进行选择。
首选 codegen 而非反射
通常,您应选择使用代码生成 (codegen) 而非反射的库。借助 codegen,优化器可以更轻松地确定运行时实际使用的代码以及可以移除的代码。很难确定库是使用 codegen 还是反射,但有一些迹象可以帮助您判断 - 请参阅提示。
如需详细了解 codegen 与反射,请参阅面向库作者的优化。
选择库的一般提示
请参考以下提示,确保您的库与应用优化兼容。
检查优化问题
在考虑使用新库时,请查看该库的问题跟踪器和在线讨论,检查是否存在与缩减大小或配置应用优化相关的问题。如果有,您应尝试寻找该库的替代方案。请注意以下几点:
- AndroidX 库和 Hilt 等库非常适合应用优化,因为它们使用 codegen 而非反射。当它们使用反射时,会提供最少的保留规则,以仅保留所需的代码。
- 序列化库在实例化或序列化对象时,经常使用反射来避免使用样板代码。请寻找使用 codegen 来避免这些问题的库,而不是基于反射的方法(例如,使用 Gson 处理 JSON)。例如,改用 Kotlin 序列化。
- 应尽可能避免使用包含软件包级保留规则的库。软件包级保留规则有助于解决错误,但最终应优化宽泛的保留规则,以保留仅需的代码。如需了解详情,请参阅逐步采用优化。
在添加新库后启用优化
添加新库后,请启用优化,然后检查是否有错误。如果出现错误,请查找该库的替代方案或编写保留规则。如果某个库不兼容优化,请针对该库提交 bug。
规则是累加的
请注意,保留规则可累加。也就是说,库依赖项包含的某些规则无法移除,并且可能会影响应用其他部分的编译。例如,如果某个库包含停用代码优化的规则,该规则将针对整个项目停用优化。
检查是否使用了反射(高级)
您或许可以通过检查库的代码来确定该库是否使用了反射。如果库使用反射,请检查它是否提供了关联的保留规则。如果库执行以下操作,则可能使用反射:
- 使用
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)
滤除不良的保留规则(高级)
您应避免使用包含会保留应真正移除的代码的 keep 规则的库。不过,如果您必须使用这些规则,可以滤除这些规则,如以下代码所示:
// 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 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-07-27。
[null,null,["最后更新时间 (UTC):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."]]