Android APK组成&编译打包流程详解
Android APK组成&编译打包流程详解
Android APK(Android Package)是Android应用的安装包文件,其组成和打包流程涉及多个步骤和文件结构。本文将详细介绍APK的内部结构、打包流程、构建工具链的演进以及虚拟机的发展历程,帮助开发者更好地理解Android应用的构建过程。
一、APK的组成
APK是一个ZIP格式的压缩包,包含应用运行所需的所有文件。解压后主要包含以下内容:
- classes.dex
- 由Java/Kotlin代码编译后的Dalvik/ART字节码文件。
- 如果方法数超过65536,会生成多个
classes2.dex
、classes3.dex
等(需启用MultiDex)。
- resources.arsc
- 编译后的二进制资源索引表,包含字符串、布局、颜色等资源的映射关系,用于快速查找资源。
- AndroidManifest.xml
- 应用的配置文件(二进制格式),声明包名、权限、组件(Activity/Service等)、最低SDK版本等。
- res/目录
- 存放编译后的资源文件(图片、布局XML、动画等),原始XML会被编译为二进制格式以优化读取效率。
- assets/目录
- 存放原始资源文件(如字体、配置文件),通过
AssetManager
直接访问,不参与资源ID生成。
- lib/目录
- 存放原生库(
.so
文件),按CPU架构分目录(如armeabi-v7a
、arm64-v8a
、x86
)。
- META-INF/目录
- 包含应用签名信息(
MANIFEST.MF
、CERT.SF
、CERT.RSA
),用于验证APK完整性。
- kotlin/目录
- 如果使用Kotlin,会包含Kotlin标准库的相关文件。
- 其他文件
- 如ProGuard/R8生成的映射文件(
mapping.txt
)、AAPT2生成的资源映射等。
二、APK打包流程
Android应用的构建流程通过Gradle和Android构建工具链(如AAPT2、D8、R8等)完成,主要步骤如下:
1. 资源处理
- 工具:AAPT2 (Android Asset Packaging Tool)
- 编译
res/
下的资源文件(XML、图片等),生成resources.arsc
和二进制XML。 - 生成
R.java
文件,为每个资源分配唯一ID。
2. 代码编译
- Java/Kotlin编译
- 将Java/Kotlin源代码编译为
.class
文件(javac
或kotlinc
)。 - DEX转换
- 使用D8或R8工具将
.class
文件转换为Android虚拟机所需的.dex
文件,优化字节码并可能启用代码混淆(通过R8)。
3. 资源与代码合并
- 工具:Android Gradle Plugin
- 合并所有模块的资源文件,处理资源冲突。
- 将
classes.dex
、resources.arsc
、lib/
、assets/
等文件打包到临时APK中。
4. 原生库处理
- 将JNI库(
.so
文件)按CPU架构分类,并打包到APK的lib/
目录。
5. APK签名
- 工具:
apksigner
或jarsigner
- 使用开发者密钥对APK进行签名,确保应用来源可信且未被篡改。
- 生成
META-INF/
目录下的签名文件。
6. APK对齐优化
- 工具:
zipalign
- 对APK中的未压缩文件进行内存对齐(4字节边界),提升运行时加载效率。
zipalign
主要工作是将apk包进行对齐处理。使apk包中的所有资源文件,起始偏移为4字节的整数倍,这样通过mmap内存映射访问apk时的速度会更快。
工具名称 | 功能介绍 | 在操作系统中的路径 |
---|---|---|
aapt | Android资源打包工具 | ${ANDROID_SDK_HOME}/build-tools/30.0.0/aapt |
aidl | Android接口描述语言转化为.java文件的工具 | ${ANDROID_SDK_HOME}/build-tools/30.0.0/aidl |
javac | java Compiler java代码转class文件 | ${JDK_HOME}/javac 或/usr/bin/javac |
dex | 转化.class文件为Davik VM能识别的.dex文件 | ${ANDROID_SDK_HOME}/build-tools/30.0.0/dx |
apkbuilder | 生成apk包 | ???没有找到 |
jarsigner | .jar文件的签名工具 | ${JDK_HOME}/jarsigner 或/usr/bin/jarsigner |
zipalign | 字节码对齐工具 | ${ANDROID_SDK_HOME}/tools/zipalign |
三、详细构建流程图
源代码 (Java/Kotlin) --> 编译 --> .class 文件 --> D8/R8 --> classes.dex
资源文件 (res/, assets/) --> AAPT2 --> resources.arsc + 二进制 XML
原生库 (JNI) --> 按架构分类打包到 lib/
合并所有文件 --> 未签名 APK --> 签名 --> 签名后的 APK --> zipalign 对齐 --> 最终 APK
四、构建工具链演进
- AAPT → AAPT2:支持增量资源编译,提升构建速度。
- DX → D8:更快的DEX编译,更好的字节码优化。
- ProGuard → R8:将代码压缩(Shrinking)、优化(Optimization)、混淆(Obfuscation)与DEX编译合并为一步。
五、优化与扩展
- Android App Bundle (AAB):Google推出的动态分发格式,按设备配置生成优化后的APK。
- Split APKs:根据屏幕密度、ABI等拆分APK,减少用户下载体积。
- 资源混淆:通过工具(如AndResGuard)对资源文件名进行混淆,进一步缩减APK体积。
六、虚拟机演进
虚拟机是一个可以运行class、odex、oat可执行文件的运行环境;
常见的虚拟机有Java虚拟机、Dalvik虚拟机、ART虚拟机;
Java虚拟机:运行的class字节码文件,运行程序时解码class文件中的内容;基于栈架构,需要频繁在栈上读写数据,造成较多的指令分派,更多的内存访问次数,比较耗费CPU时间;
编译时:Java源码,使用javac编译器,编译成class字节码文件;运行时:类加载器通过Java类库验证字节码,验证通过会后进入Java虚拟机,进入Java解释器或即时编译器,然后进入运行时系统,之后进入操作系统,然后调用硬件;
Dalvik虚拟机:基于JIT机制(即时编译技术)
Android 5.0以下使用的虚拟机是Dalvik虚拟机,该虚拟机的可执行文件是dex文件,该文件比class字节码文件更小;JIT(Just In Time)即时编译技术,对应Dalvik虚拟机;基于寄存器架构,通过寄存器间接访问数据,该方式比基于栈架构速度更快;
ART虚拟机:
Android 5.0以上使用的虚拟机是ART虚拟机;AOT(Ahhead Of Time)预编译技术, 对应ART虚拟机;Java虚拟机/Dalvik虚拟机/ART虚拟机都向上层提供了3个接口JNI_GetDefaultJavaVMInitArgs JNI_CreateJavaVM JNI_GetCreatedJavaVMS;虚拟机之间可实现无缝衔接;
Dalvik虚拟机与ART虚拟机区别:虚拟机中有个persist.sys.dvlvik.vm.lib字段,如果该字段存储的是libdvm.so,该虚拟机是Dalvik虚拟机;如果该字段存储的是;ibart.so,该虚拟机是ART虚拟机;
Dalvik虚拟机与ART虚拟机可执行文件:
Dalvik虚拟机加载dex文件加载时不是直接加载dex文件,加载执行的是odex文件,odex文件是通过dexopt工具对dex进行优化生成的;
ART虚拟机加载dex文件时加载的是oat文件,oat文件时通过dex2oat工具对dex文件进行优化生成的;
通过理解APK的组成和打包流程,开发者可以更好地优化应用性能、调试构建问题,并掌握高级构建技术(如模块化、动态交付)。