Markdown版本笔记 | 个人GitHub首页 | 个人博客 | 个人微信 | 个人邮箱 |
---|---|---|---|---|
MyAndroidBlogs | baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
Android APK 打包流程 MDjava
参考android
Android的包文件APK分为两个部分:代码和资源
,因此打包方面也分为资源打包和代码打包两个方面,这篇文章就来分析资源和代码的编译打包原理。git
Android打包流程详图:github
APK总体的的打包流程以下图所示:数组
具体说来:微信
AAPT
工具进行资源文件(包括AndroidManifest.xml、布局文件、各类xml资源等)的打包,生成R.java文件。AIDL
工具处理AIDL文件,生成相应的Java文件。Javac
工具编译项目源码,生成Class文件。DX
工具将全部的Class文件转换成DEX文件,该过程主要完成Java字节码转换成Dalvik字节码,压缩常量池以及清除冗余信息等工做。ApkBuilder
工具将资源文件、DEX文件打包生成APK文件。KeyStore
对生成的APK文件进行签名。ZipAlign
工具进行对齐处理,对齐的过程就是将APK文件中全部的资源文件举例文件的起始距离都偏移4字节的整数倍,这样经过内存映射访问APK文件的速度会更快。上述流程都是Android Studio在编译时调用各类编译命令
自动完成的,具体说来,以下所示:数据结构
一、建立Android工程。app
android create project \
-n packageTest2 \
-a MainActivity \
-k com.package.test2 \
-t android-23 \
-p ./PackageTest2ide
二、编译R文件函数
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
四、编译DEX文件
dx --dex \
--verbose \
--output ./gen/dex/packtest1.dex
./gen/classes/
五、生成APK文件
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
六、APK文件对齐
zipalign -v -p 4 packagetest_unsigned.apk packagetest_aligned_unsigned.apk
七、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
工具来完成的,资源打包主要有如下流程:
AndroidManifest.xml
,得到应用程序的包名称,建立资源表。R.java
中。AaptAssets
对象,收集当前须要编译的资源文件,收集到的资源保存在AaptAssets对象对象中。ResourceTable
中去,用于最终生成资源描述文件resources.arsc
。values
类资源,这类资源包括数组、颜色、尺寸、字符串等值。resources.arsc
。每一个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里存放了各种资源的索引参数和配置信息。
resources.arsc的文件格式以下所示:
注:整个文件都是有一系列chuck(块)构成的,chuck是整个文件的划分单位,每一个模块都是一个chuck,chuck最前面是一个ResChunk_header的结构体,用来描述整个chunk的信息,更多关于索引表格式的细节,能够查阅源码:
resources.arsc 索引表从上至下文件格式依次为:
资源包也被划分为如下几个部分:
从这里能够看到resources.arsc索引表存在不少常量池,常量池的使用目的也很明显,就是提供资源的复用率,减小resources.arsc索引表的体积,提升索引效率。
Android APK是如何来的呢?
怀着这个问题去查资料,发现了下边这张图。
解压一个普通的apk文件后,解压出来的文件包括:
MANIFEST.MF
文件:版本号以及每个文件的哈希值(BASE64),包括资源文件。这个是对每一个文件的总体进行SHA1(hash)。CERT.SF
:这个是对每一个文件的头3行进行SHA1 hash。CERT.RSA
:这个文件保存了签名和公钥证书。使用aapt来打包res资源文件,生成R.java、resources.arsc和res文件(二进制 & 非二进制如res/raw和pic保持原样)
AIDL,Android接口定义语言,Android提供的IPC的一种独特实现。
这个阶段处理.aidl文件,生成对应的Java接口文件。
经过Java Compiler编译R.java、Java接口文件、Java源文件,生成.class文件。
经过dex命令,将.class文件和第三方库中的.class文件处理生成classes.dex。
将classes.dex
、resources.arsc
、res
文件夹(res/raw资源被原装不动地打包进APK以外,其它的资源都会被编译或者处理)、Other Resources(assets
文件夹)、AndroidManifest.xml
打包成apk文件。
对apk进行签名,能够进行Debug和Release 签名。
release mode 下使用 aipalign 进行align,即对签名后的apk进行对齐处理。
Zipalign是一个android平台上整理APK文件的工具,它对apk中未压缩的数据进行4字节对齐,对齐后就可使用mmap
函数读取文件,能够像读取内存同样对普通文件进行操做。若是没有4字节对齐,就必须显式的读取,这样比较缓慢而且会耗费额外的内存。
在 Android SDK 中包含一个名为 zipalign
的工具,它可以对打包后的 app 进行优化。 其位于 SDK 的 \build-tools\23.0.2\zipalign.exe
目录下
2019-2-18