Proguard/R8误删ServiceLoader的findFirst方法,如何阻止该行为?
问题背景
一段Java代码在独立环境运行正常,移植到Android项目后出现崩溃,报错信息如下:
Process: com.example.fragmentbasics, PID: 8642 java.lang.NoSuchMethodError: No virtual method findFirst()Ljava/util/Optional; in class Ljava/util/ServiceLoader; or its super classes (declaration of 'java.util.ServiceLoader' appears in /apex/com.android.art/javalib/core-oj.jar)
经排查确认,是R8混淆优化工具移除了findFirst()方法。尝试在proguard-android.txt中添加以下规则后问题仍未解决:
-keepclassmembers class java.util.ServiceLoader { <methods>; }
可行解决方案
精确锁定目标方法的keep规则
替换原规则为直接指定findFirst()方法,避免R8的模糊匹配逻辑忽略该方法:-keepclassmembers class java.util.ServiceLoader { java.util.Optional findFirst(); }保留ServiceLoader类的所有成员
如果精确规则仍不生效,直接禁止R8对ServiceLoader类进行任何优化,保留其所有字段和方法:-keep class java.util.ServiceLoader { *; }检查SDK版本兼容性
ServiceLoader.findFirst()是Java 9引入的方法,Android API 26(Android 8.0)才开始支持。若项目minSdkVersion低于26,即便R8不删除该方法,低版本设备运行时也会报错。需确认build.gradle配置:android { defaultConfig { minSdkVersion 26 // 或设置为更高兼容版本 } }临时关闭R8全量优化模式
若以上方案均无效,可尝试在gradle.properties中添加以下配置关闭R8全量优化(注意会增加APK体积,仅作为临时调试方案):android.enableR8.fullMode=false
内容的提问来源于stack exchange,提问作者Brad Walker

