转载请注明出处:http://blog.csdn.net/magic_jss/article/details/52521056;
自2015年QQ空间Team放出安卓App热补丁动态修复技术介绍之后,各种热修复技术层出不穷,越来越多的项目也开始尝试这种新技术,也有了一些相对稳定的框架出现。本文主要讲解如何在Eclipse中利用Ant构建工具产生多个dex文件,从而为热修复做准备。若有问题恳请指正,欢迎评论交流!
1、什么是dex多分包?
一般情况下Apk解压后里面都会包含一个classes.dex文件,该文件里面包含了应用的所有.class文件,当创建多个dex文件,并指定某些.class到指定dex文件中就是dex多分包。简言之,一个Apk包含多个.dex文件。
dex多分包的应用场景:
- 解决方法数越界,因为单个dex文件中方法数最多为65536个。超出将抛出DexIndexOverflowException。(方法包括:自定义方法,FrameWork及第三方Jar的所有方法,可通过IDA Pro逆向工具进行查看)。
- 实现热修复,该热修复根据QQ空间Team的热补丁动态修复技术原理进行修复。
2、dex多分包的基本步骤
在ADT中对Android项目进行多分包需要借助Ant构建工具,通过修改构建策略和规则产生多分包,如果你对Ant构建不是很了解可以参考http://blog.csdn.net/magic_jss/article/details/52504131;该步骤讲解主要是根据前篇文章的修改。
Ant打包主要流程:
- 删除gen、bin目录并新建
- 生成R.java类文件
- 编译aidl文件
- 编译源文件生成对应的class文件
- 将.class文件转化成.dex文件
- 打包资源文件
- 生成未签名的apk包
- 对未签名的apk包进行签名
- 对签名的apk包进行字节对齐
在第5步,将.class文件转化成.dex文件,在这里可以修改打包策略产生多个dex文件,修改如下:
主包:classes.dex主要存放Activity、Application等入口类。
从包:classesn.dex主要存放业务逻辑类,可能出现bug的类,后期修复的类。
<!-- 将.class文件转化成.dex文件 -->
<target
name="dex"
depends="compile" >
<echo message="dex..." />
<exec
executable="${dx}"
failonerror="true" >
<arg value="--dex" />
<arg value="--multi-dex" /><!-- 多分包命令 -->
<arg value="--set-max-idx-number=10000" /><!-- 指定单个dex中的方法数 -->
<arg value="--main-dex-list" />
<arg value="${basedir}/c.txt" /><!-- 放到主包里面的class文件 -->
<arg value="--minimal-main-dex" />
<arg value="--output=${bin}" /> <!-- 输出位置 -->
<arg value="${bin}" /><!-- 把bin下所有class打包 -->
<arg value="${libs}" /><!-- 把libs下所有jar打包 -->
</exec>
</target>
c.txt
将该文件里面的class文件打包到classes.dex(主包),一般情况下要保证该文件里面的类不会出现问题。
com/magic/test_hotfix/MainActivity.class
com/magic/test_hotfix/MainActivity$1.class//代表内部类
com/magic/test_hotfix/HotFixUtils.class
在第7步,需要将主包classes.dex添加到未签名的apk中去。
<!-- 根据classes.dex文件和resources.ap_生成未签名的apk包 -->
<target
name="package"
depends="package-res-and-assets" >
<echo message="package..." />
<exec
executable="${apkbuilder}"
failonerror="true" >
<arg value="${unsigned-package}" /><!-- 输出 -->
<arg value="-u" /><!-- u指创建未签名的包 -->
<arg value="-z" /><!-- 资源压缩包 -->
<arg value="${resources-package}" />
<arg value="-f" /><!-- dex文件 -->
<arg value="${bin}/classes.dex" />
<arg value="-rf" />
<arg value="${src}" />
<arg value="-rj" />
<arg value="${libs}" />
<arg value="-nf" />
<arg value="${libs}" />
</exec>
</target>
由于aapt命令在添加或者删除的时候不能是绝对路径,而是相对路径,因此需要拷贝文件到项目的根目录下面,因为我们的脚本是在根目录下面,这样在运行aapt的时候,可以直接操作dex文件了。
<!-- 拷贝文件到项目的根目录下面,因为我们的脚本是在根目录下面,这样在运行aapt的时候,可以直接操作dex文件了 -->
<target
name="copy_dex"
depends="package" >
<echo message="copy dex..." />
<copy todir="." >
<fileset dir="${bin}" >
<include name="classes*.dex" />
</fileset>
</copy>
</target>
添加其他dex文件到未签名Apk中去。这里需要用到ant-contrib-1.0b3.jar,下载地址http://download.csdn.net/detail/magic_jss/9628968;将该Jar放到Ant解压目录的lib目录下面,还需要在build.xml中指定ant-contrib-1.0b3.jar的路径。
<!-- ant-contrib-1.0b3.jar的路径-->
<taskdef
classpath="D:\Ant\apache-ant-1.9.7\lib\ant-contrib-1.0b3.jar"
resource="net/sf/antcontrib/antlib.xml" />
<