浅谈Android编译打包流程

作为移动开发的我们平时关注更多的关注业务上的实现和技术的提升,而技术的提升也是为了更好的维护好我们的业务。但是我们很少关注有关apk的一些问题:一个apk的内部构造有哪些?一个apk是怎么从我们的java代码或者kotlin工程编译出来的?以及apk编译需要哪些步骤?如果把apk的编译过程研究透了,那将会继续拓宽我们的技术栈。本文就浅谈一下Android项目编译成apk的内部流程。

apk是啥玩意儿

APK是Android Package的缩写,即Android安装包。.apk文件其实就是一个压缩包,把文件的后缀改成.zip,就可以正常解压,查看内部的相关文件信息了。

有同学问了为什么zip不能安装?当然不能,系统规定的不允许!

系统中有一个叫应用管理器的程序,他会优先扫描搜集系统中所有.apk的文件,标记这些文件是可以被系统加载的。然后当我们点击apk或者系统第一次启动的时候,会复制这些.apk文件到系统指定目录进行校验、解压处理。

apk包含哪些东西

我们把一个apk解压后会得到以下这些文件:

apk解压后

  1. assets资源(不是每个项目都有);
  2. lib包(不是每个项目都有),lib文件夹里面存放的是so动态链接库,so动态链接库是不需要apk打包一些压缩处理的;
  3. META-INF,签名文件夹;
  4. res资源,里面是二进制的xml资源和其他非代码类的资源文件;
  5. AndroidManifest.xml,二进制的;
  6. classes.dex,.dex文件,就是我们写的java代码经过处理得到的;
  7. resources.arsc,记录了所有的应用程序资源目录的信息,将其想象成是一个资源索引表,这个资源索引表在给定资源ID和设备配置信息的情况下,能够在应用程序的资源目录中快速地找到最匹配的资源。

apk打包流程

apk打包流程

如图所示apk打包流程主要分为以下几个阶段:

  1. aapt阶段,打包资源文件,生成R.java文件
  2. aidl阶段,处理aidl文件,生成相应的.java文件
  3. Java Compiler阶段,编译工程源码,生成相应的class文件
  4. dex阶段,转换所有的class文件,生成classes.dex文件
  5. apkbuilder阶段,打包生成apk
  6. Jarsigner阶段,对apk文件进行签名
  7. zipalign阶段,对签名后的apk进行对齐处理,这个过程一般是release包条件下。

每一个阶段,都对应一个工具:

apk打包所需工具

aapt阶段

使用aapt工具来打包res资源文件,生成R.java、resources.arsc和res文件。

aapt传统的打包主要指的是res和Java代码的打包,aapt打包走的是单线程,流水式的任务从上到下进行打包构建。传统的aapt打包,aapt会执行2次,第一次是生成R.java,参与javac编译,第二次是对res里面的资源文件进行编译,最后将Dex文件与编译好的资源文件打包成apk,进行签名。整个流程下来没有任务缓存,没有并发,也没有增量,每次构建都是一个全新的流程。所以每次构建时间也比较恒定,代码量,资源量越多,构建的时间越慢。

其中:

  1. 除了assets和res/raw资源被原装不动地打包进APK包中,其它的资源文件都会被编译或者特殊处理(压缩,过滤等)
  2. 除了assets资源外,其他资源都会被赋予一个资源ID,res/raw也会有资源ID。
  3. 打包工具负责编译和打包资源,编译完成之后,会生成一个resources.arsc文件和一个R.java,前者保存的是一个资源索引表,后者定义了各个资源ID常量。

R文件存的全部是资源ID,而resources.arsc则存储的是所有资源文件的信息表,包括不同设备下的资源准确定位。

R.java文件

我们平时使用最多的findViewById就是在resources.arsc文件下通过R文件中该资源的Id准确定位到该资源所在位置,进一步加载引用。有时候我们资源中有不同大小的同一张图片,虽然引用id一样,也可以在不同的设备下找到准确的图片位置。

项目还未编译打包的时候res完整的有9种目录:

  • animator,这类资源以XML文件保存在res/animator目录下,用来描述属性动画。
  • anim,这类资源以XML文件保存在res/anim目录下,用来描述补间动画。
  • color,这类资源以XML文件保存在res/color目录下,用描述对象颜色状态选择子。
  • drawable,这类资源以XML或者Bitmap文件保存在res/drawable目录下,用来描述可绘制对象。
  • layout,这类资源以XML文件保存在res/layout目录下,用来描述应用程序界面布局。
  • menu,这类资源以XML文件保存在res/menu目录下,用来描述应用程序菜单。
  • raw,这类资源以任意格式的文件保存在res/raw目录下。
  • values,这类资源以XML文件保存在res/values目录下,用来描述一些简单值,例如,数组、颜色、尺寸、字符串和样式值等。
  • xml,这类资源以XML文件保存在res/xml目录下,一般就是用来描述应用程序的配置信息。

编译打包成apk后,apk文件中不包括res/values目录, 这是因为res/values目录下的资源文件的内容经过编译之后,都直接写入到资源项索引表resources.arsc去了。

aidl阶段

