成為一名優(yōu)秀的Android開(kāi)發(fā),需要一份完備的知識(shí)體系,在這里,讓我們一起成長(zhǎng)為自己所想的那樣~。
一、Gradle 插件實(shí)現(xiàn)架構(gòu)概述
Android Gradle plugin 團(tuán)隊(duì)在 Android Gradle V3.2.0 之前一直是都是用 Java 編寫的 Gradle 插件,在 V3.2.0 便采用了 Kotlin 進(jìn)行大面積的重寫。盡管 Groovy 語(yǔ)法簡(jiǎn)潔,且其閉包的寫法非常靈活,但是 Android Studio 對(duì) Groovy 的支持非常不友好,因此,目前寫自定義的 Gradle 插件時(shí)我們還是盡量使用 Kotlin,這樣能盡量避免編寫插件時(shí)提示不夠造成的坑。
下面,我們就來(lái)看看 Gradle 插件的整體實(shí)現(xiàn)架構(gòu),如下圖所示:

在最下層的是底層 Gradle 框架,它主要提供一些基礎(chǔ)的服務(wù),如 task 的依賴,有向無(wú)環(huán)圖的構(gòu)建等等。
上面的則是 Google 編譯工具團(tuán)隊(duì)的 Android Gradle plugin 框架,它主要是 在 Gradle 框架的基礎(chǔ)上,創(chuàng)建了很多與 Android 項(xiàng)目打包有關(guān)的 task 及 artifacts(每一個(gè) task 執(zhí)行完成之后通常都會(huì)輸出產(chǎn)物)。
最上面的則是開(kāi)發(fā)者自定義的 Plugin,關(guān)于自定義 Plugin 通常有兩種使用套路,如下所示:
- 1)、在 Android Gradle plugin 提供的 task 的基礎(chǔ)上,插入一些自定義的 task。
- 2)、增加 Transform 進(jìn)行編譯時(shí)代碼注入。
二、了解 Android Gradle Plugin 的更新歷史
下表列出了各個(gè) Android Gradle 插件版本所需的 Gradle 版本。我們應(yīng)該使用 Android Gradle Plugin 與 Gradle 這兩者的最新版本以獲得最佳的性能。
| 插件版本 | 所需的 Gradle 版本 |
|---|---|
| 1.0.0 - 1.1.3 | 2.2.1 - 2.3 |
| 1.2.0 - 1.3.1 | 2.2.1 - 2.9 |
| 1.5.0 | 2.2.1 - 2.13 |
| 2.0.0 - 2.1.2 | 2.10 - 2.13 |
| 2.1.3 - 2.2.3 | 2.14.1+ |
| 2.3.0+ | 3.3+ |
| 3.0.0+ | 4.1+ |
| 3.1.0+ | 4.4+ |
| 3.2.0 - 3.2.1 | 4.6+ |
| 3.3.0 - 3.3.2 | 4.10.1+ |
| 3.4.0 - 3.4.1 | 5.1.1+ |
| 3.5.0+ | 5.4.1-5.6.4 |
目前最新的 Android Gradle Plugin 版本為 V3.6.2,Gradle 版本為 V5.6.4。下面,我們了解下 Android Gradle Plugin 更新歷史中比較重要的更新變化。
1、Android Gradle Plugin V3.5.0(2019 年 8 月)
本次更新的重中之重是 提高項(xiàng)目的構(gòu)建速度。
2、Android Gradle Plugin V3.4.0(2019 年 4 月)
如果使用的是 Gradle 5.0 及更高版本,默認(rèn)的 Gradle 守護(hù)進(jìn)程內(nèi)存堆大小會(huì)從 1 GB 降到 512 MB。這可能會(huì)導(dǎo)致構(gòu)建性能降低。如果要替換此默認(rèn)設(shè)置,請(qǐng)?jiān)陧?xiàng)目的 gradle.properties 文件中指定 Gradle 守護(hù)進(jìn)程堆大小。
1)、新的 Lint 檢查依賴項(xiàng)配置
增加了新的依賴項(xiàng)配置 lintPublish,并更改了原有 lintChecks 的行為,它們的作用分別如下所示:
-
lintChecks:僅用于在本地構(gòu)建項(xiàng)目時(shí)運(yùn)行的 Lint 檢查。 -
lintPublish:在已發(fā)布的 AAR 中啟用 Lint 檢查,這樣使用此 AAR 的項(xiàng)目也會(huì)應(yīng)用那些 Lint 檢查。
其示例代碼如下所示:
dependencies {
// Executes lint checks from the ':lint' project at build time.
lintChecks project(':lint')
// Packages lint checks from the ':lintpublish' in the published AAR.
lintPublish project(':lintpublish')
}
復(fù)制代碼
2)、Android 免安裝應(yīng)用功能插件棄用警告
在之前的版本可以使用 com.android.feature 插件構(gòu)建免安裝應(yīng)用,現(xiàn)在建議使用動(dòng)態(tài)功能插件,這樣便可以通過(guò)單個(gè) Android App Bundle 發(fā)布安裝版應(yīng)用和免安裝應(yīng)用。
3)、R8 默認(rèn)處于啟用狀態(tài)
R8 將 desugar(脫糖:將 .class 字節(jié)碼轉(zhuǎn)換為 .dex 字節(jié)碼的過(guò)程)、壓縮、混淆、優(yōu)化和 dex 處理整合到了一個(gè)步驟中,從而顯著提升了構(gòu)建性能。R8 是在 Android Gradle Plugin V3.2.0 中引入的,對(duì)于使用插件 V3.4.0 及更高版本的應(yīng)用和 Android 庫(kù)項(xiàng)目來(lái)說(shuō),R8 已經(jīng)默認(rèn)處于啟用狀態(tài)。
R8 引入之前的編譯流程

R8 引入之后的編譯流程

