Android编译混淆包时报错 {“kind“:“error“,“text“:“java.lang.NullPointerException“,“sources“:[{}],“tool“:“R8“}

我在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的高级选项

### Java程序中处理`NullPointerException`的方法 当遇到`java.lang.NullPointerException`,表明尝试访问的对象为空。对于Ice-Servlet中的连接失败问题,可以采取以下措施来解决问题并增强代码健壮性。 #### 1. 使用全局异常处理器捕获空指针异常 通过定义一个带有@ControllerAdvice注解的类,并利用@ExceptionHandler指定要捕捉的具体异常类型,可以在应用程序级别统一管理未预期到的错误情况[^2]: ```java @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(NullPointerException.class) public ResponseEntity<String> handleNullPointer(Exception ex) { logger.error("发生空指针异常", ex); return new ResponseEntity<>("服务器内部错误,请稍后再试.", HttpStatus.INTERNAL_SERVER_ERROR); } } ``` 此方法允许开发者自定义响应消息以及HTTP状态码给客户端返回更友好的提示信息而不是默认的技术堆栈跟踪。 #### 2. 对可能抛出`NullPointerException`的地方做预防性编程 在调用任何可能导致`NullPointerException`的操作之前先检查对象是否为null: ```java if (object != null && object.getProperty() != null){ // 安全操作 } else { // 处理逻辑 或者 抛出自定义异常 } ``` 这种做法虽然增加了少量冗余代码但是极大地提高了系统的稳定性和可靠性。 #### 3. 利用Optional简化空值判断 Java8引入了`Optional<T>`用于表示可能存在也可能不存在的值,在某些场景下可以帮助减少显式的null检测语句: ```java Optional.ofNullable(object).map(Object::getProperty).orElseThrow(() -> new RuntimeException("Property cannot be found")); ``` 这种方式不仅使代码更加简洁易读而且有效防止了潜在的`NullPointerException`.
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值