问题:加快 Android 的 Gradle 构建
问题:把模块的公共的变量统一下
问题:如何立即停止编译?
Android工程中的Gradle
下面简述对我们工程最重要的几个Gradle文件,后续也会围绕他们进行详细讲解和补充
(请仔细看代码中的注释哈)
工程Project 中的 build.gradle : 工程控制Gradle编译配置
模块module中的 build.gradle : 控制每个Module的编译过程
gradle.properties : gradle动态参数的配置文件
local.properties : 本地的配置,如:SDK位置
gradle-wrapper.properties :gradle本地代理,声明了指向目录和版本
distributionUrl : 指定gradle版本不存在时,就从Value的地址中去下载。很多时候,我们只要版本换成我们本地存在的gradle版本就可以了
settings.gradle : 配置Gradle中的Module管理
常用Gradle Task
~ 表示 gradlew
gradlew是包装器,自动下载包装里定义好的gradle 版本,保证编译环境统一
gradle 是用本地的gradle
gradlew task -all : 罗列出所有Task ,同时携带具体作用和相互关系
gradlew assembleDebug : 导出所有渠道测试包
~ assembleRelease : 导出所有渠道正式包
~ assembleBaiduDebug --stacktrace : 导出指定渠道测试包,同时携带异常信息
~ --stop : 立即停止编译
~ check : 检查任务
~ build : 执行了 check和assemble
~ clean : 清除所有中间编译结果
————————————————
Gradle是一个构建工具,那么为什么要用构建工具,这就需要先从项目自动化开始讲起。
这个APK构建的过程主要分为以下几步:
1. 通过AAPT(Android Asset Packaging Tool)打包res资源文件,比如AndroidManifest.xml、xml布局文件等,并将这些xml文件编译为二进制,其中assets和raw文件夹的文件不会被编译为二进制,最终会生成R.java和resources.arsc文件。
2. AIDL工具会将所有的aidl接口转化为对应的Java接口。
3. 所有的Java代码,包括R.java和Java接口都会被Java编译器编译成.class文件。
4. Dex工具会将上一步生成的.class文件、第三库和其他.class文件编译成.dex文件。
5. 上一步编译生成的.dex文件、编译过的资源、无需编译的资源(如图片等)会被ApkBuilder工具打包成APK文件。
6. 使用Debug Keystore或者Release Keystore对上一步生成的APK文件进行签名。
7. 如果是对APK正式签名,还需要使用zipalign工具对APK进行对齐操作,这样应用运行时会减少内存的开销。
从以上步骤可以看出,APK的构建过程是比较繁琐的,而且这个构建过程又是时常重复的,如果没有构建工具,手动去完成构建工作,无疑对于开发人员是个折磨,也会产生诸多的问题,导致项目开发周期变长。
在Gradle出现之前,有三个基于Java的构建工具:Ant、Gant和Maven,它们被应用于Java或者Android开发中,我们来看看它们都有什么特点。
————————————————
3.2 采用了Groovy
Gradle这个基于Groovy的DSL,DSL(Domain Specifc Language)意为领域特定语言,只用于某个特定的领域。我们只要按照Groovy的DSL语法来写,就可以轻松构建项目。
Ant和Maven的构建脚本是由XML来编写的,如果XML逻辑复杂内容太多就不容易维护。Gradle可以使用Groovy来实现构建脚本,Groovy 是基于Jvm一种动态语言,它的语法和Java非常相似并兼容Java,因此你无需担心学习Groovy的成本。Groovy在Java的基础上增加了很多动态类型和灵活的特性,比起XML,Gradle更具有表达性和可读性。
Groovy的一些语法
————————————————
Gradle Wrapper
gradle-wrapper.properties 文件有一个简单的目的:决定在构建项目时使用哪个 Gradle 版本。它将随后会自动为你下载并保存该版本的 Gradle 。如果你在 Mac 上使用,运行下面命令 ls ~/.gradle/wrapper/dists/ 你就可以看到 Gradle Wrapper 曾为你下载过的所有 Gradle 版本。
#Mon Feb 17 10:44:51 CST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
3.配置Gradle Wrapper
gradle-wrapper.properties是Gradle Wrapper的属性文件,用来配置Gradle Wrapper,Gradle 4.2.1版本对应的gradle-wrapper.properties如下所示。
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
|
字段的含义如下:
- distributionBase:Gradle解包后存储的主目录。
- distributionPath:distributionBase指定目录的子目录。distributionBase+distributionPath就是Gradle解包后的存放位置。
- distributionUrl:Gradle发行版压缩包的下载地址。
- zipStoreBase:Gradle压缩包存储主目录。
- zipStorePath:zipStoreBase指定目录的子目录。zipStoreBase+zipStorePath就是Gradle压缩包的存放位置。
这里我们最需要关注的是distributionUrl这个字段,如果官方的地址下载不了或者缓慢,可以将这个地址换为其他的镜像地址,或者干脆把Gradle发行版压缩包放在服务器上以供下载。
升级Gradle Wrapper有两种方式
一种是设置Gradle属性文件的distributionUrl属性
第二种是通过运行wrapper任务,推荐使用第二种方式
在Gradle中一个原子性的操作叫做task,简单理解为task是Gradle脚本中的最小可执行单元。
依照惯例,我们从HelloWorld开始,新建一个build.gralde文件,创建2个task:
<span style="color:#000000"><span style="color:#cccccc"><code class="language-go">task helloWorld {
doLast {
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"Hello World!"</span>
}
}
task helloWorld2 <span style="color:#67cdcc"><<</span> {
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"Hello World2!"</span>
}</code></span></span>
<span style="color:#000000"><span style="color:#cccccc"><code class="language-css">> <span style="color:#f8c555">Task</span> :helloWorld
Hello World!
> <span style="color:#f8c555">Task</span> :helloWorld2
Hello World2!</code></span></span>
在 build.gradle 里可以通过 task 关键字来创建Task:
<span style="color:#000000"><span style="color:#cccccc"><code class="language-bash">task myTask(type: SomeType)</code></span></span>
task hello {
doLast {
println 'Hello world!'
}
} |
task hello << {
println 'Hello world!'
} |
<span style="color:#000000"><span style="color:#cccccc"><code class="language-go">task myTask1 {
doLast {
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"doLast in task1"</span>
}
}
task myTask2 <span style="color:#67cdcc"><<</span> {
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"doLast in task2"</span>
}
<span style="color:#999999">//采用 Project.task(String name) 方法来创建</span>
project.<span style="color:#f08d49">task</span>(<span style="color:#7ec699">"myTask3"</span>).doLast {
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"doLast in task3"</span>
}
<span style="color:#999999">//采用 TaskContainer.create(String name) 方法来创建</span>
project.tasks.<span style="color:#f08d49">create</span>(<span style="color:#7ec699">"myTask4"</span>).doLast {
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"doLast in task4"</span>
}
project.tasks.<span style="color:#f08d49">create</span>(<span style="color:#7ec699">"myTask5"</span>) <span style="color:#67cdcc"><<</span> {
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"doLast in task5"</span>
}</code></span></span>
创建Task的参数介绍
<span style="color:#000000"><span style="color:#cccccc"><code class="language-go">task myTask1 <span style="color:#67cdcc"><<</span> {
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"doLast in task1"</span>
}
task myTask2 <span style="color:#67cdcc"><<</span> {
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"doLast in task2"</span>
}
task myTask3 <span style="color:#67cdcc"><<</span> {
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"doLast in task3, this is old task"</span>
}
task <span style="color:#f08d49">myTask3</span>(description: <span style="color:#7ec699">"这是task3的描述"</span>, group: <span style="color:#7ec699">"myTaskGroup"</span>, dependsOn: [myTask1, myTask2], overwrite: <span style="color:#f08d49">true</span>) <span style="color:#67cdcc"><<</span> {
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"doLast in task3, this is new task"</span>
}</code></span></span>
实战演习:
task clean(type: Delete) {
delete rootProject.buildDir
}
Task增量构建
Gradle 支持一种叫做 up-to-date 检查的功能,也就是常说的增量构建。Gradle 的 Task 会把每次运行的结果缓存下来,当下次运行时,会检查输出结果有没有变更,如果没有变更则跳过运行,这样可以提高 Gradle 的构建速度。
重点:Project详解
1. Project类图
当构建进程启动后,Gradle基于build.gradle中的配置实例化org.gradle.api.Project类,先来看看 Project 类的主要结构(节选部分常用):
3. 文件操作
3.1 通过mkdir创建目录
<span style="color:#000000"><span style="color:#cccccc"><code class="language-bash">File mkDir = mkdir("${buildDir}/test");
File mkDir2 = mkdir("${buildDir}/test2")
println "检测目录是否创建成功:${mkDir.exists()}, ${mkDir2.exists()}"</code></span></span>
3.2 通过file、files 定位文件
<span style="color:#000000"><span style="color:#cccccc"><code class="language-dart"><span style="color:#999999">//定位单个文件,参数可以是相对路径、绝对路径</span>
File testDir <span style="color:#67cdcc">=</span> <span style="color:#f08d49">file</span>(<span style="color:#7ec699">"${buildDir}/test"</span>)
println <span style="color:#7ec699">"文件定位是否成功:${testDir.exists()}"</span>
<span style="color:#999999">//文件集合,Gradle里用 FileCollection 来表示</span>
FileCollection fileCollection <span style="color:#67cdcc">=</span> <span style="color:#f08d49">files</span>(<span style="color:#7ec699">"${buildDir}/test"</span>, <span style="color:#7ec699">"${buildDir}/test2"</span>)
println <span style="color:#7ec699">"-------对文件集合进行迭代--------"</span>
fileCollection.each {File f <span style="color:#67cdcc">-</span><span style="color:#67cdcc">></span>
println f.name
}
println <span style="color:#7ec699">"-------文件迭代结束-------"</span>
<span style="color:#999999">//获取文件列表</span>
Set<span style="color:#67cdcc"><</span>File<span style="color:#67cdcc">></span> <span style="color:#cc99cd">set</span> <span style="color:#67cdcc">=</span> fileCollection.<span style="color:#f08d49">getFiles</span>()
println <span style="color:#7ec699">"文件集合里共有${set.size()}个文件"</span></code></span></span>
3.3 通过fileTree创建文件树
Gradle里用 ConfigurableFileTree 来表示文件树,文件树会返回某个目录及其子目录下所有的文件,不包含目录。
<span style="color:#000000"><span style="color:#cccccc"><code class="language-go"><span style="color:#999999">//先在build目录下创建3个txt文件</span>
<span style="color:#f08d49">file</span>(<span style="color:#7ec699">"${buildDir}/t1.txt"</span>).<span style="color:#f08d49">createNewFile</span>()
<span style="color:#f08d49">file</span>(<span style="color:#7ec699">"${buildDir}/test/t2.txt"</span>).<span style="color:#f08d49">createNewFile</span>()
<span style="color:#f08d49">file</span>(<span style="color:#7ec699">"${buildDir}/t1.java"</span>).<span style="color:#f08d49">createNewFile</span>()
<span style="color:#999999">//1.通过一个基准目录创建文件树,参数可以是相对目录,也可以是绝对目录,与file()方法一样</span>
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"通过基准目录来创建文件树"</span>
ConfigurableFileTree fileTree1 <span style="color:#67cdcc">=</span> <span style="color:#f08d49">fileTree</span>(<span style="color:#7ec699">"build"</span>)
<span style="color:#999999">//添加包含规则</span>
fileTree1.include <span style="color:#7ec699">"*.txt"</span>, <span style="color:#7ec699">"*/*.txt"</span>
<span style="color:#999999">//添加排除规则</span>
fileTree1.exclude <span style="color:#7ec699">"*.java"</span>
fileTree1.each { f <span style="color:#67cdcc">-</span><span style="color:#67cdcc">></span>
<span style="color:#cc99cd">println</span> f
}
<span style="color:#67cdcc">/</span><span style="color:#67cdcc">/</span><span style="color:#f08d49">2.</span>通过闭包来创建文件树
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"通过闭包来创建文件树"</span>
ConfigurableFileTree fileTree2 <span style="color:#67cdcc">=</span> <span style="color:#f08d49">fileTree</span>(<span style="color:#7ec699">"build"</span>) {
include <span style="color:#7ec699">"*/*.txt"</span>, <span style="color:#7ec699">"*.java"</span>
exclude <span style="color:#7ec699">"*.txt"</span>
}
fileTree2.each { f <span style="color:#67cdcc">-</span><span style="color:#67cdcc">></span>
<span style="color:#cc99cd">println</span> f
}
<span style="color:#999999">//3.通过map配置来创建文件树,可配置的选项有:dir: ''、include: '[]、exclude: []、includes: []、excludes: []</span>
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"通过Map来创建文件树"</span>
def fileTree3 <span style="color:#67cdcc">=</span> <span style="color:#f08d49">fileTree</span>(dir: <span style="color:#7ec699">"build"</span>, includes: [<span style="color:#7ec699">"*/*.txt"</span>, <span style="color:#7ec699">"*.java"</span>])
fileTree3 <span style="color:#67cdcc">=</span> <span style="color:#f08d49">fileTree</span>(dir: <span style="color:#7ec699">"build"</span>, exclude: <span style="color:#7ec699">"*.java"</span>)
fileTree3.each { f <span style="color:#67cdcc">-</span><span style="color:#67cdcc">></span>
<span style="color:#cc99cd">println</span> f
}</code></span></span>
3.4 复制文件
复制文件需要使用复制任务(Copy)来进行,它需要指定要复制的源文件和一个目标目录,复制的规则都是定义在 CopySpec 接口里的,更详细的说明可参见 API 文档。
<span style="color:#000000"><span style="color:#cccccc"><code class="language-tsx">task <span style="color:#f08d49">testCopyFile</span>(<span style="color:#cc99cd">type</span>: Copy) {
<span style="color:#999999">//复制build目录下的所有文件</span>
<span style="color:#cc99cd">from</span> <span style="color:#7ec699">"build"</span>
<span style="color:#999999">//复制单独的某个文件</span>
<span style="color:#cc99cd">from</span> <span style="color:#7ec699">"test.java"</span>
<span style="color:#999999">//复制某个文件树下的所有文件</span>
<span style="color:#cc99cd">from</span> <span style="color:#f08d49">fileTree</span>(<span style="color:#7ec699">"build"</span>)
include <span style="color:#7ec699">"*.txt"</span>
include <span style="color:#7ec699">"*.java"</span>
exclude <span style="color:#7ec699">"t1.txt"</span>
<span style="color:#999999">//指定目标目录</span>
into <span style="color:#7ec699">"outputs"</span>
<span style="color:#999999">//对复制的文件重命名:通过闭包来映射</span>
rename { fileName <span style="color:#67cdcc">-</span><span style="color:#67cdcc">></span>
<span style="color:#999999">//增加 rename_ 前缀</span>
<span style="color:#cc99cd">return</span> fileName.<span style="color:#f08d49">endsWith</span>(<span style="color:#7ec699">".java"</span>) <span style="color:#67cdcc">?</span> <span style="color:#7ec699">"rename_"</span> <span style="color:#67cdcc">+</span> fileName : fileName
}
<span style="color:#999999">//通过正则来映射文件名:abctest.java 会映射成 abchjy.java</span>
rename <span style="color:#7ec699">'(.*)test(.*)'</span>, <span style="color:#7ec699">'$1hjy$2'</span>
}
</code></span></span>
3.5 删除文件
<span style="color:#000000"><span style="color:#cccccc"><code class="language-cpp"><span style="color:#999999">//删除 build 目录下所有文件</span>
<span style="color:#cc99cd">delete</span>(<span style="color:#7ec699">"${buildDir}"</span>)</code></span></span>
4.1 通过 settings.gradle 引入子项目
<span style="color:#000000"><span style="color:#cccccc"><span style="color:#404040"><code class="language-php"><span style="color:#cc99cd">include</span> <span style="color:#7ec699">":app"</span>, <span style="color:#7ec699">":library"</span></code></span></span></span>
<span style="color:#000000"><span style="color:#cccccc"><span style="color:#404040"><code class="language-go"><span style="color:#999999">//在根目录 build.gradle 里增加</span>
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"-----root file config-----"</span>
<span style="color:#999999">//在 app/build.gradle 里增加</span>
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"-----app config-----"</span>
<span style="color:#999999">//在 library/build.gradle 里增加</span>
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"-----library config-----"</span></code></span></span></span>
这是一个多项目构建的简单例子,可以看到结构与我们的 Android 项目是类似的。
Gradle 在运行时会读取并解析 settings.gradle 文件,生成一个 Settings对象,然后从中读取并解析子项目的 build.gradle 文件,
然后为每个 build.gradle 文件生成一个 Project 对象,进而组装一个多项目构建出来。
Settings 里最核心的API就是 include 方法,通过该方法引入需要构建的子项目。
在根项目里可以对子项目进行配置:
<span style="color:#cccccc"><code class="language-dart"><span style="color:#999999">//通过path定位并获取该 Project 对象</span>
<span style="color:#f08d49">project</span>(path: String): Project
<span style="color:#999999">//通过path定位一个Project,并进行配置</span>
<span style="color:#f08d49">project</span>(path: String, config: Closure): Project
<span style="color:#999999">//针对所有项目进行配置</span>
<span style="color:#f08d49">allprojects</span>(config: Closure)
<span style="color:#999999">//针对所有子项目进行配置</span>
<span style="color:#f08d49">subprojects</span>(config: Closure)</code></span>
我们修改根目录 build.gradle 文件如下:
<span style="color:#cccccc"><code class="language-go"><span style="color:#cc99cd">println</span> <span style="color:#7ec699">"-----root file config-----"</span>
<span style="color:#999999">//配置 app 项目</span>
<span style="color:#f08d49">project</span>(<span style="color:#7ec699">":app"</span>) {
ext {
appParam <span style="color:#67cdcc">=</span> <span style="color:#7ec699">"test app"</span>
}
}
<span style="color:#999999">//配置所有的项目</span>
allprojects {
ext {
allParam <span style="color:#67cdcc">=</span> <span style="color:#7ec699">"test all project"</span>
}
}
<span style="color:#999999">//配置子项目</span>
subprojects {
ext {
subParam <span style="color:#67cdcc">=</span> <span style="color:#7ec699">"test sub project"</span>
}
}
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"allParam = ${allParam}"</span></code></span>
ext是干嘛用的?
常见用法
<span style="color:#000000"><span style="color:#cccccc"><code class="language-groovy">ext {
compileSdkVersion = 25
buildToolsVersion = "26.0.0"
minSdkVersion = 14
targetSdkVersion = 22
appcompatV7 = "com.android.support:appcompat-v7:$androidSupportVersion"
}</code></span></span>
然后在app模块下,通过
<span style="color:#000000"><span style="color:#cccccc"><code class="language-groovy">rootProject.ext.compileSdkVersion
rootProject.ext.buildToolsVersion</code></span></span>
这种方式来访问在根目录build.gradle下定义的变量。
implementation(name: 'WbCloudOcrSdk-pro-release-v2.2.29', ext: 'aar')
subprojects的用处
5. 构建脚本配置
5.1 buildscript
配置该 Project 的构建脚本的 classpath,在 Andorid Studio 中的 root project 中可以看到:
<span style="color:#cccccc"><code class="language-bash">buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
}
}</code></span>
5.2 apply
我们通过该方法使用插件或者是其他脚本,options里主要选项有:
- from: 使用其他脚本,值可以为 Project.uri(Object) 支持的路径
- plugin:使用其他插件,值可以为插件id或者是插件的具体实现类
例如:
<span style="color:#404040"><span style="color:#cccccc"><code class="language-csharp"><span style="color:#999999">//使用插件,com.android.application 就是插件id</span>
apply plugin: <span style="color:#7ec699">'com.android.application'</span>
<span style="color:#999999">//使用插件,MyPluginImpl 就是一个Plugin接口的实现类</span>
apply plugin: MyPluginImpl
<span style="color:#999999">//引用其他gradle脚本,push.gradle就是另外一个gradle脚本文件</span>
apply <span style="color:#cc99cd">from</span>: <span style="color:#7ec699">'./push.gradle'</span></code></span></span>
6. 属性
6.1 Gradle属性
在与 build.gradle 文件同级目录下,定义一个名为 gradle.properties 文件,里面定义的键值对,可以在 Project 中直接访问。
<span style="color:#404040"><span style="color:#cccccc"><code class="language-cpp"><span style="color:#999999">//gradle.properties里定义属性值</span>
company<span style="color:#67cdcc">=</span><span style="color:#7ec699">"hangzhouheima"</span>
username<span style="color:#67cdcc">=</span><span style="color:#7ec699">"hjy"</span></code></span></span>
在 build.gradle 文件里可以这样直接访问:
<span style="color:#404040"><span style="color:#cccccc"><code class="language-bash">println "company = ${company}"
println "username = ${username}"</code></span></span>
6.2 扩展属性
还可以通过 ext 命名空间来定义属性,我们称之为扩展属性。
<span style="color:#404040"><span style="color:#cccccc"><code class="language-go">ext {
username <span style="color:#67cdcc">=</span> <span style="color:#7ec699">"hjy"</span>
age <span style="color:#67cdcc">=</span> <span style="color:#f08d49">30</span>
}
<span style="color:#cc99cd">println</span> username
<span style="color:#cc99cd">println</span> ext.age
<span style="color:#cc99cd">println</span> project.username
<span style="color:#cc99cd">println</span> project.ext.age</code></span></span>
Extension
Android的Extension
先看个 Android 的常规配置,以下是我的项目配置,截图如下所示:
NamedDomainObjectContainer的使用场景
<span style="color:#000000"><span style="color:#cccccc"><span style="color:#404040"><code class="language-csharp">android {
buildTypes {
release {
<span style="color:#999999">// 是否开启混淆</span>
minifyEnabled <span style="color:#cc99cd">true</span>
<span style="color:#999999">// 开启ZipAlign优化</span>
zipAlignEnabled <span style="color:#cc99cd">true</span>
<span style="color:#999999">//去掉不用资源</span>
shrinkResources <span style="color:#cc99cd">true</span>
<span style="color:#999999">// 混淆文件位置</span>
proguardFiles <span style="color:#f08d49">getDefaultProguardFile</span>(<span style="color:#7ec699">'proguard-android.txt'</span>), <span style="color:#7ec699">'proguard-rules.pro'</span>
<span style="color:#999999">// 使用release签名</span>
signingConfig signingConfigs.hmiou
}
debug {
signingConfig signingConfigs.hmiou
}
}
}</code></span></span></span>
- debug、release 是可以修改成其他名字的,你可以替换成你喜欢的名字;
Android Gradle学习(七):Gradle构建生命周期
Gradle 进行构建,都要经过3个生命周期阶段:
- 初始化阶段
- 配置阶段
- 执行阶段
Gradle 提供了很多生命周期监听方法,可以在各个阶段 Hook 指定的任务。
build.gradle 代码:<span style="color:#000000"><span style="color:#cccccc"><span style="color:#404040"><code class="language-go"><span style="color:#999999">//对子模块进行配置</span>
subprojects { sub <span style="color:#67cdcc">-</span><span style="color:#67cdcc">></span>
sub.beforeEvaluate { proj <span style="color:#67cdcc">-</span><span style="color:#67cdcc">></span>
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"子项目beforeEvaluate回调..."</span>
}
}
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"根项目配置开始---"</span>
task rootTest {
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"根项目里任务配置---"</span>
doLast {
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"执行根项目任务..."</span>
}
}
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"根项目配置结束---"</span></code></span></span></span>
app/build.gradle 代码:
<span style="color:#000000"><span style="color:#cccccc"><span style="color:#404040"><code class="language-go"><span style="color:#cc99cd">println</span> <span style="color:#7ec699">"APP子项目配置开始---"</span>
afterEvaluate {
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"APP子项目afterEvaluate回调..."</span>
}
task appTest {
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"APP子项目里任务配置---"</span>
doLast {
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"执行子项目任务..."</span>
}
}
<span style="color:#cc99cd">println</span> <span style="color:#7ec699">"APP子项目配置结束---"</span></code></span></span></span>
在根目录执行:gradle -q,结果如下:
<span style="color:#000000"><span style="color:#cccccc"><span style="color:#404040"><code class="language-undefined">根项目配置开始---
根项目里任务配置---
根项目配置结束---
子项目beforeEvaluate回调...
APP子项目配置开始---
APP子项目里任务配置---
APP子项目配置结束---
APP子项目afterEvaluate回调...</code></span></span></span>
Gradle插件讲解
实际遇到的问题解决办法:
The number of method references in a .dex file cannot exceed 64K.
api的含义:把架包提供出去。某一个架包也是可以用api的。
api 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:5.1.4'
问题:
multiDexEnabled true
显示你有2个版本,1.01和1.02版本。模块之间弄multi和项目之间multi
查看是否编译进去了
https://www.jianshu.com/p/24ebbbe434a4
参考博客:刘望舒
https://blog.csdn.net/itachi85/article/details/81906139