可以看到,R8 組合了 Proguard、D8 的功能。如果遇到因 R8 導(dǎo)致的編譯失敗的問(wèn)題,可以配置以下代碼停用 R8:
# Disables R8 for Android Library modules only.
android.enableR8.libraries = false
# Disables R8 for all modules.
android.enableR8 = false
復(fù)制代碼
3)、棄用 ndkCompile
此時(shí)使用 ndkBuild 編譯原生庫(kù)會(huì)收到構(gòu)建錯(cuò)誤。我們應(yīng)該 使用 CMake 或 ndk-build 將 C 和 C++ 代碼添加到項(xiàng)目中。
3、Android Gradle Plugin V3.3.0(2019 年 1 月)
1)、為庫(kù)項(xiàng)目更快地生成 R 類
在老版本中,Android Gradle 插件會(huì)為項(xiàng)目的每個(gè)依賴項(xiàng)生成一個(gè) R.java 文件,然后將這些 R 類和應(yīng)用的其他類一起編譯。現(xiàn)在,插件會(huì)直接生成包含應(yīng)用的已編譯 R 類的 JAR,而不會(huì)先編譯中間的 R.java 類。這不僅可以顯著提升包含多個(gè)庫(kù)子項(xiàng)目和依賴項(xiàng)的項(xiàng)目的編譯性能,還可以加快在 Android Studio 中索引文件的速度。
4、Android Gradle Plugin V3.2.0(2018 年 9 月)
新的代碼壓縮器 R8
R8 是一種執(zhí)行代碼壓縮和混淆的新工具,替代了 ProGuard。我們只需將以下代碼添加到項(xiàng)目的 gradle.properties 文件中,即可開(kāi)始使用 R8 的預(yù)覽版本:
android.enableR8 = true
復(fù)制代碼
使用 D8 進(jìn)行 desugar 的功能現(xiàn)已默認(rèn)處于啟用狀態(tài)
5、Android Gradle Plugin V3.1.0(2018 年 3 月)
新的 DEX 編譯器 (D8)
默認(rèn)情況下,Android Studio 此時(shí)會(huì)使用名為 D8 的新 DEX 編譯器。DEX 編譯是指針對(duì) ART (對(duì)于較早版本的 Android,則針對(duì) Dalvik)將 .class 字節(jié)碼轉(zhuǎn)換為 .dex 字節(jié)碼的過(guò)程。與之前的編譯器(DX)相比,D8 的編譯速度更快,輸出的 DEX 文件更小,同時(shí)卻能保持相同甚至更出色的應(yīng)用運(yùn)行時(shí)性能。
如果在使用 D8 的過(guò)程中出現(xiàn)了問(wèn)題,可以在 gradle.properties 配置以下代碼暫時(shí)停用 D8 并使用 DX:
android.enableD8=false
復(fù)制代碼
6、Android Gradle Plugin V3.0.0(2017 年 10 月)
1)、通過(guò)精細(xì)控制的任務(wù)圖提升了多模塊項(xiàng)目的并行性。
更改依賴項(xiàng)時(shí),Gradle 通過(guò)不重新編譯那些無(wú)法被訪問(wèn)的依賴項(xiàng) API 模塊來(lái)加快編譯速度。此時(shí)可以利用 Gradle 的新依賴項(xiàng)配置(implementation、api、compileOnly 和 runtimeOnly)限制哪些依賴項(xiàng)會(huì)將其 API 泄露給其他模塊。
2)、借助每個(gè)類的 dex 處理,可加快增量編譯速度。
每個(gè)類現(xiàn)在都會(huì)編譯成單獨(dú)的 DEX 文件,并且只會(huì)對(duì)修改過(guò)的類重新進(jìn)行 dex 處理。
3)、啟用 Gradle 編譯緩存優(yōu)化某些任務(wù)來(lái)使用緩存的輸出
啟用 Gradle 編譯緩存能夠優(yōu)化某些任務(wù)來(lái)使用緩存的輸出,從而加快編譯速度。
4)、AAPT2 默認(rèn)已啟用并改進(jìn)了增量資源處理
如果在使用 AAPT2 時(shí)遇到了問(wèn)題,我們可以停用 AAPT2,在 gradle.properties 文件中設(shè)置如下代碼:
android.enableAapt2=false
復(fù)制代碼
然后,通過(guò)在命令行中運(yùn)行 ./gradlew --stop 來(lái)重啟 Gradle 守護(hù)進(jìn)程。
7、Android Gradle Plugin V2.3.0(2017 年 2 月)
1)、增加編譯緩存
存儲(chǔ)編譯項(xiàng)目時(shí) Android 插件生成的特定輸出。使用緩存時(shí),編譯插件的速度會(huì)明顯加快,因?yàn)榫幾g系統(tǒng)在進(jìn)行后續(xù)編譯時(shí)可以直接重用這些緩存文件,而不必重新創(chuàng)建。此外,我們也可以 使用 cleanBuildCache Task 去清除編譯緩存。
更老版本的的更新細(xì)節(jié)請(qǐng)查閱 gradle-plugin。
三、Gradle 構(gòu)建核心流程解析
當(dāng)我們輸入 ./gradlew/gradle ... 命令之后,一個(gè) Gradle 構(gòu)建就開(kāi)始了。它包含如下 三個(gè)步驟:
- 1)、首先,初始化 Gradle 構(gòu)建框架自身。
- 2)、然后,把命令行參數(shù)包裝好送給 DefaultGradleLauncher。
- 3)、最后,觸發(fā) DefaultGradleLauncher 中 Gradle 構(gòu)建的生命周期,并開(kāi)始執(zhí)行標(biāo)準(zhǔn)的構(gòu)建流程。
在開(kāi)始深入源碼之前,我們可以先自頂向下了解下 Gradle 構(gòu)建的核心流程圖,以便對(duì) Gradle 的構(gòu)建流程建立一個(gè)整體的感知。

