Android的包文件APK分为两个部分:代码和资源,所以打包方面也分为资源打包和代码打包两个方面,这篇文章就来分析资源和代码的编译打包原理。
APK整体的的打包流程如下图所示:
具体说来:
上述流程都是Android Studio在编译时调用各种编译命令自动完成的,具体说来,如下所示:
android create project \ -n packageTest2 \ -a MainActivity \ -k com.package.test2 \ -t android-23 \ -p ./PackageTest2
aapt package \ -f \ -J ./gen \ -M ./AndroidManifest.xml \ -S ./res/ \ -I /Users/RadAsm/Library/AndroidSDK/sdk/platforms/android-23/android.jar
javac -source 1.6 \ -target 1.6 \ -cp /Users/RadAsm/Library/AndroidSDK/sdk/platforms/android-23/android.jar \ ./src/com/packtest/test1/MainActivity.java ./src/com/packtest/test1/R.java \ -d ./gen/classes
dx --dex \ --verbose \ --output ./gen/dex/packtest1.dex ./gen/classes/
aapt package -f \ -J ./gen \ -M ./AndroidManifest.xml \ -S ./res/ \ -I /Users/RadAsm/Library/AndroidSDK/sdk/platforms/android-23/android.jar \ -F ./output/res.apk
zipalign -v -p 4 packagetest_unsigned.apk packagetest_aligned_unsigned.apk
apksigner sign --ks my-release-key.jks my-app.apk
以上便是APK打包的整个流程,我们再来总结一下:
理解了整体的流程,我们再来看看具体的细节。
在分析资源的编译和打包之前,我们先来了解一下Android程序包里有哪些资源。
我们知道Android应用程序的设计也是代码与资源相分离的,Android的资源文件可以分为两大类:
assets:assets资源放在主工程assets目录下,它里面保存一些原始的文件,可以以任何方式来进行组织,这些文件最终会原封不动的 地被打包进APK文件中。
获取asset资源也十分简单,如下所示:
InputStream is = getAssets.open("fileName");
res:res资源放在主工程的res目录下,这类资源一般都会在编译阶段生成一个资源ID供我们使用。
res资源包含了我们开发中使用的各种资源,具体说来:
这些资源的含义大家应该都很熟悉,这里就不再赘述。
上述9种类型的资源文件,除了raw类型资源,以及Bitmap文件的drawable类型资源之外,其它的资源文件均为文本格式的XML文件,它们在打包的过程中,会被编译成二进制格式的XML文件。这些二进制格式的XML文件分别有一个字符串资源池,用来保存文件中引 用到的每一个字符串,包括XML元素标签、属性名称、属性值,以及其它的一切文本值所使用到的字符串。这样原来在文本格式的XML文件中的每一个放置字符串的地方在二进制格式的XML文件中都被替换成一个索引到字符串资源池的整数值,这写整数值统一保存在 R.java类中,R.java会和其他源文件一起编译到APK中去。
前面我们提到xml编写的Android资源文件都会编译成二进制格式的xml文件,资源的打包都是由AAPT工具来完成的,资源打包主要有以下流程:
每个Android项目里都有有一个R.java文件,如下所示:
public final class R {
//...
public static final class anim {
public static final int abc_fade_in=0x7f010000;
}
public static final class attr {
public static final int actionBarDivider=0x7f020000;
}
public static final class string {
public static final int actionBarDivider=0x7f020000;
}
//...
}
每个资源项后的整数就是资源ID,资源ID是一个4字节的无符整数,如下所示:
上面提到,最终生成的是资源索引表resources.arsc,Android正是利用这个索引表根据资源ID进行资源的查找,为不同语言、不同地区、不同设备提供相对应的最佳资源。查找和通过Resources和 AssetManger来完成的,这个我们下面会讲。
resources.arsc是一个编译后的二进制文件,在Android Stduio里打开以后是这样的,如下所示:
可以看到resources.arsc里存放l各类资源的索引参数和配置信息。
resources.arsc的文件格式如下所示:
注:整个文件都是有一系列chuck(块)构成的,chuck是整个文件的划分单位,每个模块都是一个chuck,chuck最前面是一个ResChunk_header的结构体,用来描述整个chunk的信息,如下所示:
更多关于索引表格式的细节,可以查阅源码:
resources.arsc索引表从上至下文件格式依次为:
资源包也被划分为以下几个部分:
从这里可以看到resources.arsc索引表存在很多常量池,常量池的使用目的也很明显,就是提供资源的复用率,减少resources.arsc索引表的体积,提高索引效率。
Android打包流程详图
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8