谈谈打包之整体介绍

    不管你是做移动开发、前端开发还是后端开发,一定会遇到一个概念——打包,那打包是什么?为什么要打包?以及如何打包呢?

打包是什么,为什么要打包

    在我们日常生活中有哪些常见的打包场景呢?旅行打包、快递打包、礼品打包、资料文档打包,这些打包是指把若干物品在空间上有机的组合在一起,对外呈现为一个整体的过程打包的目的是为了更方便、安全地储存、运输、呈现和使用物品
    在技术领域依旧如此,打包一般指将程序的源代码、资源文件和依赖库等整合成一个整体的过程,打包是为了程序能够更加方便、安全的使用(包括存储、传输、复制、部署、安装、运行等)。

如何打包

    马上过年了,X厂要发放新年大礼包给员工,那制作过程大概是这样的:确定大礼包物品清单以及包装盒样式→确定每个物品摆放位置和顺序→按顺序对物品进行摆放→封包→打上防伪标签,在这个打包过程中,其实还隐藏着另一个流程,那就是每个步骤所需要的环境和工具的准备。在技术领域,打包过程亦是如此,接下来就Android打包过程具体展开:

Android 打包流程

    打包在Android上也叫APK构建,打包就是把Android工程源码变为APK的过程,使用的工具叫Gradle。首先我们得有个认知,每个APK构建的大流程是确定的,只是不同的APP依赖三方库(物品清单一部分)、签名(防伪手段)、使用工具集、打包后存放位置一些自定的地方不同,我们才需要进行对打包控制文件(build.gradle)进行配置。我们觉得打包流程不容易理解是因为我们能够操作的build.gradle等文件都只是配置文件,打包的内部逻辑和流程是对我们隐藏的。打包跟其他任何工作一样都是分为三步走:
    确定工作内容和范围→确定工作分工和顺序→顺序执行每个任务,分别对应上述流程,Android打包也分为三个大的步骤:

  • 初始化(Initialization)
  • 配置(Configuration)
  • 执行(Execution)

我们在setting和build.gradle的配置也是在初始化和配置阶段生效的。下面我们逐个进行介绍

一 、初始化 Initialization

  1. 从工程源码根目录开始查找setting.gradle文件;
  2. 根据setting.gradle文件中的配置来决定哪些模块参与构建;
  3. 首先为根build.gradle生成一个Project实例,接下来为每一个setting.gradle中配置的模块(对应build.gradle)生成一个Project实例,根build.gradle对应的Project是其他build.gradle对应Project的父Project;

注意:
    ① 因为每个build.gradle 都对应一个Project对象,Project对象类似于Android中的 Context,在build.gradle中获取gradle系统方法都是通过内置的project对象或者 getProject() 得到上下文后去获取。
    ② 这个阶段我们配置的task、回调都不会被执行,可以认为是Android中的类加载到内存和实例对象初始化阶段。

二、配置 Configuration

1. 对每个build.gradle对应的Project进行配置,所谓的配置主要是指 ① 下载并初始化插件 ②配置 Android 的编译版本、签名、产品风味等 ③ 下载依赖库 ④注册自定义Task 等,其实这四个主要事情也是一个build.gradle中所有的内容。project配置和执行都是采用广度优先遍历,那就是父project先执行,然后是按照Setting.gradle中顺序执行子project, 这个阶段也叫 Project Evaluation
2. 执行Project evaluation的回调,比如Project.beforeEvalution 、Project.afterEvalution等;
3. 广度优先顺序为每个Project注册task,执行task create回调(如果有),示例如下:

tasks.whenTaskAdded { task ->
    println("hahaha task added call back name= "+task.name)
}

4. 为每一个Task创建一个依赖图,依赖图就是来说明运行这个task要先执行哪些Task的图;
5. 当所有Task的依赖图构建完毕,发送 task构建图完成通知。如果用户定义了回调就可以收到

project.gradle.taskGraph.addTaskExecutionGraphListener(new TaskExecutionGraphListener() {
    @Override
    void graphPopulated(TaskExecutionGraph graph) {
        println("hahaha task TaskExecutionGraph call back")
    }
})

小结:配置就是决定打包的具体内容、使用工具和详细流程。我们大部分在build.gradle中自定义的东西都是在配置阶段生效和执行。