當(dāng)我們執(zhí)行一個(gè) gralde 命令時(shí),便會(huì)調(diào)用 gradle/wrapper/gradle-wrapper.jar 里面 org.gradle.wrapper.GradleWrapperMain 類的 main 方法,它就是 gradle 的一個(gè)入口方法。該方法的核心源碼如下所示:
public static void main(String[] args) throws Exception {
...
// 1、索引到 gradle-wrapper.properties 文件中配置的 gradle zip 地址,并由此包裝成一個(gè) WrapperExecutor 實(shí)例。
WrapperExecutor wrapperExecutor = WrapperExecutor.forWrapperPropertiesFile(propertiesFile);
// 2、使用 wrapperExecutor 實(shí)例的 execute 方法執(zhí)行 gradle 命令。
wrapperExecutor.execute(args, new Install(logger, new Download(logger, "gradlew", "0"), new PathAssembler(gradleUserHome)), new BootstrapMainStarter());
}
復(fù)制代碼
然后,我們繼續(xù)看看 wrapperExecutor 的 execute 方法,源碼如下所示:
public void execute(String[] args, Install install, BootstrapMainStarter bootstrapMainStarter) throws Exception {
// 1、下載 gradle wrapper 需要的依賴與源碼。
File gradleHome = install.createDist(this.config);
// 2、從這里開(kāi)始執(zhí)行 gradle 的構(gòu)建流程。
bootstrapMainStarter.start(args, gradleHome);
}
復(fù)制代碼
首先,在注釋1處,會(huì)下載 gradle wrapper 需要的依賴與源碼。接著,在注釋2處,便會(huì)調(diào)用 bootstrapMainStarter 的 start 方法從這里開(kāi)始執(zhí)行 gradle 的構(gòu)建流程。其內(nèi)部最終會(huì)依次調(diào)用 DefaultGradleLauncher 的 getLoadedSettings、getConfiguredBuild、executeTasks 與 finishBuild 方法,而它們對(duì)應(yīng)的狀態(tài)都定義在 DefaultGradleLauncher 中的 Stage 枚舉類中,如下所示:
private static enum Stage {
LoadSettings,
Configure,
TaskGraph,
RunTasks {
String getDisplayName() {
return "Build";
}
},
Finished;
private Stage() {
}
String getDisplayName() {
return this.name();
}
}
復(fù)制代碼
下面,我們就對(duì)這五個(gè)流程來(lái)進(jìn)行詳細(xì)地分析。
1、LoadSettings
當(dāng)調(diào)用 getLoadedSettings 方法時(shí)便開(kāi)始了加載 Setting.gradle 的流程。其源碼如下所示:
public SettingsInternal getLoadedSettings() {
this.doBuildStages(DefaultGradleLauncher.Stage.LoadSettings);
return this.gradle.getSettings();
}
復(fù)制代碼
這里又繼續(xù)調(diào)用了 doBuildStages 方法進(jìn)行處理,內(nèi)部實(shí)現(xiàn)如下所示:
private void doBuildStages(DefaultGradleLauncher.Stage upTo) {
Preconditions.checkArgument(upTo != DefaultGradleLauncher.Stage.Finished, "Stage.Finished is not supported by doBuildStages.");
try {
// 當(dāng) Stage 是 RunTask 的時(shí)候執(zhí)行。
if (upTo == DefaultGradleLauncher.Stage.RunTasks && this.instantExecution.canExecuteInstantaneously()) {
this.doInstantExecution();
} else {
// 當(dāng) Stage 不是 RunTask 的時(shí)候執(zhí)行。 this.doClassicBuildStages(upTo);
}
} catch (Throwable var3) {
this.finishBuild(upTo.getDisplayName(), var3);
}
}
復(fù)制代碼
繼續(xù)調(diào)用 doClassicBuildStages 方法,源碼如下所示:
private void doClassicBuildStages(DefaultGradleLauncher.Stage upTo) {
// 1、當(dāng) Stage 為 LoadSettings 時(shí)執(zhí)行 prepareSettings 方法去配置并生成 Setting 實(shí)例。
this.prepareSettings();
if (upTo != DefaultGradleLauncher.Stage.LoadSettings) {
// 2、當(dāng) Stage 為 Configure 時(shí)執(zhí)行 prepareProjects 方法去配置工程。
this.prepareProjects();
if (upTo != DefaultGradleLauncher.Stage.Configure) {
// 3、當(dāng) Stage 為 TaskGraph 時(shí)執(zhí)行 prepareTaskExecution 方法去構(gòu)建 TaskGraph。
this.prepareTaskExecution();
if (upTo != DefaultGradleLauncher.Stage.TaskGraph) {
// 4、當(dāng) Stage 為 RunTasks 時(shí)執(zhí)行 saveTaskGraph 方法 與 runWork 方法保存 TaskGraph 并執(zhí)行相應(yīng)的 Tasks。 this.instantExecution.saveTaskGraph();
this.runWork();
}
}
}
}
復(fù)制代碼
可以看到,doClassicBuildStages 方法是個(gè)很重要的方法,它對(duì)所有的 Stage 任務(wù)進(jìn)行了分發(fā),這里小結(jié)一下:
- 1)、當(dāng) Stage 為 LoadSettings 時(shí)執(zhí)行 prepareSettings 方法去配置并生成 Setting 實(shí)例。
- 2)、當(dāng) Stage 為 Configure 時(shí)執(zhí)行 prepareProjects 方法去配置工程。
- 3)、當(dāng) Stage 為 TaskGraph 時(shí)執(zhí)行 prepareTaskExecution 方法去構(gòu)建 TaskGraph。
- 4)、當(dāng) Stage 為 RunTasks 時(shí)執(zhí)行 saveTaskGraph 方法 與 runWork 方法保存 TaskGraph 并執(zhí)行相應(yīng)的 Tasks。
然后,我們接著繼續(xù)看看 prepareSettings 方法,其源碼如下所示:
private void prepareSettings() {
if (this.stage == null) {
// 1、回調(diào) BuildListener.buildStarted() 回調(diào)接口。
this.buildListener.buildStarted(this.gradle);
// 2、調(diào)用 settingPreparer 接口的實(shí)現(xiàn)類 DefaultSettingsPreparer 的 prepareSettings 方法。
this.settingsPreparer.prepareSettings(this.gradle);
this.stage = DefaultGradleLauncher.Stage.LoadSettings;
}
}
復(fù)制代碼
在 prepareSettings 方法做了兩件事:
- 1)、回調(diào) BuildListener.buildStarted 接口。
- 2)、調(diào)用 settingPreparer 接口的實(shí)現(xiàn)類 DefaultSettingsPreparer 的 prepareSettings 方法。
我們繼續(xù)看到 DefaultSettingsPreparer 的 prepareSettings 方法,如下所示:
public void prepareSettings(GradleInternal gradle) {
// 1、執(zhí)行 init.gradle,它會(huì)在每個(gè)項(xiàng)目 build 之前被調(diào)用,用于做一些初始化的操作。
this.initScriptHandler.executeScripts(gradle);
SettingsLoader settingsLoader = gradle.getParent() != null ? this.settingsLoaderFactory.forNestedBuild() : this.settingsLoaderFactory.forTopLevelBuild();
// 2、調(diào)用 SettingLoader 接口的實(shí)現(xiàn)類 DefaultSettingsLoader 的 findAndLoadSettings 找到 Settings.gradle 文件的位置。
settingsLoader.findAndLoadSettings(gradle);
}
復(fù)制代碼
在 prepareSettings 方法中做了兩項(xiàng)處理:
- 1)、執(zhí)行 init.gradle,它會(huì)在每個(gè)項(xiàng)目 build 之前被調(diào)用,用于做一些初始化的操作。
- 2)、調(diào)用 SettingLoader 接口的實(shí)現(xiàn)類 DefaultSettingsLoader 的 findAndLoadSettings 找到 Settings.gradle 文件的位置。
DefaultSettingLoader 的 findAndLoadSettings 方法關(guān)聯(lián)的實(shí)現(xiàn)代碼非常多,限于篇幅,我這里直接點(diǎn)出 findAndLoadSettings 方法中的主要處理流程:
- 1)、首先,查找 settings.gradle 位置。
- 2)、然后,編譯 buildSrc(Android 默認(rèn)的 Plugin 目錄)文件夾下的內(nèi)容。
- 3)、接著,解析 gradle.properites 文件:這里會(huì)讀取 gradle.properties 文件里的配置信息與命令行傳入的配置屬性并存儲(chǔ)。
- 4)、然后,解析 settings.gradle 文件:這里最后會(huì)調(diào)用 BuildOperationScriptPlugin.apply 去執(zhí)行 settings.gradle 文件。
- 5)、最后,根據(jù) Settings.gradle 文件中獲得的信息去創(chuàng)建 project 以及 subproject 實(shí)例。
2、Configure
當(dāng)執(zhí)行完 LoadSetting 階段之后,就會(huì)執(zhí)行 Configure 階段,而配置階段所作的事情就是 把 gradle 腳本編譯成 class 文件并執(zhí)行。由前可知,此時(shí)會(huì)執(zhí)行 prepareProjects 方法,如下所示:
private void prepareProjects() {
if (this.stage == DefaultGradleLauncher.Stage.LoadSettings) {
// 1、調(diào)用 ProjectsPreparer 接口的實(shí)現(xiàn)類 DefaultProjectsPreparer 的 prepareProjects 方法。
this.projectsPreparer.prepareProjects(this.gradle);
this.stage = DefaultGradleLauncher.Stage.Configure;
}
}
復(fù)制代碼
這里會(huì)繼續(xù)調(diào)用 ProjectsPreparer 接口的實(shí)現(xiàn)類 DefaultProjectsPreparer 的 prepareProjects 方法。其源碼如下所示:
public void prepareProjects(GradleInternal gradle) {
...
// 1、如果在 gradle.properties 文件中指定了參數(shù) configure-on-demand,則只會(huì)配置主項(xiàng)目以及執(zhí)行 task 所需要的項(xiàng)目。
if (gradle.getStartParameter().isConfigureOnDemand()) {
this.projectConfigurer.configure(gradle.getRootProject());
} else {
// 2、如果沒(méi)有指定在 gradle.properties 文件中指定參數(shù) configure-on-demand,則會(huì)調(diào)用 ProjectConfigurer 接口的實(shí)現(xiàn)類 TaskPathProjectEvaluator 的 configureHierarchy 方法去配置所有項(xiàng)目。
this.projectConfigurer.configureHierarchy(gradle.getRootProject());
(new ProjectsEvaluatedNotifier(this.buildOperationExecutor)).notify(gradle);
}
this.modelConfigurationListener.onConfigure(gradle);
}
復(fù)制代碼
在注釋1處,如果在 gradle.properties 文件中指定了參數(shù) configure-on-demand,則只會(huì)配置主項(xiàng)目以及執(zhí)行 task 所需要的項(xiàng)目。我們這里只看默認(rèn)沒(méi)有指定的情況。否則,在注釋2處,則會(huì)調(diào)用 ProjectConfigurer 接口的實(shí)現(xiàn)類 TaskPathProjectEvaluator 的 configureHierarchy 方法去配置所有項(xiàng)目。
我們接著繼續(xù)看到 configureHierarchy 方法,如下所示:
public void configureHierarchy(ProjectInternal project) {
this.configure(project);
Iterator var2 = project.getSubprojects().iterator();
while(var2.hasNext()) {
Project sub = (Project)var2.next();
this.configure((ProjectInternal)sub);
}
}
復(fù)制代碼
可以看到在 configureHierarchy 方法中使用了 Iterator 遍歷并配置了所有 Project。而 configure 方法最終會(huì)調(diào)用到 EvaluateProject 類的 run 方法,如下所示:
public void run(final BuildOperationContext context) {
this.project.getMutationState().withMutableState(new Runnable() {
public void run() {
try {
EvaluateProject.this.state.toBeforeEvaluate();
// 1、 回調(diào) ProjectEvaluationListener 的 beforeEvaluate 接口。
LifecycleProjectEvaluator.this.buildOperationExecutor.run(new LifecycleProjectEvaluator.NotifyBeforeEvaluate(EvaluateProject.this.project, EvaluateProject.this.state));
if (!EvaluateProject.this.state.hasFailure()) {
EvaluateProject.this.state.toEvaluate();
try {
// 2、在 evaluate 方法中會(huì)設(shè)置默認(rèn)的 init、wrapper task 和 默認(rèn)插件,然后便會(huì)編譯、執(zhí)行 build.gradle 腳本
LifecycleProjectEvaluator.this.delegate.evaluate(EvaluateProject.this.project, EvaluateProject.this.state);
} catch (Exception var10) {
LifecycleProjectEvaluator.addConfigurationFailure(EvaluateProject.this.project, EvaluateProject.this.state, var10, context);
} finally {
EvaluateProject.this.state.toAfterEvaluate();
// 3、回調(diào) ProjectEvaluationListener.afterEvaluate 接口。
LifecycleProjectEvaluator.this.buildOperationExecutor.run(new LifecycleProjectEvaluator.NotifyAfterEvaluate(EvaluateProject.this.project, EvaluateProject.this.state));
}
}
if (EvaluateProject.this.state.hasFailure()) {
EvaluateProject.this.state.rethrowFailure();
} else {
context.setResult(ConfigureProjectBuildOperationType.RESULT);
}
} finally {
EvaluateProject.this.state.configured();
}
}
});
}
復(fù)制代碼
在 EvaluateProject 的 run 方法中有如下 三個(gè)重要的處理:
- 1)、回調(diào) ProjectEvaluationListener 的 beforeEvaluate 接口。
- 2)、在 evaluate 方法中會(huì)設(shè)置默認(rèn)的 init、wrapper task 和 默認(rèn)插件,然后便會(huì)編譯并執(zhí)行 build.gradle 腳本。
- 3)、回調(diào) ProjectEvaluationListener.afterEvaluate 接口。
3、TaskGraph
執(zhí)行完 初始化階段 與 配置階段 之后,就會(huì) 調(diào)用到 DefaultGradleLauncher 的 prepareTaskExecution 方法去創(chuàng)建一個(gè)由 Tasks 組成的一個(gè)有向無(wú)環(huán)圖。該方法如下所示:
private void prepareTaskExecution() {
if (this.stage == DefaultGradleLauncher.Stage.Configure) {
// 1、調(diào)用 TaskExecutionPreparer 接口的實(shí)現(xiàn)類 BuildOperatingFiringTaskExecutionPreparer 的 prepareForTaskExecution 方法。
this.taskExecutionPreparer.prepareForTaskExecution(this.gradle);
this.stage = DefaultGradleLauncher.Stage.TaskGraph;
}
}
復(fù)制代碼
這里繼續(xù)調(diào)用了 TaskExecutionPreparer 接口的實(shí)現(xiàn)類 BuildOperatingFiringTaskExecutionPreparer 的 prepareForTaskExecution 方法,如下所示:
public void prepareForTaskExecution(GradleInternal gradle) {
this.buildOperationExecutor.run(new BuildOperatingFiringTaskExecutionPreparer.CalculateTaskGraph(gradle));
}
復(fù)制代碼
可以看到,這里使用 buildOperationExecutor 實(shí)例執(zhí)行了 CalculateTaskGraph 這個(gè)構(gòu)建操作,我們看到它的 run 方法,如下所示:
public void run(BuildOperationContext buildOperationContext) {
// 1、填充任務(wù)圖
final TaskExecutionGraphInternal taskGraph = this.populateTaskGraph();
buildOperationContext.setResult(new Result() {
getRequestedTaskPaths() {
return this.toTaskPaths(taskGraph.getRequestedTasks());
}
public List<String> getExcludedTaskPaths() {
return this.toTaskPaths(taskGraph.getFilteredTasks());
}
private List<String> toTaskPaths(Set<Task> tasks) {
return ImmutableSortedSet.copyOf(Collections2.transform(tasks, new Function<Task, String>() {
public String apply(Task task) {
return task.getPath();
}
})).asList();
}
});
}
復(fù)制代碼
在注釋1處,直接調(diào)用了 populateTaskGraph 填充了 Tasks 有向無(wú)環(huán)圖。源碼如下所示:
TaskExecutionGraphInternal populateTaskGraph() {
// 1、這里又調(diào)用了 TaskExecutionPreparer 接口的另一個(gè)實(shí)現(xiàn)類 DefaultTaskExecutionPreparer 的 prepareForTaskExecution 方法。
BuildOperatingFiringTaskExecutionPreparer.this.delegate.prepareForTaskExecution(this.gradle);
return this.gradle.getTaskGraph();
}
復(fù)制代碼
可以看到,在注釋1處,又調(diào)用了 TaskExecutionPreparer 接口的另一個(gè)實(shí)現(xiàn)類 DefaultTaskExecutionPreparer 的 prepareForTaskExecution 方法。該方法如下所示:
public void prepareForTaskExecution(GradleInternal gradle) {
// 1
this.buildConfigurationActionExecuter.select(gradle);
TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
// 2、根據(jù) Tasks 與 Tasks 間的依賴信息填充 taskGraph 實(shí)例。
taskGraph.populate();
this.includedBuildControllers.populateTaskGraphs();
if (gradle.getStartParameter().isConfigureOnDemand()) {
(new ProjectsEvaluatedNotifier(this.buildOperationExecutor)).notify(gradle);
}
}
復(fù)制代碼
在注釋1處,調(diào)用了 buildConfigurationActionExecuter 接口的 select 方法,這里采用了 策略 + 接口隔離 設(shè)計(jì)模式,后續(xù)會(huì)依次調(diào)用 ExcludedTaskFilteringBuildConfigurationAction 的 configure 方法、 DefaultTasksBuildExecutionAction 的 configure 方法、TaskNameResolvingBuildConfigurationAction 的 configure 方法。
下面,我們依次來(lái)分析下其中的處理。
1)、ExcludedTaskFilteringBuildConfigurationAction#configure:處理需要排除的 task
public void configure(BuildExecutionContext context) {
// 1、獲取被排除的 Tasks 名稱,并依次把它們放入 filters 中。
GradleInternal gradle = context.getGradle();
Set<String> excludedTaskNames = gradle.getStartParameter().getExcludedTaskNames();
if (!excludedTaskNames.isEmpty()) {
Set<Spec<Task>> filters = new HashSet();
Iterator var5 = excludedTaskNames.iterator();
while(var5.hasNext()) {
String taskName = (String)var5.next();
filters.add(this.taskSelector.getFilter(taskName));
}
// 2、給 TaskGraph 實(shí)例添加要 filter 的 Tasks
gradle.getTaskGraph().useFilter(Specs.intersect(filters));
}
context.proceed();
}
復(fù)制代碼
在注釋1處,先獲取了被排除的 Tasks 名稱,并依次把它們放入 filters 中,接著在注釋2處給 TaskGraph 實(shí)例添加了要 filter 的 Tasks。
可以看到,這里給 TaskGraph 設(shè)置了 filter 去處理需要排除的 task,以便在后面計(jì)算依賴的時(shí)候排除相應(yīng)的 task。
2)、DefaultTasksBuildExecutionAction#configure:添加默認(rèn)的 task
public void configure(BuildExecutionContext context) {
StartParameter startParameter = context.getGradle().getStartParameter();
Iterator var3 = startParameter.getTaskRequests().iterator();
TaskExecutionRequest request;
// 1、如果指定了要執(zhí)行的 Task,則什么也不做。
do {
if (!var3.hasNext()) {
ProjectInternal project = context.getGradle().getDefaultProject();
this.projectConfigurer.configure(project);
List<String> defaultTasks = project.getDefaultTasks();
// 2、如果沒(méi)有指定 DefaultTasks,則輸出 gradle help 信息。
if (defaultTasks.size() == 0) {
defaultTasks = Collections.singletonList("help");
LOGGER.info("No tasks specified. Using default task {}", GUtil.toString(defaultTasks));
} else {
LOGGER.info("No tasks specified. Using project default tasks {}", GUtil.toString(defaultTasks));
}
// 3、否則,添加默認(rèn)的 Task。
startParameter.setTaskNames(defaultTasks);
context.proceed();
return;
}
request = (TaskExecutionRequest)var3.next();
} while(request.getArgs().isEmpty());
context.proceed();
}
復(fù)制代碼
可以看到,DefaultTasksBuildExecutionAction 類的 configure 方法的處理分為如下三步:
- 1、如果指定了要執(zhí)行的 Task,則什么也不做。
- 2、如果沒(méi)有指定 defaultTasks,則輸出 gradle help 信息。
- 3、否則,添加默認(rèn)的 defaultTasks。
3)、TaskNameResolvingBuildConfigurationAction#configure:計(jì)算 task 依賴圖
public void configure(BuildExecutionContext context) {
GradleInternal gradle = context.getGradle();
TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
List<TaskExecutionRequest> taskParameters = gradle.getStartParameter().getTaskRequests();
Iterator var5 = taskParameters.iterator();
while(var5.hasNext()) {
TaskExecutionRequest taskParameter = (TaskExecutionRequest)var5.next();
// 1、解析 Tasks。
List<TaskSelection> taskSelections = this.commandLineTaskParser.parseTasks(taskParameter);
Iterator var8 = taskSelections.iterator();
// 2、遍歷并添加所有已選擇的 Tasks 至 taskGraph 實(shí)例之中。
while(var8.hasNext()) {
TaskSelection taskSelection = (TaskSelection)var8.next();
LOGGER.info("Selected primary task '{}' from project {}", taskSelection.getTaskName(), taskSelection.getProjectPath());
taskGraph.addEntryTasks(taskSelection.getTasks());
}
}
context.proceed();
}
復(fù)制代碼
這里主要做了 兩個(gè)處理:
- 1)、
解析 Tasks:分析命令行中的 Task 的參數(shù)前面是否指定了 Project,例如 ':project:assembleRelease',如果沒(méi)有指定則選中 Project 下所有符合該 taskName 的 Task。 - 2)、
遍歷并添加所有已選擇的 Tasks 至 taskGraph 實(shí)例之中: 在內(nèi)部會(huì)處理 dependson finalizedby mustrunafter shouldrunafter 等 Tasks 間的依賴關(guān)系,并會(huì)把信息保存在 TaskInfo 之中。
4)、填充 task 依賴圖
最后,我們?cè)倩氐?DefaultTaskExecutionPreparer 的 prepareForTaskExecution 方法,在注釋2處,我們就可以 調(diào)用 taskGraph 的 populate 方法去根據(jù)這些 Tasks 與 Tasks 之間的依賴信息去填充 taskGraph 實(shí)例了。
4、RunTasks
填充完 taskGraph 之后,我們就可以開(kāi)始來(lái)執(zhí)行這些 Tasks 了,我們看到 DefaultGradleLauncher 實(shí)例的 executeTasks 方法,如下所示:
public GradleInternal executeTasks() {
this.doBuildStages(DefaultGradleLauncher.Stage.RunTasks);
return this.gradle;
}
復(fù)制代碼
在 doBuildStages 方法中又會(huì)調(diào)用 doClassicBuildStages 方法,源碼如下所示:
private void doClassicBuildStages(DefaultGradleLauncher.Stage upTo) {
this.prepareSettings();
if (upTo != DefaultGradleLauncher.Stage.LoadSettings) {
this.prepareProjects();
if (upTo != DefaultGradleLauncher.Stage.Configure) {
this.prepareTaskExecution();
if (upTo != DefaultGradleLauncher.Stage.TaskGraph) {
this.instantExecution.saveTaskGraph();
// 1
this.runWork();
}
}
}
}
復(fù)制代碼
在注釋1處,繼續(xù)調(diào)用了 runWork 方法,如下所示:
private void runWork() {
if (this.stage != DefaultGradleLauncher.Stage.TaskGraph) {
throw new IllegalStateException("Cannot execute tasks: current stage = " + this.stage);
} else {
List<Throwable> taskFailures = new ArrayList();
// 1
this.buildExecuter.execute(this.gradle, taskFailures);
if (!taskFailures.isEmpty()) {
throw new MultipleBuildFailures(taskFailures);
} else {
this.stage = DefaultGradleLauncher.Stage.RunTasks;
}
}
}
復(fù)制代碼
這里又繼續(xù) 調(diào)用了 buildExecuter 接口的實(shí)現(xiàn)類 DefaultBuildWorkExecutor 的 execute 方法,其實(shí)現(xiàn)如下所示:
public void execute(GradleInternal gradle, Collection<? super Throwable> failures) {
this.execute(gradle, 0, failures);
}
private void execute(final GradleInternal gradle, final int index, final Collection<? super Throwable> taskFailures) {
if (index < this.executionActions.size()) {
// 1
((BuildExecutionAction)this.executionActions.get(index)).execute(new BuildExecutionContext() {
public GradleInternal getGradle() {
return gradle;
}
public void proceed() {
// 2、執(zhí)行完 executionActions 列表中的第一項(xiàng)后,便開(kāi)始執(zhí)行下一項(xiàng)。
DefaultBuildWorkExecutor.this.execute(gradle, index + 1, taskFailures);
}
}, taskFailures);
}
}
復(fù)制代碼
1)、執(zhí)行 DryRunBuildExecutionAction:處理 DryRun
可以看到,這里又調(diào)用了 BuildExecutionAction 接口的實(shí)現(xiàn)類 DryRunBuildExecutionAction 的 execute 方法,如下所示:
public void execute(BuildExecutionContext context, Collection<? super Throwable> taskFailures) {
GradleInternal gradle = context.getGradle();
// 1、如果命令行里包含 --dry-run 參數(shù),則會(huì)跳過(guò)該 Task 的執(zhí)行,并輸出 Task 的名稱與執(zhí)行的先后關(guān)系。
if (gradle.getStartParameter().isDryRun()) {
Iterator var4 = gradle.getTaskGraph().getAllTasks().iterator();
while(var4.hasNext()) {
Task task = (Task)var4.next();
this.textOutputFactory.create(DryRunBuildExecutionAction.class).append(((TaskInternal)task).getIdentityPath().getPath()).append(" ").style(Style.ProgressStatus).append("SKIPPED").println();
}
} else {
context.proceed();
}
}
復(fù)制代碼
在注釋1處,如果命令行里包含了 --dry-run 參數(shù),則會(huì)跳過(guò)該 Task 的執(zhí)行,并輸出 Task 的名稱與執(zhí)行的先后關(guān)系。
2)、執(zhí)行:SelectedTaskExecutionAction:使用線程執(zhí)行被選擇的 Tasks
執(zhí)行完 DryRunBuildExecutionAction 后,我們?cè)倩氐?DefaultBuildWorkExecutor 類的 execute 方法,在注釋2處,會(huì)執(zhí)行 executionActions 列表中的下一項(xiàng),即第二項(xiàng):SelectedTaskExecutionAction,我們看看它的 execute 方法,如下所示:
public void execute(BuildExecutionContext context, Collection<? super Throwable> taskFailures) {
...
taskGraph.addTaskExecutionGraphListener(new SelectedTaskExecutionAction.BindAllReferencesOfProjectsToExecuteListener());
// 1、
taskGraph.execute(taskFailures);
}
復(fù)制代碼
可以看到,這里直接調(diào)用了 TaskExecutionGraphInternal 接口的實(shí)現(xiàn)類 DefaultTaskExecutionGraph 的 execute 方法去執(zhí)行 Tasks,其關(guān)鍵源碼如下所示:
public void execute(Collection<? super Throwable> failures) {
ProjectExecutionServiceRegistry projectExecutionServices = new ProjectExecutionServiceRegistry();
try {
// 使用線程池執(zhí)行 Task
this.executeWithServices(projectExecutionServices, failures);
} finally {
projectExecutionServices.close();
}
}
復(fù)制代碼
這里又繼續(xù)調(diào)用了 DefaultTaskExecutionGraph 的 executeWithServices 方法使用線程池并行執(zhí)行 Task,其核心源碼如下所示:
private void executeWithServices(ProjectExecutionServiceRegistry projectExecutionServices, Collection<? super Throwable> failures) {
...
this.ensurePopulated();
...
try {
// 1
this.planExecutor.process(this.executionPlan, failures, new DefaultTaskExecutionGraph.BuildOperationAwareExecutionAction(this.buildOperationExecutor.getCurrentOperation(), new DefaultTaskExecutionGraph.InvokeNodeExecutorsAction(this.nodeExecutors, projectExecutionServices)));
LOGGER.debug("Timing: Executing the DAG took " + clock.getElapsed());
} finally {
...
}
}
復(fù)制代碼
最終,這里是 調(diào)用了 PlanExecutor 接口的實(shí)現(xiàn)類 DefaultPlanExecutor 的 process 方法,如下所示:
public void process(ExecutionPlan executionPlan, Collection<? super Throwable> failures, Action<Node> nodeExecutor) {
ManagedExecutor executor = this.executorFactory.create("Execution worker for '" + executionPlan.getDisplayName() + "'");
try {
WorkerLease parentWorkerLease = this.workerLeaseService.getCurrentWorkerLease();
// 1、開(kāi)始使用線程池異步執(zhí)行 tasks
this.startAdditionalWorkers(executionPlan, nodeExecutor, executor, parentWorkerLease);
(new DefaultPlanExecutor.ExecutorWorker(executionPlan, nodeExecutor, parentWorkerLease, this.cancellationToken, this.coordinationService)).run();
this.awaitCompletion(executionPlan, failures);
} finally {
executor.stop();
}
}
復(fù)制代碼
在注釋1處,使用了線程池去異步執(zhí)行 tasks,如下所示:
private void startAdditionalWorkers(ExecutionPlan executionPlan, Action<? super Node> nodeExecutor, Executor executor, WorkerLease parentWorkerLease) {
LOGGER.debug("Using {} parallel executor threads", this.executorCount);
for(int i = 1; i < this.executorCount; ++i) {
executor.execute(new DefaultPlanExecutor.ExecutorWorker(executionPlan, nodeExecutor, parentWorkerLease, this.cancellationToken, this.coordinationService));
}
}
復(fù)制代碼
需要了解的是,用于執(zhí)行 Task 的線程默認(rèn)是 8 個(gè)線程。這里使用線程池執(zhí)行了 DefaultPlanExecutor 的 ExecutorWorker,在它的 run 方法中最終會(huì)調(diào)用到 DefaultBuildOperationExecutor 的 run 方法去執(zhí)行 Task。但在 Task 執(zhí)行前還需要做一些預(yù)處理。
3)、Task 執(zhí)行前的一些預(yù)處理
在 DefaultBuildOperationExecutor 的 run 方法中只做了兩件事,這里我們只需大致了解下即可,如下所示:
- 1、首先,回調(diào) TaskExecutionListener#beforeExecute。
- 2、然后,鏈?zhǔn)綀?zhí)行一系列對(duì) Task 的通用處理,其具體的處理如下所示:
- 1)、
CatchExceptionTaskExecuter#execute:增加 try catch,避免執(zhí)行過(guò)程中發(fā)生異常。 - 2)、
ExecuteAtMostOnceTaskExecuter#execute:判斷 task 是否執(zhí)行過(guò)。 - 3)、
SkipOnlyIfTaskExecuter#execute:判斷 task 的 onlyif 條件是否滿足執(zhí)行。 - 4)、
SkipTaskWithNoActionsExecuter#execute:跳過(guò)沒(méi)有 action 的 task,如果沒(méi)有 action 說(shuō)明 task 不需要執(zhí)行。 - 5)、
ResolveTaskArtifactStateTaskExecuter#execute:設(shè)置 artifact 的狀態(tài)。 - 6)、
SkipEmptySourceFilesTaskExecuter#execut:跳過(guò)設(shè)置了 source file 且 source file 為空的 task,如果 source file 為空則說(shuō)明 task 沒(méi)有需要處理的資源。 - 7)、
ValidatingTaskExecuter#execute:確認(rèn) task 是否可以執(zhí)行。 - 8)、
ResolveTaskOutputCachingStateExecuter#execute:處理 task 輸出緩存。 - 9)、
SkipUpToDateTaskExecuter#execute:跳過(guò) update-to-date 的 task。 - 10)、
ExecuteActionsTaskExecuter#execute:用來(lái)真正執(zhí)行 Task 的 executer。
- 1)、
可以看到,在真正執(zhí)行 Task 前需要經(jīng)歷一些通用的 task 預(yù)處理,最后才會(huì)調(diào)用 ExecuteActionsTaskExecuter 的 execute 方法去真正執(zhí)行 Task。
4)、真正執(zhí)行 Task
public TaskExecuterResult execute(final TaskInternal task, final TaskStateInternal state, final TaskExecutionContext context) {
final ExecuteActionsTaskExecuter.TaskExecution work = new ExecuteActionsTaskExecuter.TaskExecution(task, context, this.executionHistoryStore, this.fingerprinterRegistry, this.classLoaderHierarchyHasher);
// 使用 workExecutor 對(duì)象去真正執(zhí)行 Task。
final CachingResult result = (CachingResult)this.workExecutor.execute(new AfterPreviousExecutionContext() {
public UnitOfWork getWork() {
return work;
}
public Optional<String> getRebuildReason() {
return context.getTaskExecutionMode().getRebuildReason();
}
public Optional<AfterPreviousExecutionState> getAfterPreviousExecutionState() {
return Optional.ofNullable(context.getAfterPreviousExecution());
}
});
...
}
復(fù)制代碼
可以看到,這里使用了 workExecutor 對(duì)象去真正執(zhí)行 Task,在執(zhí)行時(shí)便會(huì)回調(diào) ExecuteActionsTaskExecuter.TaskExecution 內(nèi)部類的 execute 方法,其實(shí)現(xiàn)源碼如下所示:
public WorkResult execute(@Nullable InputChangesInternal inputChanges) {
this.task.getState().setExecuting(true);
WorkResult var2;
try {
ExecuteActionsTaskExecuter.LOGGER.debug("Executing actions for {}.", this.task);
// 1、回調(diào) TaskActionListener 的 beforeActions 接口。
ExecuteActionsTaskExecuter.this.actionListener.beforeActions(this.task);
// 2、內(nèi)部會(huì)遍歷執(zhí)行所有的 Action。
ExecuteActionsTaskExecuter.this.executeActions(this.task, inputChanges);
var2 = this.task.getState().getDidWork() ? WorkResult.DID_WORK : WorkResult.DID_NO_WORK;
} finally {
this.task.getState().setExecuting(false);
// 3、回調(diào) TaskActionListener.afterActions。
ExecuteActionsTaskExecuter.this.actionListener.afterActions(this.task);
}
return var2;
}
復(fù)制代碼
在 ExecuteActionsTaskExecuter.TaskExecution 內(nèi)部類的 execute 方法中做了三件事,如下所示:
- 1)、回調(diào) TaskActionListener 的 beforeActions。
- 2)、內(nèi)部會(huì)遍歷執(zhí)行 Task 所有的 Action。 => 執(zhí)行 Task 就是執(zhí)行其中包含的所有 Action,這便是 Task 的本質(zhì)。
- 3)、回調(diào) TaskActionListener.afterActions。
當(dāng)執(zhí)行完 Task 的所有 Action 之后,便會(huì)最終在 DefaultBuildOperationExecutor 的 run 方法中回調(diào) TaskExecutionListener.afterExecute 來(lái)標(biāo)識(shí) Task 最終執(zhí)行完成。
5、Finished
在 Finished 階段僅僅只干了一件比較重要的事情,就是 回調(diào) buildListener 的 buildFinished 接口,如下所示:
private void finishBuild(String action, @Nullable Throwable stageFailure) {
if (this.stage != DefaultGradleLauncher.Stage.Finished) {
...
try {
this.buildListener.buildFinished(buildResult);
} catch (Throwable var7) {
failures.add(var7);
}
this.stage = DefaultGradleLauncher.Stage.Finished;
...
}
}
復(fù)制代碼
6、小結(jié)
從對(duì) Gradle 執(zhí)行 Task 的分析中可以看到 Task 的本質(zhì),其實(shí)就是一系列的 Actions。深入了解了 Gradle 的構(gòu)建流程之后,我們?cè)僦匦禄貧w頭來(lái)看看開(kāi)始的那一張 Gradle 的構(gòu)建流程圖,如下所示:

