平时都是直接用 gradle 打包,今天来分析一下 Android 的打包流程。
目录:
- 流程图
- 具体步骤分析
1. 流程图
2. 具体步骤分析
打包的工具链:
aapt -> aidl -> javac -> dx -> apkbuilder -> jarsigner -> zipalign
现在来一步步分析。
- 2.1 aapt
aapt 为 Android 资源打包工具,目录为 ${ANDROID_SDK_HOME}/platform-tools/appt。
aapt 工具编译 res 资源文件,把大部分 xml 文件编译成二进制文件 (图片文件除外),同时生成 R.Java 文件和 resources.arsc 文件,里面保存了资源的 ID 和在 APK 中的路径。
需要进入应用程序目录,新建一个 gen 目录,没有 gen 目录,aapt 命令将会出现找不到文件的错误。
(1) Android 是如何通过 R 文件引用到真正的资源文件?
aapt 工具对于每个资源文件生成了唯一的 ID,这些 ID 保存在 R.java 文件中。比如:
public final class R {
public static final class anim {
public static final int abc_fade_in=0x7f050000;
public static final int abc_fade_out=0x7f050001;
}
public static final class array {
public static final int smssdk_country_group_a=0x7f090000;
public static final int smssdk_country_group_b=0x7f090001;
}
public static final class bool {
public static final int abc_action_bar_embed_tabs=0x7f0c0000;
public static final int abc_allow_stacked_button_bar=0x7f0c0001;
public static final int abc_config_actionMenuItemAllCaps=0x7f0c0003;
public static final int abc_config_closeDialogWhenTouchOutside=0x7f0c0004;
public static final int abc_config_showMenuShortcutsWhenKeyboardPresent=0x7f0c0005;
public static final int useHardwareAcceleration=0x7f0c0002;
}
public static final class color {
public static final int abc_background_cache_hint_selector_material_dark=0x7f0e00cc;
public static final int abc_background_cache_hint_selector_material_light=0x7f0e00cd;
public static final int abc_btn_colored_borderless_text_material=0x7f0e00ce;
public static final int abc_color_highlight_material=0x7f0e00cf;
public static final int abc_hint_foreground_material_dark=0x7f0e00d0;
public static final int abc_hint_foreground_material_light=0x7f0e00d1;
}
// ...
}
资源 ID 是一个 4 字节的无符号整数,在 R.java 文件中用 16 进制表示。其中,最高的 1 字节表示 Package ID,次高 1 个字节表示 Type ID,最低 2 字节表示 Entry ID。只有一个 ID 如何能引用到实际资源呢?实际上 aapt 工具还生成了一个文件resources.arsc,相当于一个资源索引表,或者你理解成一个 map 也行,map 的 key 是资源 ID,value 是资源在 apk 文件中的路径。resources.arsc 里面还有其他信息,这个就不多说了。通过 R.java 文件和 resources.arsc 配合,就能引用到实际的资源文件。
(2) 为什么要把xml文件编译成二进制文件?
xml 里面都是各种字符,不利于快速遍历。编译成二进制文件,用数字替换各种符号,一方面能快速访问,另一方面也能减少大小。
- 2.2 aidl
aidl 为 Android 接口描述语言转化为 .java 文件的工具,目录为 ${ANDROID_SDK_HOME}/platform-tools/aidl。
如果项目中有使用 aidl,那么就会把 .aidl 文件编译成 .java 文件。
- 2.3 javac
Java Compiler,目录为 ${JDK_HOME}/javac 或者 /usr/bin/javac。
将所有 .java 文件 (包括 R 文件和 aidl 生成的 .java 文件),通过 javac 工具生成 class 文件。
- 2.4 dx
dx 为 转化 .class 文件为 Davik/ART VM 能识别的 .dex 文件的工具,目录为 ${ANDROID_SDK_HOME}/platform-tools/dx。
将生成的 .class 文件和第三方库的 .class 文件通过 dx 工具生成 classes.dex 文件 (如果有分包,那么可能有多个)。
- 2.5 apkbuilder
apkbuilder 为生成 apk 包的工具,目录为 ${ANDROID_SDK_HOME}/tools/opkbuilder。
将 resources.arsc、dex 文件和第三方的非 java 资源包 (.so),通过 apkbuilder 工具生成未签名的 apk 包。
- 2.6 jarsigner
jarsigner 为 .jar 文件的签名工具,目录为 ${JDK_HOME}/jarsigner 或 /usr/bin/jarsigner。
使用 jarsigner 对 apk 进行签名,如果是 debug 模式用默认签名,release 模式用开发者的签名。
- 2.7 zipalign
zipalign 为字节码对齐工具,目录为 ${ANDROID_SDK_HOME}/tools/zipalign。
通过 zipalign 工具对 apk 中的未压缩资源 (图片、视频) 进行 "对齐操作",让资源按 4 字节的边界进行对齐,使得资源访问速度更快。