Android 打包之 Gradle
一、什么是Gradle
Gradle 是目前非常流行的一个项目构建工具,它不局限于前端或者后端,利用基于jvm的动态语言Groovy,语法灵活,配置简单,方便扩展。
Tips:Gradle是Gradle,AndroidGradle是AndroidGradle,不能混为一谈,可以理解Google为了在AS上使用Gradle来构建Project,自己根据Android项目拓展了Gradle,开发出了AndroidGradle插件,结合了AndroidTools等工具,方便对Android项目进行构建。
详解:https://www.cwiki.us/display/GradleZH/What+is+Gradle
二、Android中的Gradle
Android中的Gradle可以称为gradle插件,要想编译安卓项目,不仅要下载gradle,也要下载Android对应的gradle插件,插件中包含了Gradle和Android一些工具的结合,目的是为了构建Android Project。
贴一张Gradle插件版本号和Gralde版本的对应版本
https://developer.android.google.cn/studio/releases/gradle-plugin
gradle/wrapper/gradle-wrapper.properties 中配置gradle版本,build文件中配置gradle插件版本
classpath 'com.android.tools.build:gradle:3.3.2' ----插件版本
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip ---- gradle版本
1.Android-sync project with gradle file发生了什么?
详解来自:https://developer.android.com/studio/build/dependencies?hl=zh-cn
首先,看一下安卓整个项目结构:
挨个说:
顶层build.gradle文件:
顶层 build.gradle 文件位于项目的根目录下,用于定义适用于项目中所有模块的依赖项。默认情况下,顶层 build 文件使用 plugins 代码块定义项目中所有模块共用的 Gradle 依赖项。此外,顶层 build 文件还包含用于清理 build 目录的代码。以下代码示例说明了创建新项目后可在顶层 build.gradle 文件中找到的默认设置和 DSL 元素。
其中配置项解析:
project/build.gradle project/build.gradlesettings.gradle文件:
主要功能:配置要构建几个模块
settings.gradle模块的gradle文件配置,module/build.gradle
module/build.gradle module/build.gradle小点补充:
Gradle编译后,只会停留到加载各种依赖资源和初步编译代码阶段
常见闭包参数详解:
android DSL
–领域特定语言(domain-specific languages,简称DSL)
defaultConfig{}默认配置,是ProductFlavor类型。它共享给其他ProductFlavor使用
sourceSets{ }源文件目录设置,是AndroidSourceSet类型。
buildTypes{ } BuildType类型
signingConfigs{ }签名配置,SigningConfig类型
productFlavors{ }产品风格配置,ProductFlavor类型
testOptions{ }测试配置,TestOptions类型
aaptOptions{ } aapt配置,AaptOptions类型
lintOptions{ } lint配置,LintOptions类型
dexOptions{ } dex配置,DexOptions类型
compileOptions{ }编译配置,CompileOptions类型
packagingOptions{ } PackagingOptions类型
jacoco{ } JacocoExtension类型。用于设定jacoco版本
splits{ } Splits类型。
android{… }配置了用于android构建的所有参数。这是Android DSL的入口。
2.那么,打包过程是怎样的?
内容整理来自:https://docs.gradle.org/current/userguide/build_lifecycle.html
首先gradle构建生命周期:
初始化阶段(Initialization)
配置阶段(Configuration)
执行阶段(Execution)
初始化阶段:
Gradle支持单工程或者多工程构建,初始化阶段的任务是确定有多少工程需要构建,创建整个项目的层次结构,并且为每一个项目创建一个Project实例对象。
如果是多工程构建,一般都会在根工程目录下声明一个settings.gradle脚本,在脚本中include所有需要参与构建的子工程,通过解析settings.gradle脚本,读取include信息,确定有多少个Project需要构建。
配置阶段:
配置阶段的主要任务是生成整个构建过程的有向无环图
确定了所有需要参与构建的工程后,通过读取解析各个工程对应的build.gradle脚本,构造Task任务,并根据Task的依赖关系,生成一个基于Task的有向无环图TaskExecutionGraph
执行阶段:
通过读取配置阶段生成有向无环图TaskExecutionGraph,按顺序依此执行各个Task,像流水线一样,一步一步构建整个工程,这也是构建过程中最耗时的阶段。
图片来自网络///项目中具体log图片待补充
3.接着,主要task有哪些?
先贴一张打包大致流程图,图片来自网络:
图片来自网络aapt-打包res资源文件,生成R.java、resources.arsc和res文件(二进制&非二进制如res/raw和pic保持原样)
AIDL-Android借口定义语言,Android提供的IPC(Inter Process Communication,进程间通信)的一种独特实现。这个阶段处理.aidl文件,生成对应的Java接口文件。
Java Compiler-通过Java Compiler编译R.java、Java接口文件、Java源文件,生成.class文件。
dex-通过dex命令,将.class文件和第三方库中的.class文件处理生成class.dex。
apkbuilder-将class.dex、resources.arsc、res文件夹(res/raw资源被原封不动的打包进APK之外,其他资源都会被编译或者处理)、OtherResouces(assets文件夹)、AndroidManifest.xml打包进apk文件。
Jarsigner-对上面的apk进行debug或release签名
aipalign-将签名后的pak进行对其处理
图片来自网络Task序列:
1.1分段来说:
1.21-4:
preDebugBuild task主要是得到compile 和 runtime的依赖包并对其做一些版本号,依赖等的校验工作。compileDebugAidl,处理记录aidl和java相关的信息。generateDebugBuildConfig 生成BuildConfig文件
1.3这一部分task主要作用是整理资源合并,分辨率资源文件整理等
其中generateDebugResValues比较重要,它的作用是,配置在gradle中的一些参数,自动整理到res目录中供代码调用,比如:
1.4如果你有该配置的话,执行./gradlew generateDebugResValues
则会生成以下代码:
1.5可以方便的在代码中调用
1.6这一部分task主要任务是一些加jar文件以及载处理依赖关系。其中
compileDebugJavaWithJavac尤为重要:
./gradlew compileDebugJavaWithJavac
一共做了比较重要的几件事:
已知内容(依赖此task之前task)
依赖工程的jar文件
javaPreCompileDebug 任务的输出json文件
项目的java文件
项目生成的R文件,buildconfig文件,aidl等一系列重要文件
做一下输出:
annotationProcessor 生成的java文件
生成的classes文件
下面是transform:
1.7transform vs task
TransformManager.java
1.8addTransform 方法在执行过程中,会将 Transform 包装成一个 AndroidTask 对象,所以transfrom最终会被转换成一个task
./gradlew transformClassesWithDexBuilderForDebug
根据依赖库的jar文件和class文件,生成dex文件。
值得注意的是,既然是生成dex文件,但是为甚么输出后有后缀为jar文件,实际情况是,jar后缀文件解压后,是dex。了解一下就行。
1.9最后就是打包签名输出apk
4.所以我们利用task可以做些什么?
Task一些关键字语法:
http://doc.yonyoucloud.com/doc/wiki/project/GradleUserGuide-Wiki/more_about_tasks/README.html
首先,命令行 gradle task --all 可以看到项目中所有的task
那么我们如何方便看到task之间的依赖关系呢,这里有个插件 task-tree可以辅助我们打印task之间的关系
还有一个 gradle-visteg有兴趣的小伙伴可以看看。
首先纠正一个配置阶段对task的定义的理解:
1.10在配置阶段,会输出那些内容呢?
事实上,会输出,hello,helloworld的内容,那么问题来了,不是不会执行task吗?为什么会输出呢?
这个跟方法块理解不一样,配置阶段是会走一遍task的配置,但是执行是从doFirst开始的,只有在执行task的时候,才会从doFirst入口开始执行。doLast结束。
不论执行什么task,都会完成一遍配置,哪怕clean一下缓存。
afterEvaluate
x0;这个关键字是指配置阶段结束后,之所以所有hook内容放在该关键字处,是因为只有在这里才能拿到所有task的信息,然后进行操作。
1.11gradle.taskGraph.whenReady
x0;这里输出的是当前任务构建需要依赖的所有的task的集合
1.12所以,在配置阶段结束后,我们可以做任何想做的操作,插入自己的task
列举几个项目中的例子:图片待补充。。。
文章中诸多内容借鉴了其他文章,犹豫时间久远未记录原文档地址,希望我们每个技术人都可以向原创致敬。谢谢观看。