如何在不使用-keep规则的情况下防止未使用Fragment被ProGuard删除?
解决方案
首先明确:ProGuard会移除它判定为“未被使用”的类,而反射调用的字符串引用不会被它识别为有效引用,所以FragmentName会被移除。-keepnames只保留类名但不会阻止类被移除,所以确实无效。以下是不用宽泛-keep规则(或完全不用ProGuard规则)的可行方案:
方案1:使用精确的-keep规则(推荐)
团队觉得-keep宽泛是因为可能用了-keep class com.bla.bla.**这类包级规则,但你可以针对单个Fragment写精确规则,完全不存在宽泛问题:
# 仅保留指定Fragment类及其无参构造方法(反射需要) -keep class com.bla.bla.FragmentName { public <init>(); }
这个规则只作用于FragmentName一个类,不会影响其他类的混淆和移除,完全符合“不宽泛”的要求,是最规范的解决方式。
方案2:添加代码假引用(无需修改ProGuard规则)
在某个肯定不会被ProGuard移除的类(比如你的Application子类)中添加一段不会实际执行的代码,让ProGuard认为FragmentName被引用了:
class MyApplication : Application() { // 仅用于欺骗ProGuard,不会被执行 @Suppress("UNUSED") private fun dummyReference() { if (false) { FragmentName() } } }
由于if(false)的存在,这段代码会被ProGuard的优化阶段移除,不会影响运行性能,但ProGuard在分析引用关系时会认为FragmentName被使用,从而不会删除该类。缺点是需要维护这段冗余代码。
方案3:使用@Keep注解(代码层面标记)
AndroidX提供了@Keep注解,添加在Fragment类上可以让ProGuard自动保留该类:
import androidx.annotation.Keep @Keep class FragmentName : Fragment() { // 类实现 }
这个注解本质是在编译时生成精确的-keep规则,和方案1效果一致,但更直观,代码可读性更高,不需要手动编写ProGuard规则。
内容的提问来源于stack exchange,提问作者emreesen27
相关产品推荐
相关产品推荐

