记一次 NoClassDefFoundError 排查过程
背景
在一次将应用程序打入系统包后,出现了该报错,随之伴随着应用频繁崩溃。
堆栈打印如下:
java stacktrace:
java.lang.NoClassDefFoundError: com.manager.HiBoardMgr$1
at com.manager.HiBoardMgr.<init>(HiBoardMgr.java:322)
at com.manager.HiBoardMgr.getInstances(HiBoardMgr.java:313)
报错原因
developer.android.com/reference/j…
查看 Android 对于该 Error 类型进行的定义是如下:
1、JVM 或 ClassLoader 实例想要加载一个类的定义(一个正常方法调用,或者调用其的 new 关键字来创建实例),但是在这个类中找不到这个类定义。
2、这个类在编译这个将要执行的类时是存在的,但是在执行时无法找到这个类定义。
如何理解上面的定义呢?
对于上面的堆栈打印,我们找不到 HiBoardMgr1 时,这个类定义是有的。也就是说明我们最终的 apk 中是缺少 XBoardMgr$1 这个类的。
排查思路
反编译 apk
反编译 apk 的目的是为了去看一下是否我们的包中是否真的缺少这个类的定义。
简易方法,把 apk 拖入到 AS中,查看它的 classes.dex 文件。
根据一层层报名去找到我们需要的类。
的确是存在的。
ClassNotFound 与 NoClassDefFound 的区别
这里就涉及到了第一个误区与弯路,由于不明确两者的区别,我认为这个类是存在的,即认为我们的 apk 是没有问题的,并不是打包过程中的问题。而是 odex 加载过程、MultiDex 相关的问题,往这个错误方向排查了很久。
这里先解释一下两者的区别:
1、ClassNotFoundException 是当我们在运行时想要去加载(load)一个类时,通过 loadClass() 、 Class.forName() 方法,然后这个类在我们的 classPath 中无法被找到时会报错。
显然我们不属于上面的情况,该报错也不会发生
2、NoClassDefFoundError 是指我们在编译期这个类是存在的,但是在运行时它找不到了,才会报这个错。
我们属于这种情况,应该去做的是为什么会在运行时缺少这个类。
查看 HiBoardMgr$1 的类定义
带有 $1 这种的类名,一般是匿名内部类之类,那么我们就看看我们代码里是怎么使用的这个匿名内部类。
可以看到有三个定义,一个是 HiBoardMgr 的本身对象,另外一个是这个匿名内部类实现的函数,
还有一个全局变量,也是 HiBoardMgr 本身。
那么我们就确认下这个找不到的类定义在代码中是如何实现的:
用到的是 ExceptionCallBack 接口类,那么就是这个类找到不!
并且查一下 dex 文件中存不存在,果然也没有,那么就是这个问题!
反查代码:
由于之前正常版本是正常的,反查一下之前版本,这个类有没有呢?
是有的,并且可以通过 AS 来反查到对应的 jar 包
而目前的代码上面是没有这个库的引用的,那么就反查一下为什么会删除该依赖原因就行。
解决方案
通知其他组通知删除 jar 包中对于第三方 class 的引用,
之后重新打包后问题修复。