aidl工具解析aidl接口定义文件,生成对应的Java文件,供下一步程序调用。对于没有使用到aidl的android工程,可以跳过此步骤。

Java Compiler阶段

这里调用了javac工具编译工程的src目录下所有的java源文件(R.java、Java接口文件、Java源文件),生成的class文件位于工程的bin\classess目录下。

实际开发过程中,也有可能会使用android NDK来编译native代码(android SDK 开发),因此,如果可能的话,这一步还需要使用android NDK编译C/C++代码。

dex阶段

通过dx工具将.class文件和第三方库中的.class文件处理生成classes.dex。dx工具主要的工作是将java字节码转换为dalvik字节码、压缩常量池、消除冗余信息等。

apkbuilder阶段

通过系统构建apk脚本,将classes.dex、resources.arsc、res文件夹(res/raw资源被原装不动地打包进APK之外,其它的资源都会被编译或者处理)、Other Resources(assets文件夹)、AndroidManifest.xml打包成apk文件。

res/raw和assets的相同点:

两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制。

res/raw和assets的不同点:

  1. res/raw中的文件会被映射到R.java文件中,访问的时候直接使用资源ID即R.id.filename;assets文件夹下的文件不会被映射到R.java中,访问的时候需要AssetManager类。
  2. res/raw不可以有目录结构,而assets则可以有目录结构,也就是assets目录下可以再建立文件夹

Jarsigner阶段

通过jarsigner工具对apk文件进行签名。

android的应用程序需要签名才能在android设备上安装,签名apk文件有两种情况:

  1. 在平时开发的时候,在编译调试程序时会自己使用一个debug.keystore对apk进行签名,该文件位于C:\Users\{用户}\.android\目录下。
  2. 正式发布时对应用程序打包进行签名,这种情况下需要提供一个符合android开发文档中要求的签名文件。

zipalign阶段

release模式下通过zipalign工具对签名后的apk进行对齐处理。

Zipalign是一个android平台上整理APK文件的工具,它对apk中未压缩的数据进行4字节对齐,对齐后就可以使用mmap函数读取文件,每个资源的开始位置上都是上一个资源之后的4字节,访问下一个资源就不用遍历了,有点类似于资源数组化,加快访问速度。

整体细节图

apk打包整体细节图

apk安装流程

Android应用安装有如下四种方式:

  1. 系统应用安装—开机时完成,没有安装界面
  2. 网络下载应用安装—通过market应用完成,没有安装界面
  3. ADB工具安装—没有安装界面。
  4. 第三方应用安装—通过SD卡里的APK文件安装,有安装界面,由packageinstaller.apk(程序安装器)应用处理安装及卸载过程的界面。

应用安装涉及到如下几个目录:

  • system/app ---------------系统自带的应用程序,获得adb root权限才能删除
  • data/app ---------------用户程序安装的目录。安装时把apk文件复制到此目录
  • data/data ---------------存放应用程序的数据
  • data/dalvik-cache--------将apk中的dex文件安装到dalvik-cache目录下

在应用管理器中执行.apk安装需要经过以下几步:

第一步:拷贝文件到指定的目录:

在Android系统中,apk安装文件是会被保存起来的,默认情况下,用户安装的apk首先会被拷贝到/data/app目录下,/data/app目录是用户有权限访问的目录,在安装apk的时候会自动选择该目录存放用户安装的文件,而系统出场的apk文件则被放到了/system分区下,包括/system/app,/system/vendor/app,以及/system/priv-app等等,该分区只有ROOT权限的用户才能访问,这也就是为什么在没有Root手机之前,我们没法删除系统出场的app的原因了。

第二步:解压缩apk,保存文件,创建应用的数据目录

为了加快app的启动速度,apk在安装的时候,会首先将app的可执行文件dex拷贝到/data/dalvik-cache目录,缓存起来。然后,在/data/data/目录下创建应用程序的数据目录(以应用的包名命名),存放在应用的相关数据,如数据库、xml文件、cache、二进制的so动态库等。

第三步:解析apk的AndroidManifest.xml文件

Android系统中,也有一个类似注册表的东西,用来记录当前所有安装的应用的基本信息,每次系统安装或者卸载了任何apk文件,都会更新这个文件。这个文件位于如下目录:/data/system/packages.xml。

系统在安装这个apk的过程中,会解析apk的AndroidManifest.xml文件,提取出这个apk的重要信息写入到packages.xml文件中,这些信息包括:权限、应用包名、APK的安装位置、版本、userID等等。由此,我们就知道了为什么一些应用市场和软件管理类的app能够很清楚地知道当前手机所安装的所有app,以及这些app的详细信息了。

以上过程都是由PackageManagerService完成的,PackageManagerService处理各种应用的安装,卸载,管理等工作,开机时由systemServer启动此服务。

第四步:显示快捷方式

如果这些应用程序在PackageManagerService服务注册好了,如果我们想要在Android桌米上看到这些应用程序,还需要有一个Home应用程序,负责从PackageManagerService服务中把这些安装好的应用程序取出来,并以友好的方式在桌面上展现出来,例如以快捷图标的形式。在Android系统中,负责把系统中已经安装的应用程序在桌面中展现出来的Home应用就是Launcher了。

在这里插入图片描述

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值