我是靠谱客的博主 无限香烟,这篇文章主要介绍学徒浅析Android——斜体、依赖、NoClassDefFoundError,现在分享给大家,希望可以做个参考。

起这个标题是因为我想到了《死亡,爱,机器人》,看起来毫无关联的词汇,实际暗示着蛛丝马迹。最近在定位一个so引用问题时,就遇到了这种现象。异常日志很简单,如下所示:

复制代码
1
java.lang.NoClassDefFoundError: Failed resolution of XXX

NoClassDefFoundError实际上就ClassNotFoundException。常见的类加载异常,如字面意思所说,没有从默认类路径中找到所需的类。实际上我一开始就说出了原因是什么,但是同事一句话让我不得不去证明他是错误的。他说用AS打开apk后可以看到有包含引用的类,而我用反编译工具打开后,却没有看到这类。两边一对比,肯定是有什么未知的事情困扰着我和小伙伴们。

在分析一个apk搭载了哪些依赖时,我们可以在ExtenalLibrary中查看到,也可以通过AS直接查看.dex文件,这两者是相同的,但是在展示内容上,.dex文件实际上是存在提示的。下面给大家看下具体的实例,以一个随意生成的demo为例,默认会引用android系统依赖:androidx。

 

复制代码
1
implemention androidx.appcompat:appcompat:1.1.0

 

执行编译生成一个apk后,通过AS直接打开会发现在.dex文件中包含着一个同样的androidx文件夹,依赖的各级API都可以在文件夹中查询到。打开dex文件的效果如下图所示:

如果我把implemention替换成compileOnly再执行编译,很遗憾没编译成功。出现了各种类似下方的限定:

复制代码
1
Android dependency 'androidx.lifecycle:lifecycle-livedata:2.0.0' is set to compileOnly/provided which is not supported

如果换一个第三方依赖,比如jsoup。implemention 'org.jsoup:jsoup:1.13.1',执行编译后,jsoup在.dex文件中的展示是这样的。

 

jsoup这个文件夹的字体是非斜体的,并且内部子文件夹的名字以及类文件都是非斜体。此时若把implemention替换成compileOnly再执行编译:compileOnly 'org.jsoup:jsoup:1.13.1'

jsoup在.dex文件中的展示是这样的,如下图所示,你会发现关于jsoup的所有文件变成了斜体,而不是原来的普通字体(非斜体)。

 

compileOnly在gradle中表示只编译依赖,不导入dex中。也就是说最终生成的.dex文件是不包含这部分代码的。当你安装上apk后,关于这一部分API的加载是依靠系统提供的类加载路径DexPathList去查找和加载,如果在提供的默认路径中没有对应的API,就会报出NoClassDefFoundError。下述内容就是一个完整的错误日志:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
2021-03-06 12:20:49.304 29027-29027/net.baimulin.demo.statictest E/AndroidRuntime: FATAL EXCEPTION: main     Process: net.baimulin.demo.statictest, PID: 29027     java.lang.NoClassDefFoundError: Failed resolution of: Lorg/jsoup/Jsoup;         at net.baimulin.demo.statictest.MainActivity.onCreate(MainActivity.java:42)         at android.app.Activity.performCreate(Activity.java:7327)         at android.app.Activity.performCreate(Activity.java:7318)         at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)         at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3088)         at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3251)         at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)         at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)         at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)         at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1948)         at android.os.Handler.dispatchMessage(Handler.java:106)         at android.os.Looper.loop(Looper.java:214)         at android.app.ActivityThread.main(ActivityThread.java:7045)         at java.lang.reflect.Method.invoke(Native Method)         at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)      Caused by: java.lang.ClassNotFoundException: Didn't find class "org.jsoup.Jsoup" on path: DexPathList[[zip file "/system/framework/org.apache.http.legacy.boot.jar", zip file "/data/app/net.baimulin.demo.statictest-UR-yA_86Mw3oEdunhBFk5Q==/base.apk"],nativeLibraryDirectories=[/data/app/net.baimulin.demo.statictest-UR-yA_86Mw3oEdunhBFk5Q==/lib/arm64, /data/app/net.baimulin.demo.statictest-UR-yA_86Mw3oEdunhBFk5Q==/base.apk!/lib/arm64-v8a, /system/lib64, /system/vendor/lib64]]         at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)         at java.lang.ClassLoader.loadClass(ClassLoader.java:379)         at java.lang.ClassLoader.loadClass(ClassLoader.java:312)         at net.baimulin.demo.statictest.MainActivity.onCreate(MainActivity.java:42)          at android.app.Activity.performCreate(Activity.java:7327)          at android.app.Activity.performCreate(Activity.java:7318)          at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)          at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3088)          at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3251)          at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)          at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)          at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)          at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1948)          at android.os.Handler.dispatchMessage(Handler.java:106)          at android.os.Looper.loop(Looper.java:214)          at android.app.ActivityThread.main(ActivityThread.java:7045)          at java.lang.reflect.Method.invoke(Native Method)          at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)          at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964) 

总结:

1、一个apk的class。在AS中查看时,.dex中如果是斜体表示的,说明它只是映射,而未存在在apk中。只有执行了implementation/api等compile操作的才会变成非斜体。

2、如果aar中不搭载某些特定的依赖,而只是单纯的使用compileOnly编译通过,同样会出现上述问题。

3、gradle中依赖方式对apk打包的影响表:

依赖方式

所属层级

作用

Implementation

app

该依赖方式所依赖的库不会传递,只会在当前module中生效。

library

该依赖方式所依赖的库不会传递,只会在当前module中生效。

compile

app

该依赖方式会传递所依赖的库,当其他module依赖了该module时,可以使用该module下使用api依赖的库。

library

该依赖方式会传递所依赖的库,当其他module依赖了该module时,可以使用该module下使用api依赖的库。

compileOnly

app

只在编译时有效,不会参与打包

library

只在编译时有效,不会参与打包

api

app

该依赖方式会传递所依赖的库,当其他module依赖了该module时,可以使用该module下使用api依赖的库。

library

该依赖方式会传递所依赖的库,当其他module依赖了该module时,可以使用该module下使用api依赖的库。

runtimeOnly

app

只在生成apk的时候参与打包,编译时不会参与,很少用。

library

只在生成apk的时候参与打包,编译时不会参与,很少用。

 

最后

以上就是无限香烟最近收集整理的关于学徒浅析Android——斜体、依赖、NoClassDefFoundError的全部内容,更多相关学徒浅析Android——斜体、依赖、NoClassDefFoundError内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(88)

评论列表共有 0 条评论

立即
投稿
返回
顶部