APK 文件结构概述:它到底是个什么东西?
咱们直接点,APK 的本质是什么?
说白了,就是一个 ZIP 压缩包。
你完全可以把它当成一个普通的 ZIP 文件来解压。我自己刚开始接触 Android 开发时,就这么干过——把 APK 改名为 .zip,然后直接解压。嗯,里面就是咱们 App 的全部家当。
它被 Google Play 和 Android 系统赋予了特殊的使命和结构要求。
为什么非得用 ZIP 格式?
因为 Android 系统需要一种高效的方式来打包和分发你的代码、资源和签名信息。ZIP 的压缩特性能让包体变小,而它的目录结构又便于系统快速索引文件。我个人觉得,Google 选 ZIP 是很务实的选择——简单、通用、性能好。
好,那 APK 内部到底长什么样?我直接给你们画个结构图,一目了然。
APK 文件核心结构一览
每个目录是干什么的?
来,我一个个给你们拆开讲。
| 目录/文件 | 作用 |
|---|---|
| AndroidManifest.xml | App 的「身份证」。声明包名、组件、权限、版本号等。 |
| META-INF/ | 签名信息 + 完整性校验。一旦被篡改,系统会拒绝安装。 |
| classes.dex | 你的 Java/Kotlin 代码编译后的字节码,一个 APK 可能有多个 .dex。 |
| resources.arsc | 编译后的资源索引表,系统用它快速查找资源 ID 对应的实际文件。 |
| res/ | 原始资源文件。布局(layout/)、图片(drawable/)、字符串(values/) 等。 |
| lib/ | 原生 so 库,按 CPU 架构分目录(armeabi-v7a、arm64-v8a、x86 等)。 |
| assets/ | 可选。存放不经过编译的原始文件,比如一些大字体、视频等。 |
再说说 AndroidManifest.xml
它不是普通的 XML。Android 系统编译时会把可读的 XML 转换成 AXML(Android Binary XML)格式。你直接解压看是乱码,得用 aapt dump badging 命令或者反编译工具才能看。
我给你们演示一下怎么用命令行看 APK 的 manifest:
# 使用 aapt 工具
aapt dump badging your_app.apk
# 或者用 apktool 反编译后看
apktool d your_app.apk -o output_dir
cat output_dir/AndroidManifest.xml
META-INF:签名与安全
这个目录里的文件是 APK 的灵魂。你能安装 App,全靠它。
- MANIFEST.MF — 列出 APK 内所有文件的 SHA1 摘要
- CERT.SF — 对 MANIFEST.MF 再次做摘要,并签名
- CERT.RSA — 开发者证书,包含公钥和签名
为什么要搞这么复杂?
为了保证包体内每个文件都不被篡改。Android 安装时,会逐级验证:先解出 CERT.RSA 里的公钥,再用它验证 CERT.SF 的签名,然后用 CERT.SF 里的摘要对比 MANIFEST.MF 的内容,最后用 MANIFEST.MF 对比实际文件。
classes.dex:你的代码在哪里?
以前一个 APK 只有一个 classes.dex。但现在 App 业务复杂了,方法数轻易超过 65535。这时候就得用 multidex——生成多个 dex 文件,比如 classes.dex、classes2.dex、classes3.dex……
怎么看 APK 里有多少个 dex?
unzip -l your_app.apk | grep classes.*\.dex
我见过最夸张的一个 App,里面有 12 个 dex 文件。那简直是噩梦。
resources.arsc:资源索引的秘密
这个文件就像一个字典。App 里用 R.string.app_name 引用一个资源 ID,系统就去 .arsc 里查这个 ID 对应哪个 res 文件,然后加载它。
.arsc 文件是编译后的二进制格式,不能直接看。但你可以用 aapt dump resources 把它导出成可读的格式。
resConfigs "zh","en" 可以过滤掉其他语言的资源表。
res/ 和 assets/ 有什么不同?
这个问题我经常被问到。直接说区别:
- res/ — 会被编译,资源 ID 由系统分配(R.class),访问速度快。
- assets/ — 不编译,保持原样,用 AssetManager 按文件名读取。
我个人建议:能用 res/ 就用 res/,因为它能利用 Android 的资源管理机制(比如屏幕适配、主题切换)。但如果你需要保持文件原始路径结构(比如放一个数据库文件),就用 assets/。
lib/:小心多架构适配
arm64-v8a — 64 位 ARM 设备,目前主流
armeabi-v7a — 32 位 ARM 设备,逐渐被淘汰
x86 / x86_64 — 模拟器和少数设备
你在 build.gradle 里配置 abiFilters 可以控制只打包哪些架构的 so 库。
android {
defaultConfig {
ndk {
abiFilters "arm64-v8a", "armeabi-v7a"
}
}
}
小节小结
APK 的结构没那么神秘。你可以直接把它当 ZIP 玩。看懂每个目录的用途,是你进行包体优化、问题排查、甚至竞品分析的基础。
下一次我们深入到 AAB(Android App Bundle)的格式里,看看 Google 用它来做什么新花样。不过别急,先把 APK 搞透再说。