动态加载dex这个技术属于看上去高大上,原理很简单,做起来很崩溃的一个玩意。
首先要说的是,这个技术肯定是得掌握才行的。APK加固,热修复,插件化,这些个最近几年比较高大上的玩意,基础原理都是从动态加载dex开始的。有很多博客做过这个课题,有很多写的不错的博客,我就从自己学习的流程给大家说说这玩意。
apk编流程译
首先要理解APK的一个编译流程,google的官网上有着详细的一张图,我选了一个博客上精简过的。
打包整体流程:
- 打包资源文件,生成R.java文件
- 处理aidl文件,生成相应的.java文件
- 编译工程源xs码,生成相应的class文件
- 转换所有的class文件,生成classes.dex文件
- 打包生成apk
- 对apk文件进行签名
- 对签名后的apk进行对齐处理
需要注意点的就是appt打包时候是运行两次,一次编译是将class文件变成.dex一次是把资源文件编译出来。
dex文件的65535根本原因是,dex中统计method个数的类型是个short!无符号边界的话就是就是可以存储最大65535个方法数。
dex文件的结构
- 8位字节的二进制流文件
- 各个数据紧密排列,无间隙,减少了文件体积,加快加载速度
- 整个工程的类信息都存放在一个dex文件中(不考虑dex分包的情况下)
优势 :1.优化常量池 2.dex文件的头文件与索引区部分,dvm可通过这两部分快速查找到对应类及数据
类加载器
这个玩意就是动态加载的核心了
Android加载器
1.PathClassLoader用来加载Android系统类和应用的类和已安装好的APK
2.DexClassLoader支持加载APK、DEX和JAR,也可以从SD卡进行加载。
说几个比较需要注意的点。这两个类加载器的区别在于,DexClassLoader可以传递一个叫optimizedDirectory的参数。从名字上的意思是提供一个存放优化后Dex的文件夹。Dex会经过一次优化,变成ODex,方便内存查找。意思就是DexClassLoader可以解压,PathClassLoader不带解压功能,所以只能加载已安装好的APK,因为安装好的在缓存中有ODex。
另外一个重点就是类加载器是一个双亲委派机制。在加载一个类的时候,它会先让它的父类去加载,如果父类没有加载过,才会自己去加载。作用就是,不会有重复的类被加载。这个机制很关键,QQ空间的热修复方式就是利用了这点。他们把修复类放到Elements数组最前面,这样有bug的Class就会因为这个机制,不再被加载,就达到了修复的目的、
反射机制
这就是动态加载的另一个重要机制了。我一直相信,做好android一定要学好JAVA。用个人理解来说下原理:Java中一个.Class文件就是一个类,JVM是动态加载,一个.Class在被使用时才会加载进内存中。当它被加载到内存后,分配空间还有它的引用。反射就是让内存在已经加载的通过包名,类名去找到这个.Class文件,找到后返回它的引用。所以这个过程很耗资源。
如何写一个反射的代码网上很多,我就只聊一下我的理解。
Android中去动态加载时,记住先去用DexClassLoader把Dex加载完成,再去反射你要的类。如果要进行修复,那就去获取Elements数组,把你的Dex与之前的Dex重新组合。加固的话就是先把Dex进行加密,然后在Application里面,先解密,解密完成之后,在把Dex拼起来。