如何让@Keep注解实现与ProGuard -keep规则等效的类及成员保留效果
核心原因
R8/ProGuard 对官方@Keep注解的默认处理逻辑和预期的全量保留效果并不一致:
- 默认规则只会把被
@Keep标记的类本身保留下来,不做裁剪、不混淆类名 - 类内部的字段、方法、构造器这些成员,只有自己被单独打上
@Keep才会被保留,类级别的@Keep标记不会自动覆盖所有内部成员
单独打aar的时候看起来生效,是因为库模块构建时默认不会激进裁剪自身对外暴露的公共API成员;但App层级构建时,R8会做全项目的跨模块优化,把没有被App代码实际调用的类成员判定为可混淆对象,就出现了“类留着、成员被混淆”的问题。
原有的-keep,includedescriptorclasses public class com.demo.api.** { *; }规则,是会把匹配到的类的所有内容——包括类本身、所有成员、甚至方法/字段描述符里引用到的关联类——全部保留不混淆,这和默认@Keep的语义有本质区别。
对齐效果的配置方法
- 配置库的Consumer ProGuard传递规则
这类规则会被自动打包进aar,App集成时会自动加载,不需要App端手动改任何配置。- 在库模块的
build.gradle中声明consumer规则文件:android { // 其他原有配置 consumerProguardFiles "consumer-rules.pro" } - 在库模块根目录新建
consumer-rules.pro文件,添加和原keep规则等价的注解匹配规则:# 全量保留所有被@Keep标记的类:保留类本身、所有内部成员,同时连带保留类描述符引用的关联类 -keep,includedescriptorclasses @androidx.annotation.Keep class * { *; }
- 在库模块的
- 清理旧的硬编码保留规则
删掉之前库模块里写死包路径的通配keep规则,后续只需要在需要全量保留的类上打@Keep注解,不需要再单独给每个成员、每个类重复标注。 - 校验规则是否正确打包
打出release版aar后,解压包文件查看META-INF/proguard/目录下的内容,确认上面的keep规则已经被打进aar,避免规则只在库本地构建生效、没有传递到App端。
避坑提醒
- 别把上面的keep规则写到库模块默认的
proguard-rules.pro里:这个文件的规则只在库自身混淆构建时生效,不会被打包进aar传给App,必然会导致集成时规则失效。 - 一定要用官方提供的
androidx.annotation.Keep注解:自己自定义的同名注解R8不认识,不会触发保留逻辑。 - 原规则里的
includedescriptorclasses参数不能省:缺了这个参数,类的方法、字段引用到的其他自定义类还是会被混淆,后续很容易出现反射调用失败、类型转换报错的问题。
内容的提问来源于stack exchange,提问作者tvanlaerhoven
相关产品推荐
相关产品推荐

