Android APK (Android Application Package) 是 Android 系统中应用程序安装包的文件格式,以 .apk 作为文件后缀名,MIME 类型为 application/vnd.android.package-archive。通过分析 APK 的组成内容和打包流程,我们可以对 Android 应用程序有一个直观和整体的认识。
APK 文件是一个 zip 格式的压缩包,因此可以通过 unzip 命令或者工具进行解压,解压后的内容包含以下几部分:

APK│└──lib/ └──META-INF/└──res/ └──assets/└──AndroidManifest.xml └──resources.arsc└──classes.dex 

可以看到,解压后的目录结构和 IDE (Android Studio 或者 Eclipse) 工程的文件层次结构十分相似。下面解释下这几部分内容:
lib – 用于存放与处理器相关的二进制文件,其内部根据处理器架构不同又细分为 armeabi, x86, mips 等目录。
META-INF – 用于存放 APK 的签名信息。
res – 包含 APK 图形界面和字符串相关的资源文件,对应 IDE 中的 res 目录。
Android 资源文件由如下内容组成:

目录 用途
layout 存放布局文件 (layout-land 文件用于保存横屏布局文件,layout-port 文件用于保存竖屏布局文件)。
menu 存放菜单布局文件,比如 Options Menu, Context Menu, Sub Menu 等
drawable 存放应用中使用的图片资源,也包含帧动画 (Frame Animations) 文件
mipmap 存放应用在 Launcher 中的显示图标
animator 动画资源,主要是属性动画 (Property Animations) 文件
anim 动画资源,主要是补间动画 (Tween Animations) 文件
color 颜色资源,定义 ColorStateList 对象
raw 保存原始文件格式的任意文件,可通过 Resources.openRawResource() 来读取
values 存放字符串资源,比如 dimens, strings, colors, styles, arrays, integers。
xml 应用程序的一些配置信息

Notice:
1. 布局文件命名应尽可能遵循一定的规范,不然文件很多时会感觉混乱,可以参考 android-best-practices 统一布局文件命名。也可以通过 gradle 来实现 layout Nesting,以解决布局文件太多的问题。
2. 为了节省存储空间,存放在 drawable 中的图片资源会经过 aapt 工具编译后再打包,如果不想某些图片资源被优化,可以将其存放在raw目录。
3. APK中 res 不包含 values,为了提高解析和访问效率,values 下的资源文件都会编译进 resource.arsc 中。
4. 资源的组织方式异常丰富,有19个维度,常用的有 smallestWidth, Available width, Available height, Screen size, Screen orientation 等,可以查阅 Providing Resources 小节。

接触过 Web 开发的人都了解 skeleton 的概念。目前看来,Google 定义的资源文件的 skeleton 还是蛮合理的。更多内容可以查阅官网 Resource Types 这一小节。

assets – 用于存放保持原始文件内容的任意文件,比如音频,视频,主题包等。assets 与 res/raw 目录中的文件都会保持原始文件内容。两者不同之处在于,res/raw 中存放的文件在 R.java 文件中有资源 ID,因此在代码中可以通过引用资源 ID 来使用资源。而 assets 中存放的文件没有分配资源 ID,因此 assets 中存放的文件只能通过 AssetManager 来读取。

AndroidManifest.xml – APK 的配置文件,包含以下主要部分:
1. 声明应用的包名,这个包名作为应用安装到 Android 系统中的唯一标识
2. 描述应用中使用的组件 (activity, service, broadcast receiver 和 content provider)
3. 声明应用组件运行时所在的进程
4. 申请应用运行时必须具备的权限
5. 声明应用支持运行的最低 SDK 版本
6. 应用需要链接的库
更多内容可以查阅官网 App Manifest

resources.arsc – APK 的资源索引文件,主要用于提高对应用程序资源的访问效率,该文件生成的具体过程可以参考老罗的 Android应用程序资源的编译和打包过程分析 。

classes.dex – Android 应用程序的代码逻辑部分,由 java 源代码编译生成的可由 Dalvik/ART 虚拟机解析执行的可执行文件。

classes.dex 可以通过 apktool 反编译成 smali 格式文件,或者通过 dex2jar 工具反编译成 .class 文件。

Android 工程编译生成 APK 过程如下图所示:

以上步骤都可由 IDE 自动完成,流程如下:
1. 所有的 XML 文件,都会被 aapt (Android Asset Package Tool) 解析成二进制格式。通过编译时进行 XML 的解析,能够节省运行时的开销。解析后的资源会在 R.java 中保存一个索引 ID。
2. 所有的 java 文件,都会被 JDK 中的 javac 编译成按源代码包结构组织的 .class 字节码文件。然后会再通过 SDK 中提供的 dx 工具转换成可以被 Dalvik/ART 虚拟机解析执行的 classes.dex 文件。
3. 然后,前两步生成的二进制资源文件和 classes.dex 可执行文件,会通过 apkbuilder 工具,使用 zip 压缩算法打包成一个 APK 文件。
4. 最后,通过 jarsigner 工具对 APK 包进行校验和数字签名。为了提高虚拟机访问内存的效率,通过 zipalign 工具对 APK 中的资源进行4字节对齐。最后得到可以分发安装的 APK 文件。

参考学习资料:
1. Android application package
2. Android应用程序开发以及背后的设计思想深度剖析(1)
2. Android资源管理框架(Asset Manager)简要介绍和学习计划

更多相关文章

  1. Android(安卓)AIDL分析
  2. Android之Adapter用法总结(转载)
  3. android学习历程---android工程和目录详解
  4. Android(安卓)studio 一直卡在Gradle:Build Running
  5. Android(安卓)jni代码注册本地方法
  6. android SharedPreferences 记录数据
  7. Android开发规范实战
  8. Android(安卓)studio上面学习Aidl实现复杂数据类型的传递
  9. Android:apk签名

随机推荐

  1. android网络连接
  2. vs xamarin android 监听返回键退出程序
  3. android 打开软键盘 关闭软键盘
  4. Android简单短信发送示例
  5. Android(安卓)Proguard 如何混淆package
  6. Android(安卓)ListView列表分组
  7. android字体闪烁动画(线程)
  8. Android关于SD卡中多层目录的创建
  9. Android(安卓)Localization
  10. Wakelock API详解