注意:

  • 我们在Android studio执行sync的时候其实就是执行了初始化+配置,我们配置了更多的东西比如更多三方库,更多构建变体 这个sync时间就会更长;
  • 执行任何Task都要重新执行整个项目的初始化和配置阶段,但是如果之前执行过sync或者这两个步骤,而且所有的buid.gradle都未变化,gradle内部会找到之前的缓存并跳过一个个任务的执行。

三、执行:Execution

    其实前面两个阶段都是读入决策和准备阶段,真正做事都是在这个阶段——打包(也叫构建、assemble),根据不同的构建类型和产品风味会有多个打包产物,接下来我们就指对最常见的assembleRelease进行展开。
    本文前面讲所谓打包就是把Android App源码变为APK的过程,Android App工程源码是什么,结构是怎么样的,做Android开发的应该都比较清晰,主要有AndroidManifest配置文件、java代码、kotlin代码、XML、图片、依赖库地址、本地库(jar、aar、so)等,这里就展开介绍;而APK其实就是一个包含编译后的代码和资源的压缩文件,我们找到一个APK(改后缀为.zip)解压得到文件列表如下:

Apk解压缩.png

重点模块介绍如下:
1、META-INF
    META是Meta Data的缩写,元数据是描述数据的数据,APK是一个压缩包,可以认为是一种数据结构,那它的Meta-data就是描述这个APK相关信息的数据,比如使用三方库版本号、JAR包签名(V1签名文件,V2签名等会是签名在包装APK之上,打开后就破坏了这个签名)等。
2、res
    res目录下包含了整个APP工程的资源,就是说打包时候会把一个APP所有模块,依赖库中的资源挑选出来,进行合并 、缩减(比如开启R8优化,工程种没有使用的资源就不会打包到APK),重命名等操作,最后整理出来一份资源放这里,它对应着我们工程目录中的资源目录:
image.png

3、AndroidManifest.xml
    AndroidManifest.xml包含了整个APP所有模块的配置文件,就是说打包时候会把一个APP所有模块、依赖库中的AndroidManifest文件拿出来合并、优化得到这一份总的AndroidManifest配置文件。
4、classes.dex
    classes.dex 文件是 对应Android 工程中的Java和Kotlin源码,是他们经过编译后生成的 Android虚拟机(Dalvik、ART) Executable(可执行) 文件,.dex 后缀就是 Dalvik Excecutable的缩写。
5、resources.arsc
    resources.arsc是所有模块的资源地址映射表合集, 就是说我们在代码中寻找资源是 R.id.XX,但是实际读一个文件是需要文件路径的,这个文件就是把Id映射为路径的表。
6、assets
    assets目录就是我们原来放在各个模块assets目录下的so、图片、apk等文件的合集,这部分是直接移动复制过来,没有优化、没有压缩,所以搞包体积优化这地方是重点。
7、lib目录
    lib目录存储了整个工程的所有so文件,这些so文件来源于本模块、依赖模块、依赖库等地方,如果能够确定每个渠道包对应的设备使用CPU架构,可以在Android默配置、flavor 中配置, 配置后就只打包需要的SO文件,使用这个配置能有效减少APK包体积大小如下图:
cpu架构支持配置.png

接下来就谈谈这些产物是如何生成的,Android官方给出的App打包详细流转图如下:

image.png

注意:

  • 这些流程是配置阶段决定好的,执行阶段就是按找之前决定的进行执行;
  • 只要没有先后顺序的任务都是可以并行执行的,Gradle也是多线程工作的;

名词解释
AAPT
aapt 是Android Asset Packaging Tool的缩写,是编译和打包资源的工具,在SDK的build-tools目录下。

ApkBuilder
ApkBuilder 相当于一个压缩工具,它可以将已经编译好的 Java 代码、资源文件、AndroidManifest.xml等打包成一个 ZIP 文件,即 APK 文件

参考文档

https://docs.gradle.org/current/userguide/build_lifecycle.html#sec:build_phases

https://blog.csdn.net/qq_38056514/article/details/127292335

https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html

https://juejin.cn/post/7113713363900694565

http://tools.android.com/tech-docs/new-build-system/build-workflow

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容