Android 项目中依赖项使用项目代码,出现 NoSuchMethodException

2017-11-10 11:09:55 +08:00
 gam2046

其实算是一个比较诡异的需求,但是 leader 交代的,没办法。

情况

有一个普通的 jar 文件(无源码),要求在 Android 上运行,由于这个 jar 有部分方法调用在 Android 上不存在,因此我新建了一个 Android 工程,将这个 jar 作为依赖项引用到项目中。

我在项目中写了该 jar 需要调用的一些方法,转换成了 Android 中存在的操作。随后编译,lint 不通过,当时没注意,随后忽略 lint 报告,直接打包,丢到设备上运行。

设备上程序闪退,通过 logcat 发现,抛出了NoSuchMethodException,位置就在 jar 中调用 Android 中不存在的方法(该方法已经由我在项目中提供了)。随后查看之前的 lint 报告,说 jar 文件中引用的包不存在(即 Android 中不存在,但是已经在我项目中,我重写的)

所以说,第三方 jar 作为 classpath,是不可以使用主程序的代码?但是将程序打包后,第三方 jar 与主程序位于同样的 classpath 下,由同一个 Classloader 加载( Android 中即 PathDexClassLoader ),按理说,不应该出现这样的情况呀。

所以这种情况下,我可以如何做呢?

1884 次点击
所在节点    Java
7 条回复
nicevar
2017-11-10 16:57:40 +08:00
既然抛出了这个异常那就说明你打得包中是不存在这个方法,前面你说的一堆我看的不太明白,不过我觉得你的分析有问题,你应该把 apk 的 dex 拿出来检查一下是否存在这个方法,或者检查打包编译的中间文件,另外我很好奇既然原来的 jar 没有这些方法,你直接补做异常不行吗?还是说你必须要实现这些不存在的方法程序才能正常?
gam2046
2017-11-10 18:24:07 +08:00
@nicevar 反编译查看过,最终文件中是存在的。这样说吧,原来的项目是 A -> B -> J2SE Platform,依次依赖;现在变成 A -> D -> Android Platform。其中 D 就是我现在写的 Android 项目,A 就是那个 jar 文件。原来的依赖路径中有部分方法,在 Android 中并不存在,因此为了让 A 能够顺利在 Android 中启动,我写了 D 项目,将原本 Android 中不存在的方法补上,转成 Android 支持的方法。

那么现在的情况就是,编译是可以顺利通过的。但是运行期间,A 中的调用我在 D 中写的方法,会提示方法不存在。
AckywOw
2017-11-10 18:54:24 +08:00
表示完全晕了,看不懂到底 @@情况...
eminemcola
2017-11-10 20:17:49 +08:00
@gam2046 我猜 jar 中所调用的这个 Java 方法所在的包路径是显式 import 的,在这个路径下可能搜索不到你写在 D 里面的替代方案。可以尝试 catch 一下这个 exception。
jameslan
2017-11-11 06:34:02 +08:00
他的 classloader 出于某种原因不去找你的 mock。试试抢先把 mock load 进来?

但是这么 risky 的解决方案真的要用么。。。。
gam2046
2017-11-11 08:47:31 +08:00
@eminemcola catch 到这个异常以后呢,并没有什么方法处理,原方法的参数我也拿不到,也无法恢复。

@jameslan 按理来说,在 Android 上整个 apk 都是由同一个 PathDexClassLoader 加载,不应该存在这种情况。而且我单步调试过,发现 BootClassLoader 与 PathDexClassLoader 正常,且在调试模式下,IDE 注入的进程是可以正常调用这个方法,只是程序自身无法调用会出现 NoSuchMethodException。至今不理解。
nicevar
2017-11-11 21:22:00 +08:00
@gam2046 你确定那个报异常的方法存在?我指的不是类文件,你这种方案类似的我在好几年前还是 2.3 系统的时候做过,是可行的,现在你描述的情况是 class 明显没有加载进去,另外你分析一下 davlik-cache 生成的 dex 看看
还有种情况,系统之前是否加载过没有这个方法的类,如果有加载过而且改应用是系统应用并且 persistent 是 true,这样就会触发系统的一个 bug,更新了程序内存里面依然加载的是以前的 class,需要断电重启一次

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/405210

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX