Android项目构建Apk包流程
Posted 程序员七哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android项目构建Apk包流程相关的知识,希望对你有一定的参考价值。
好久都没有写博文了,主要是现在的工作重点是前端开发了,最近在学习webpack、weex等前端知识,说起weex,一直都在填坑中,目前还没爬出来了! 好了,回归到本文的主题。之前也写过有关android打包apk方面的博文(使用Ant打包Apk,打包Apk),但是都不够细致,比较笼统的介绍有关Apk打包的过程。所以,本文再次详细描述下,Android项目构建Apk包流程。
一. 前言
当我们使用Android Studio开发Android时,点击运行按钮,就会自动生成一个Apk文件,至于这个Apk是如何生成的,我们并不知道。而这个Apk中包含哪些东西呢?我们还是可以知道的。怀着好奇的心态,我们先来解压一个Apk,看看他的庐山真面目。
随便找一个Apk文件,修改它的后缀名为rar或者zip(其实Apk格式的文件就是一个压缩文件)。如下图所示,
其中 app-debug.rar文件是app-debug.apk修改后缀名后得到的,而app-debug文件夹是app-debug.rar文件解压后生成的,
上面这张截图是app-debug文件夹中的东东,可以看到大致包含5部分:
1. META-INF 文件夹,该文件夹中包含该Apk的签名信息以及该Apk中所有文件的哈希值的计算结果;
2. res文件夹,存放的是资源文件,例如动画、颜色、图片和布局等资源;下面给出一张res文件夹的中文件列表的截图,
3. dex文件,该文件是适用于Dalvik虚拟机的字节码文件,是通过dx工具将class文件转化生成的;
4. resources.arsc,它是一个资源索引表,是由aapt根据res资源文件转化生成的二进制文件;(下面会继续补充该文件的作用);
5. AndroidManifest.xml,这个文件,我们都知道,这是Apk的清单文件,配置了各种权限以及注册Activity、service等组件。(这个文件是压缩处理过的,直接打开是乱码,需要借助其他工具)
二. 打包。
首先来看一张Google官方给出的Apk构建流程,如下图所示,
根据上图,就能大致得出构建Apk的整个流程,
1. aapt工具将res中的资源生成 R.java文件和resources.arsc文件;
2. 如果有aidl,那么aidl工具会将aidl接口转化为java类;
3. javac将所有的java类编译为class文件;
4. 如果有代码混淆,则会加入代码混淆;
5. dx.bat将所有的class文件转化为classes.dex文件;
6. ApkBuild将所有的资源(assets、so、jni)、resources.arcs以及上一步生成的dex文件,打包生成一个apk文件;
7. 对上一步生成的apk进行签名;
8. 使用Zipalign对签名后的apk进行优化。
下面详细分析下各步骤的实现细节。
2.1. 资源打包。(这一部分引用了网上一位博主的内容,详细连接见下文)
开发app时,需要代码和资源。最终生成的apk中代码转换为了dex文件,那么apk文件中的资源是否还是app开发时那些资源文件呢?或者说这些资源文件是否发生了什么变化?引用老罗一张关于资源打包过程以及查找的图:
从上图可以看出:
1). 除了assets和res/raw资源被原装不动地打包进APK之外,其它的资源都会被编译或者处理.xml文件会被编译为二进制的xml,所以解压apk后,无法直接打开xml文件。
2). 除了assets资源之外,其它的资源都会被赋予一个资源ID。
3). 打包工具负责编译和打包资源,编译完成之后,会生成一个resources.arsc文件和一个R.java,前者保存的是一个资源索引表,后者定义了各个资源ID常量,供在代码中索引资源。
4). 应用程序配置文件AndroidManifest.xml同样会被编译成二进制的XML文件,然后再打包到APK里面去。
5). 应用程序在运行时最终是通过AssetManager来访问资源,或通过资源ID来访问,或通过文件名来访问。
在生成的apk中,只有assets和res/raw资源被原装不动地打包进apk。其它的资源都会被编译或者处理。可以使用如下命令查看apk中的文件列表:
aapt l -v apkfile
将apk直接解压后,会发现xml都打不开,提示格式不对,因为其已经变为二进制xml了。另外PNG等图片也会进行相应的优化。还有就是多了一个resources.arsc文件。
更多详细的描述,可以查看Android6.0之App中的资源Rsources.arsc详解这篇文章。
2.2 aidl处理。
aidl,全名Android Interface Definition Language,即Android接口定义语言。是我们在编写进程间通信的时候,定义的接口。输入:aidl后缀的文件。输出:可用于进程通信的C/S端java代码,位于build/generated/source/aidl。
更多有关aidl的描述,请参考这篇Android IPC之AIDL浅谈。
2.3 生成class文件。
这一步是将整个代码中的所有的java文件通过javac编译为class文件.
2.4 生成dex文件。
通过dex工具将项目中所有的class文件(也包含第三方库中的)生成dex文件。
2.5 生成Apk文件。
通过apkbuilder工具 将所有的资源(res和assets)、resources.arsc和dex文件(可能是多个)打包生成Apk文件。
2.6 Apk签名。
上一步生成的Apk文件是没有签名的,也就是说,是无法安装到Android设备中的。android的应用程序需要签名才能在android设备上安装,签名apk文件有两种情况:一种是在调试程序时进行签名,使用eclipse开发android程序时,在编译调试程序时会自己使用一个debug.keystore对apk进行签名;另一种是打包发布时对程序进行签名,这种情况下需要提供一个符合android开发文档中要求的签名文件。签名的方法也分两种:一种是使用jdk中提供的jarsigner工具签名;另一种是使用android源码中提供的signapk工具,它的代码位于android系统源码build\\tools\\signapk目录下。
2.7 Apk优化。
这一步需要使用的工具为zipalign,它位于android-sdk\\tools目录,源码位于android系统源码的build\\tools\\zipalign目录,它的主要工作是将spk包进行对齐处理,使spk包中的所有资源文件距离文件起始偏移为4字节整数倍,这样通过内存映射访问apk文件时速度会更快,验证apk文件是否对齐过的工作由ZipAlign.cpp文件的verify()函数完成,处理对齐的工作则由process()函数完成。
以上就是构建APk的全过程。相信看到这里,小伙伴们对Apk的构建过程更清晰明了了!
三. 补充。
3.1 aapt。
aapt----Android Asset Packaging Tool,即Android资源打包工具,位于SDK的build-tools目录下。该工具的作用是将Android中的res资源生成R.java文件以及将资源文件生成一个二进制文件(resources.arsc)。在打包Apk时,需要使用到该工具。
其中,R.java文件,相信开发Android的小伙伴们都知道,每当我们创建一个资源例如一个字符串,aapt就会在R.java文件中自动生成一个常量(ID),我们在使用某资源时,需要引用该资源对应的R.java文件的资源ID。下面是R.java文件的部分代码截图,
resources.arsc,是aapt工具编译资源时生成的重要文件。App资源能根据配置的变化,索引到相应的资源都要依赖它。例如Android设备语言,屏幕设备尺寸不同时,app通过同样的ID但却能找到不同的资源进行显示。因为 resources.arsc是二进制文件,所以解压后,直接打开是乱码。
总结下:
R.java文件,定义了各个资源ID常量,在使用时需要使用该ID;resources.arsc,保存的是一个资源索引表。
3.2 Dalvik虚拟机。
Dalvik是Google公司自己设计用于Android平台的Java虚拟机,它是Android平台的重要组成部分,支持dex格式(Dalvik Executable)的Java应用程序的运行。dex格式是专门为Dalvik设计的一种压缩格式,适合内存和处理器速度有限的系统。Google对其进行了特定的优化,使得Dalvik具有高效、简洁、节省资源的特点。从Android系统架构图知,Dalvik虚拟机运行在Android的运行时库层。
当你的应用安装在手机上后,应用程序的代码将会以字节码保存,每次冷启动一个应用的时候,Dalvik虚拟机将字节码转换为机器码,然后交给硬件来执行;每次冷启动的时候,Dalvik虚拟机就要重复将字节码转换为机器码的动作,而在这个阶段,我们只能等待,静静的看着应用启动,虽然每次都耗时较长,但是不会占用过多的内存。因此在Android4.4发布时,谷歌推出了新的Android虚拟机ART虚拟机,ART-Android Runtime,即Android运行时。ART虚拟机也是将字节码转换为机器码,但是它和Dalvik虚拟机的工作模式不一样,在ART模式下,当你在安装应用的时候,它就将字节码转换为机器码,并且保存起来,当在启动一个应用的时候,就直接运行这个机器码,因此,启动速度就比较快。
有关Dalvik和ART的介绍,可以参考这篇文章 IT之家学院:认识Android中的Dalvik与ART虚拟机。
Java虚拟机-JVM和Dalvik虚拟机的区别。
1). Java虚拟机运行的是Java字节码(保存在class文件中),Dalvik运行的是Dalvik字节码(由Java字节码转化而来,打包到DEX文件中)。
2). Dalvik可执行文件更小。
由于Android SDK中的dx文件对常量池进行了压缩,使得相同字符串、常量在DEX文件中只出现一次。
3). Java虚拟机与Daivik虚拟机架构不同 。
Java虚拟机基于栈结构,资源开销大,Dalvik虚拟机基于寄存器结构,数据由寄存器直接传递,这样的方式比基于栈结构的方式快得多。
以上内容参考了理解Android虚拟机体系结构。
推荐一篇有关安卓手机为什么越用越卡越慢 问题原因探究。
欢迎大家关注我的公众号
以上是关于Android项目构建Apk包流程的主要内容,如果未能解决你的问题,请参考以下文章
Android 安装包优化资源混淆 ( 资源混淆效果 | APK 构建流程简介 | 资源 ID 组成 )
Android Gradle 插件Gradle 构建工具简介 ② ( Android 项目构建打包流程 | 构建工具发展 -> 手动配置 -> Ant -> Maven -> Gradle )