我在Android项目中升级某个依赖项时,当编译debug版本一切如常,但是打正式混淆包时,出现NullPointerException异常:
AGPBI: {"kind":"error","text":"java.lang.NullPointerException: Cannot read field \"d\" because \"<local0>\" is null","sources":[{}],"tool":"R8"}
1. 分析原因
在Android编译混淆包时遇到NullPointerException错误,通常是由于以下几个原因导致的:
1.1 混淆规则设置不当:
混淆规则设置有冲突或设置不对,导致在编译过程中产生NullPointerException(例如组件化的module混淆规则设置有冲突或设置不对)
1.2 第三方库混淆问题:
混淆后代码有时会混淆项目中的三方库,导致项目异常
1.3 R8工具问题:
R8工具在处理某些情况时可能会抛出NullPointerException(例如当试图访问一个空引用对象的属性或调用空引用对象的方法时,会抛出此异常)
1.4 编码问题:
文件的编码方式可能不是UTF-8,导致编译时出现NullPointerException
1.5 内存不足:
在创建release构建时,可能会遇到内存不足的问题,导致NullPointerException
2. 解决路径
2.1 首先在proguard-rules.pro中去掉该依赖项对应的混淆策略,如:
#-keep class thirdparty.** { *; }
此时报错内容有了变化:
AGPBI: {"kind":"error","text":"java.lang.NullPointerException","sources":[{}],"tool":"R8"}
由于项目中使用java和kotlin混合编程,在app的module中引入了r8工具:
buildscript { repositories { google() mavenCentral() } dependencies { classpath "com.android.tools.build:gradle:7.4.1" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0" // 引入了此依赖项 classpath("com.android.tools:r8:8.2.42") }}
2.2 去掉这个依赖项 classpath("com.android.tools:r8:8.2.42")
此时能看到真正的报错内容了:
AGPBI: {"kind":"error","text":"java.lang.NullPointerException: Cannot read field \"d\" because \"<parameter1>\" is null","sources":[{"file":"D:\\test\\app\\build\\intermediates\\transforms\\sensorsAnalyticsAutoTrack\\release\\74.jar"}],"tool":"R8"}
定位到sensorsAnalyticsAutoTrack,该报错与sensors混淆相关
2.3 升级/降级sensors相关的依赖,我选择升级
将app gradle和module gradle中的相关依赖都升级一下。
至此我以为问题解决了,没想到又报了新的错误:
AGPBI: {"kind":"error","text":"java.lang.NullPointerException: Cannot invoke \"String.length()\" because \"<parameter1>\" is null","sources":[{"file":"C:\\Users\\test\\.gradle\\caches\\transforms-3\\7e9e3809872555124c43eb45d868e6bc\\transformed\\jetified-viewpager2-1.1.0-runtime.jar"}],"tool":"R8"}
该报错与viewpager2的依赖有关,由于我引入的是最新依赖,因此,
2.4 降级viewpager2依赖
此时问题解决,能正常编译混淆版本的包了。
但是此时不能编译非混淆包了,此时出现:
AGPBI: {"kind":"error","text":"com.android.tools.r8.kotlin.H","sources":[{}],"tool":"D8"}com.android.tools.r8.kotlin.H
然后将此依赖又添加回来:classpath("com.android.tools:r8:8.2.42"),此时能够编译混淆/非混淆包了,但是偶尔又会出现新的问题:
AGPBI: {"kind":"error","text":"java.lang.OutOfMemoryError: Java heap space","sources":[{}],"tool":"R8"}
2.5 此时的解决办法有两种:
(1) clean一下project;(2) 将gradle.properties中org.gradle.jvmargs设置为4096或者更大
3 方案总结:
当混淆编译时出现类似"tool":"R8"或者"D8"的问题时,根据上面的解决路径,可以尝试使用下面的方法:
3.1 检查混淆规则:
确保混淆规则设置正确,避免冲突,可以对比一下官网对应的依赖的混淆策略,需要添加的就添加,没有就默认忽略混淆
#-keep class thirdparty.** { *; }
3.2 升级/关闭R8工具
尝试升级R8工具版本,若能解决问题更好;
若不能,就暂时去掉app gradle中dependencies里的R8依赖,然后编译找到具体报错点,升级三方库能解决问题就升级,降级三方库能解决问题就降级;
dependencies { // classpath("com.android.tools:r8:8.2.42")}
问题解决后,如果调试版本不能编译通过,再重新添加该依赖
3.3 检查文件编码
确保所有文件的编码方式为UTF-8
3.4 增加内存分配
如果编译时出现OutOfMemoryError问题:
(1) clean一下project;
(2) 将gradle.properties中org.gradle.jvmargs设置为4096或者更大;
org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8
3.5 禁用高级选项
如果问题仅在构建Lollipop或Marshmallow设备时出现,可以尝试禁用R8的高级选项