Android APK(Android Package)是 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 的组成和打包流程,开发者可以更好地优化应用性能、调试构建问题,并掌握高级构建技术(如模块化、动态交付)。
参考:
1. 深入详解Apk编译打包流程
2. APK 打包流程 ( 文件结构 | 打包流程 | 安装流程 | 安卓虚拟机 )
3. Android 打包流程