此外,zhangyi54 做的 Gradle原理動(dòng)畫講解 將枯燥的原理流程視覺(jué)化了,值得推薦。需要注意區(qū)分的是,動(dòng)畫講解的 Gradle 版本比較老,但是主要的原理還是一致的,可以放心觀看。
注意:build.gradle 腳本的 buildscript 會(huì)在腳本的其它內(nèi)容之前執(zhí)行。
四、關(guān)于 Gradle 中依賴實(shí)現(xiàn)的原理
1、通過(guò) MethodMissing 機(jī)制,間接地調(diào)用 DefaultDependencyHandler 的 add 方法去添加依賴
我們都知道,DependencyHandler 是用來(lái)進(jìn)行依賴聲明的一個(gè)類,但是在 DependencyHandler 并沒(méi)有發(fā)現(xiàn) implementation(), api(), compile() 這些方法,這是怎么回事呢?
其實(shí)這是 通過(guò) MethodMissing 機(jī)制,間接地調(diào)用 DependencyHandler 的實(shí)現(xiàn) DefaultDependencyHandler 的 add() 方法將依賴添加進(jìn)去的。
那么,methodMissing 又是什么?
它是 Groovy 語(yǔ)言的一個(gè)重要特性,這個(gè)特性允許在運(yùn)行時(shí) catch 對(duì)于未定義方法的調(diào)用。
而 Gradle 對(duì)這個(gè)特性進(jìn)行了封裝,一個(gè)類要想使用這個(gè)特性,只要實(shí)現(xiàn) MixIn 接口即可。代碼如下所示:
public interface MethodMixIn {
MethodAccess getAdditionalMethods();
}
復(fù)制代碼
2、不同的依賴聲明,其實(shí)是由不同的轉(zhuǎn)換器進(jìn)行轉(zhuǎn)換的
例如如下兩個(gè)依賴:
- 1)、
DependencyStringNotationConverter: 將類似于 'androidx.appcompat:appcompat:1.1.0' 的常規(guī)依賴聲明轉(zhuǎn)換為依賴。 - 2)、
DependencyProjectNotationConverter: 將類似于 'project(":mylib")' 的依賴聲明轉(zhuǎn)換為依賴。
此外,除了 project 依賴,其它的依賴最終都會(huì)轉(zhuǎn)換為 SelfResolvingDependency, 而這個(gè)依賴可以實(shí)現(xiàn)自我解析。
3、Project 依賴的本質(zhì)是 Artifacts 依賴,也即 產(chǎn)物依賴。
4、什么是 Gradle 中的 Configuration?
implementation 與 api。但是,承擔(dān) moudle 或者 aar 依賴僅僅是 Configuration 表面的任務(wù),依賴的實(shí)質(zhì)就是獲取被依賴項(xiàng)構(gòu)建過(guò)程中產(chǎn)生的 Artifacts。
而對(duì)于大部分的 Task 來(lái)說(shuō),執(zhí)行完之后都會(huì)有產(chǎn)物輸出。而在各個(gè) moudle 之間 Artifacts 的產(chǎn)生與消費(fèi)則構(gòu)成了一個(gè)完整的生產(chǎn)者-消費(fèi)者模型。
5、Task 是如何發(fā)布自己 Artifacts 的?
每一個(gè) task 都會(huì)調(diào)用 VariantScopeImpl 中的 publishIntermediateArtifact 方法將自己的產(chǎn)物進(jìn)行發(fā)布,最后會(huì)調(diào)用到 DefaultVariant 的 artifact 方法對(duì)產(chǎn)物進(jìn)行發(fā)布。
作者:jsonchao
鏈接:https://juejin.cn/post/6844904142725447687
來(lái)源:掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。