Android的gradle中compile和provided的区别

来源:互联网 发布:残兵屠龙熔炼数据 编辑:程序博客网 时间:2024/06/05 22:53

先说最多的说法:


compile和provided都是对某个module或者jar等进行依赖。compile会对它进行编译,并将编译后的结果打包到apk中;而provided只会对其进行编译,不会将module或者jar等打包到apk中。对于这个说法,我的理解一直不是很深刻。compile还好说,毕竟编译完成后,同时将编译后的jar放到apk中,等到运行时调用apk中再从apk中加载相应的类型并进行调用。然而,provided只参与编译,却不将编译后的结果打入包中,却没有很好地理解。直到项目中遇上了pre-verify的坑,才对这个说法有了些眉目。


ok~假如现在我们的项目叫Project,并依赖于一个叫Jar的jar包,A中有个类叫Class。如果项目中配置的是 compile Jar,并打成了apk,那么在将apk装入手机中,调用Class时会很自然地调用在apk中的Jar的Class。如果配置的时provided Jar,并打成apk。编译打包会成功,安装到手机中也会成功。但是一旦打开这个app,会报出NoClassDefFoundError的crash。原因是,Jar只是参与了编译,只是让这个apk可以编译成功,但是并没有将这个Jar编译后的结果一起存放入dex中。所以,provided的方式,编译打包和安装都会成功,但是运行时如果沿着android查找类的路径没有找到对应的类的话,就会报错。可以理解成,在编译阶段,我们"借"给编译器一个jar,告诉编译这个jar时provided的,编包时不要将其一起放入apk中。至于app运行时到哪里去找Class这个类,你编译器就别操心了。


但是,等程序运行时,这个Class究竟应该怎么找?这就涉及dexclassloader和pathclassloader的加载问题了,这里不展开。不过有一点值得一提:首先手机root掉,用adb shell进入到手机的/system/framework目录下,应该发现了好多貌似很眼熟的jar包,比如android-support-v13.jar之类的。再想想我们的项目中配置gradle,可能会有类似于provided android-support-v13 类的句子(有可能依赖maven,有可能是本地的jar等等)。这里既然是对v13包provided的,说明v13并没有打入apk中,但是程序还是好好地运行着。原因是,虽然在编译时没有将v13的jar编入apk,但是程序运行时,会先从/system/framework这下面的包中加载,如果加载到了,即使v13没有编入apk中,程序也会照常运行。只是这时,我们运行的是android手机上自带的系统v13 jar包,而我们编译时用的是自己搞来的v13 jar包。系统的jar和自己的jar功能上理论是相同,但是不排除更新等因素。但是大体而言,二者应该是接口一致的。


最后祭奠下项目中的坑:项目中由于是对v13的包compile进去的,并加了混淆,所以很长时间程序都能正常运行~直到有一天,我的处女座的师傅,恩师,大哥让我重新接个第三方的sdk,因为种种原因,不能再对v13的包进行混淆。所以问题来了,新编的apk中包含了v13的jar包,而/system/framework也有一个v13的jar。在android4.4的机型上,就会报出pre-verify重复类的crash,原因在加载v13中的类时,发现了系统和自己apk中两份相同的类(但是在高版本机型上,没有出现这个问题,我想是按照默认加载顺序,直接加载了系统中的v13,而无视了apk自己的v13,所以才侥幸逃过此劫~)。解决方案自然是,compile换成provided~只是在换的过程中,还遇上了依赖传递的问题,这个之后再说。

阅读全文
1 0