likes
comments
collection
share

Android APK打包构建与增量更新

作者站长头像
站长
· 阅读数 55
Android APK打包构建与增量更新

APK编译构建流程

背景

APK编译构建流程是开发者编写的Java、资源等源文件,以及引用的第三方库,被打包到一起,生成最终APK的流程,这里面涉及到多个输入、输出文件和工具。

整体打包流程可以分为7步,如下图所示:

Android APK打包构建与增量更新

汇总表格如下:

步骤作用工具输入输出
1.资源处理将资源文件打包为R.java和编译后的资源文件AAPT原始资源文件R.java, resources.arsc, 编译后的资源
2.AIDL处理根据AIDL文件生成Java文件aidl.aidl文件.java文件
3.Java编译将.java编译为.classjavac.java文件编译后的.class文件
4.DEX合成把第三方库和.class文件合成dexDX,D8,R8,Multidex第三方库,.class文件classes.dex
5.APK打包组装APKapkbuilder原始资源文件未经编译的资源,已编译的资源.so库文件,dex文件
6.签名使用私钥进行签名JarsignerAPK签名后的APK
7.对齐文件对齐,提升在设备上性能zipalign签名APK签名且对齐后的APK

1.资源处理

Android Asset Packaging Tool (AAPT) 用于处理资源文件,并生成R.java,为代码中使用资源能提供索引。同时也生成了编译后的资源文件。

写代码时会自动调用aapt.exe,以下是AAPT执行的主要操作:

  1. 检查AndroidManifest.xml
  2. 引用其它资源包,如系统android命名空间下的资源
  3. 收集资源文件并处理overlay
  4. 加载资源到资源表ResourceTable
  5. 编译values资源并添加到资源表
  6. bag资源分配id,在编译其它资源前,先要给bag资源(如attrs)分配id,以便其它资源引用
  7. 编译xml资源文件:对layoutanimsanimators等资源进行编译,扁平化为二进制文件
  8. 编译AndroidManifest文件,生成资源表
  9. 生成R.java文件
  10. 生成resources.arsc文件

2.AIDL处理

Android Interface Definition Language (AIDL)工具用于在不同进程之间提供开放式接口,它将.aidl文件转换为相应的.java文件。

3.Java编译

将所有.java代码(源文件、AIDL文件、R.java)编译为.class文件。

4.DEX合成

Dalvik Executable (DEX) 文件,由D8DX工具将.class文件、依赖的三方库转换得到,有以下主要职责:

  1. 从.class到.dex:因为Android虚拟机不能直接运行Java字节码,需要转换为Dalvik字节码,最新的工具是R8
  2. 字节码优化:删除死代码(用不到的class),减少dex文件大小并提升运行效率
  3. dex分包:超过65535的话,生成classes.dex, classes2.dex, classes3.dex等,工具是Multidex

5.APK打包

使用apkbuilder或者gradle工具将【未经编译/已编译的资源、.dex文件、so库】打包到一个未签名的APK文件中。

6.签名

未经签名的设备需要经过签名才能在设备上面运行,可使用debug或者release密钥,通过jarsigner工具进行签名。

签名的目的

  • 身份验证:保证应用来源的正当和合法
  • 更新和版本管理:通过签名的应用表示,保证应用更新时不被劫持

V1签名与V2签名

V1V2两种签名模式,从Android 7.0开始,默认使用V2签名,但是为了保证向后兼容,大部分开发者同时使用这两种签名方式。

这两种签名在范围、存储位置有所不同。

  • V1签名:即JAR签名,为APK中每一个文件单独签名
  • V2签名:即完整APK签名,为整个APK文件进行一次签名,更安全且验证效率更高

7.对齐

使用zipalign工具对已签名的APK进行优化,从原理上来讲就是通过格式化zip文件夹中二进制文件的序列,达到提升系统解析速度。zipalign使用了4字节的边界对齐方式来映射内存,是的运行时系统可以直接mmap APK,通过空间换时间的方式提高执行效率。

对齐会改变APK的内容,因此会破坏之前的签名。


增量更新与差分包

在开发下载功能时,尤其是应用商店类APP,增量更新是一个很重要的功能,可以有效减少下载的数据量,提升下载完成率,优化用户使用体验。

什么是增量更新

增量更新基于BSDiff算法,计算两个APK字节码的差异,首先在服务端生成差分patch包,经过下载后,客户端使用同样的BSDiff算法,把patch与老APK合并,生成新APK,进行安装。

  1. 服务器计算并生成差分包
  2. 客户端下载差分包
  3. 客户端合并老APK与差分包,生成新APK
  4. 客户端安装新APK

相比于下载完整的新APK,很明显,增量更新最大的优点是数据传输量更小,下载安装更快。

BSDiff算法详解

Android APK打包构建与增量更新

什么是BSDiff

BSDiff是一种可执行文件的二进制差异构建和应用修补工具。

BSDiff的核心思想

是尽可能多的利用old文件中已有内容,尽可能少的加入新的内容来构建new文件。BSDiff算法的提出,基于可执行文件更新前后二阶变动的两个重要规律:

  1. 没有被更新代码所影响的代码段,在变为可执行文件后,该区域的二进制内容变化是极为稀疏的,即仅仅有部分指针或寄存器变动,通常不会超过一两个字节
  2. 更新后的代码和数据会有很大的位置变动,但这种变动大多为整块的移动,即某一块位置中代码内的指针地址变动均会有相同的位移值

这两个规律可以推导出一个重要事实:相同源代码对应的两个代码块中,大部分内容字节差为0,而少部分需要更新的地址位移数据又存在大量相同的位移值,即源代码相同的代码块差异数据可以被高效压缩。

Android APK打包构建与增量更新

基于此思想,BSDiff算法使用如下步骤来进行生成差异更新包:

  1. 将旧文件二进制使用后缀排序或哈希算法形成一个字符串索引
  2. 使用该字符串索引对比新文件,生成差异文件(difference file)和新增文件(extra file)
  3. 将差异文件和新增文件及必要的索引控制信息压缩为差异更新包

差分过程共生成3个文件,分别是差异文件、更新文件和控制文件。,这三个文件加一起会比新文件略大,但其中控制文件和差异文件是高度结构化的,意味着其均可被高效压缩,所以可以使用类似bzip2等压缩工具将更新包总文件进行非常有效的压缩。

实战:增量更新APK

对增量更新的思考

  • 在生产场景中,由于线上存在多个版本的APP,因此需要针对不同版本生成差分包
  • 如果版本变更过大,可能导致差分包大于new包,此时直接使用new包下载更新即可
  • 出于安全和成功率考虑,需要对old包、new包、patch分别进行md5校验

参考资料

转载自:https://juejin.cn/post/7357911195947057189
评论
请登录