目前,Gradle 自動化技術愈來愈重要,也有許多同窗已經可以製做出本身的 Gradle 插件,可是一直有一些 「梗」 遺留在咱們腦海中,無時無刻不提醒着咱們,你真的掌握了嗎?例如,「梗1」:Gradle 插件的總體實現架構?我:...,「梗2」:Android Gradle 插件更新歷史有哪些重要優化或者改進?我:..., 「梗3」:Gradle 構建的核心流程是怎樣的?我:...,「梗4」:Gradle 中依賴實現的原理?我:..., 「梗5」:AppPlugin 構建流程?我:..., 「梗6」:assembleDebug 打包流程?我:...., 「梗7」:一些很重要 Task 實現原理可否說說?我:... 。是否有不少點並無真正地去了解過呢?html
Android Gradle plugin 團隊在 Android Gradle V3.2.0 以前一直是都是用 Java 編寫的 Gradle 插件,在 V3.2.0 便採用了 Kotlin 進行大面積的重寫。儘管 Groovy 語法簡潔,且其閉包的寫法很是靈活,可是 Android Studio 對 Groovy 的支持很是不友好,所以,目前寫自定義的 Gradle 插件時咱們仍是儘可能使用 Kotlin,這樣能儘可能避免編寫插件時提示不夠形成的坑。java
下面,咱們就來看看 Gradle 插件的總體實現架構,以下圖所示:node
在最下層的是底層 Gradle 框架,它主要提供一些基礎的服務,如 task 的依賴,有向無環圖的構建等等。android
上面的則是 Google 編譯工具團隊的 Android Gradle plugin
框架,它主要是 在 Gradle 框架的基礎上,建立了不少與 Android 項目打包有關的 task 及 artifacts(每個 task 執行完成以後一般都會輸出產物)。git
最上面的則是開發者自定義的 Plugin,關於自定義 Plugin 一般有兩種使用套路,以下所示:github
下表列出了各個 Android Gradle 插件版本所需的 Gradle 版本。咱們應該使用 Android Gradle Plugin 與 Gradle 這二者的最新版本以得到最佳的性能。bootstrap
插件版本 | 所需的 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 更新歷史中比較重要的更新變化。設計模式
本次更新的重中之重是 提升項目的構建速度。api
若是使用的是 Gradle 5.0 及更高版本,默認的 Gradle 守護進程內存堆大小會從 1 GB 降到 512 MB。這可能會致使構建性能下降。若是要替換此默認設置,請在項目的 gradle.properties 文件中指定 Gradle 守護進程堆大小。緩存
增長了新的依賴項配置 lintPublish,並更改了原有 lintChecks 的行爲,它們的做用分別以下所示:
lintChecks
:僅用於在本地構建項目時運行的 Lint 檢查。lintPublish
:在已發佈的 AAR 中啓用 Lint 檢查,這樣使用此 AAR 的項目也會應用那些 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')
}
複製代碼
在以前的版本可使用 com.android.feature
插件構建免安裝應用,如今建議使用動態功能插件,這樣即可以經過單個 Android App Bundle 發佈安裝版應用和免安裝應用。
R8 將 desugar(脫糖:將 .class 字節碼轉換爲 .dex 字節碼的過程)、壓縮、混淆、優化和 dex 處理整合到了一個步驟中,從而顯著提高了構建性能。R8 是在 Android Gradle Plugin V3.2.0 中引入的,對於使用插件 V3.4.0 及更高版本的應用和 Android 庫項目來講,R8 已經默認處於啓用狀態。
能夠看到,R8 組合了 Proguard、D8 的功能。若是遇到因 R8 致使的編譯失敗的問題,能夠配置如下代碼停用 R8:
# Disables R8 for Android Library modules only.
android.enableR8.libraries = false
# Disables R8 for all modules.
android.enableR8 = false
複製代碼
此時使用 ndkBuild 編譯原生庫會收到構建錯誤。咱們應該 使用 CMake 或 ndk-build 將 C 和 C++ 代碼添加到項目中。
在老版本中,Android Gradle 插件會爲項目的每一個依賴項生成一個 R.java 文件,而後將這些 R 類和應用的其餘類一塊兒編譯。如今,插件會直接生成包含應用的已編譯 R 類的 JAR,而不會先編譯中間的 R.java 類。這不只能夠顯著提高包含多個庫子項目和依賴項的項目的編譯性能,還能夠加快在 Android Studio 中索引文件的速度。
R8 是一種執行代碼壓縮和混淆的新工具,替代了 ProGuard。咱們只需將如下代碼添加到項目的 gradle.properties 文件中,便可開始使用 R8 的預覽版本:
android.enableR8 = true
複製代碼
默認狀況下,Android Studio 此時會使用名爲 D8 的新 DEX 編譯器。DEX 編譯是指針對 ART (對於較早版本的 Android,則針對 Dalvik)將 .class 字節碼轉換爲 .dex 字節碼的過程。與以前的編譯器(DX)相比,D8 的編譯速度更快,輸出的 DEX 文件更小,同時卻能保持相同甚至更出色的應用運行時性能。
若是在使用 D8 的過程當中出現了問題,能夠在 gradle.properties 配置如下代碼暫時停用 D8 並使用 DX:
android.enableD8=false
複製代碼
更改依賴項時,Gradle 經過不從新編譯那些沒法被訪問的依賴項 API 模塊來加快編譯速度。此時能夠利用 Gradle 的新依賴項配置(implementation、api、compileOnly 和 runtimeOnly)限制哪些依賴項會將其 API 泄露給其餘模塊。
每一個類如今都會編譯成單獨的 DEX 文件,而且只會對修改過的類從新進行 dex 處理。
啓用 Gradle 編譯緩存可以優化某些任務來使用緩存的輸出,從而加快編譯速度。
若是在使用 AAPT2 時遇到了問題,咱們能夠停用 AAPT2,在 gradle.properties 文件中設置以下代碼:
android.enableAapt2=false
複製代碼
而後,經過在命令行中運行 ./gradlew --stop 來重啓 Gradle 守護進程。
存儲編譯項目時 Android 插件生成的特定輸出。使用緩存時,編譯插件的速度會明顯加快,由於編譯系統在進行後續編譯時能夠直接重用這些緩存文件,而沒必要從新建立。此外,咱們也能夠 使用 cleanBuildCache Task 去清除編譯緩存。
更老版本的的更新細節請查閱 gradle-plugin。
當咱們輸入 ./gradlew/gradle ... 命令以後,一個 Gradle 構建就開始了。它包含以下 三個步驟
:
在開始深刻源碼以前,咱們能夠先自頂向下瞭解下 Gradle 構建的核心流程圖,以便對 Gradle 的構建流程創建一個總體的感知。
當咱們執行一個 gralde 命令時,便會調用 gradle/wrapper/gradle-wrapper.jar 裏面 org.gradle.wrapper.GradleWrapperMain 類的 main 方法,它就是 gradle 的一個入口方法。該方法的核心源碼以下所示:
public static void main(String[] args) throws Exception {
...
// 一、索引到 gradle-wrapper.properties 文件中配置的 gradle zip 地址,並由此包裝成一個 WrapperExecutor 實例。
WrapperExecutor wrapperExecutor = WrapperExecutor.forWrapperPropertiesFile(propertiesFile);
// 二、使用 wrapperExecutor 實例的 execute 方法執行 gradle 命令。
wrapperExecutor.execute(args, new Install(logger, new Download(logger, "gradlew", "0"), new PathAssembler(gradleUserHome)), new BootstrapMainStarter());
}
複製代碼
而後,咱們繼續看看 wrapperExecutor 的 execute 方法,源碼以下所示:
public void execute(String[] args, Install install, BootstrapMainStarter bootstrapMainStarter) throws Exception {
// 一、下載 gradle wrapper 須要的依賴與源碼。
File gradleHome = install.createDist(this.config);
// 二、從這裏開始執行 gradle 的構建流程。
bootstrapMainStarter.start(args, gradleHome);
}
複製代碼
首先,在註釋1處,會下載 gradle wrapper 須要的依賴與源碼。接着,在註釋2處,便會調用 bootstrapMainStarter 的 start 方法從這裏開始執行 gradle 的構建流程。其內部最終會依次調用 DefaultGradleLauncher 的 getLoadedSettings、getConfiguredBuild、executeTasks 與 finishBuild 方法,而它們對應的狀態都定義在 DefaultGradleLauncher 中的 Stage 枚舉類中,以下所示:
private static enum Stage {
LoadSettings,
Configure,
TaskGraph,
RunTasks {
String getDisplayName() {
return "Build";
}
},
Finished;
private Stage() {
}
String getDisplayName() {
return this.name();
}
}
複製代碼
下面,咱們就對這五個流程來進行詳細地分析。
當調用 getLoadedSettings 方法時便開始了加載 Setting.gradle 的流程。其源碼以下所示:
public SettingsInternal getLoadedSettings() {
this.doBuildStages(DefaultGradleLauncher.Stage.LoadSettings);
return this.gradle.getSettings();
}
複製代碼
這裏又繼續調用了 doBuildStages 方法進行處理,內部實現以下所示:
private void doBuildStages(DefaultGradleLauncher.Stage upTo) {
Preconditions.checkArgument(upTo != DefaultGradleLauncher.Stage.Finished, "Stage.Finished is not supported by doBuildStages.");
try {
// 當 Stage 是 RunTask 的時候執行。
if (upTo == DefaultGradleLauncher.Stage.RunTasks && this.instantExecution.canExecuteInstantaneously()) {
this.doInstantExecution();
} else {
// 當 Stage 不是 RunTask 的時候執行。 this.doClassicBuildStages(upTo);
}
} catch (Throwable var3) {
this.finishBuild(upTo.getDisplayName(), var3);
}
}
複製代碼
繼續調用 doClassicBuildStages 方法,源碼以下所示:
private void doClassicBuildStages(DefaultGradleLauncher.Stage upTo) {
// 一、當 Stage 爲 LoadSettings 時執行 prepareSettings 方法去配置並生成 Setting 實例。
this.prepareSettings();
if (upTo != DefaultGradleLauncher.Stage.LoadSettings) {
// 二、當 Stage 爲 Configure 時執行 prepareProjects 方法去配置工程。
this.prepareProjects();
if (upTo != DefaultGradleLauncher.Stage.Configure) {
// 三、當 Stage 爲 TaskGraph 時執行 prepareTaskExecution 方法去構建 TaskGraph。
this.prepareTaskExecution();
if (upTo != DefaultGradleLauncher.Stage.TaskGraph) {
// 四、當 Stage 爲 RunTasks 時執行 saveTaskGraph 方法 與 runWork 方法保存 TaskGraph 並執行相應的 Tasks。 this.instantExecution.saveTaskGraph();
this.runWork();
}
}
}
}
複製代碼
能夠看到,doClassicBuildStages
方法是個很重要的方法,它對全部的 Stage 任務進行了分發,這裏小結一下:
而後,咱們接着繼續看看 prepareSettings 方法,其源碼以下所示:
private void prepareSettings() {
if (this.stage == null) {
// 一、回調 BuildListener.buildStarted() 回調接口。
this.buildListener.buildStarted(this.gradle);
// 二、調用 settingPreparer 接口的實現類 DefaultSettingsPreparer 的 prepareSettings 方法。
this.settingsPreparer.prepareSettings(this.gradle);
this.stage = DefaultGradleLauncher.Stage.LoadSettings;
}
}
複製代碼
在 prepareSettings
方法作了兩件事:
咱們繼續看到 DefaultSettingsPreparer 的 prepareSettings 方法,以下所示:
public void prepareSettings(GradleInternal gradle) {
// 一、執行 init.gradle,它會在每一個項目 build 以前被調用,用於作一些初始化的操做。
this.initScriptHandler.executeScripts(gradle);
SettingsLoader settingsLoader = gradle.getParent() != null ? this.settingsLoaderFactory.forNestedBuild() : this.settingsLoaderFactory.forTopLevelBuild();
// 二、調用 SettingLoader 接口的實現類 DefaultSettingsLoader 的 findAndLoadSettings 找到 Settings.gradle 文件的位置。
settingsLoader.findAndLoadSettings(gradle);
}
複製代碼
在 prepareSettings
方法中作了兩項處理:
DefaultSettingLoader 的 findAndLoadSettings 方法關聯的實現代碼很是多,限於篇幅,我這裏直接點出 findAndLoadSettings 方法中的主要處理流程:
當執行完 LoadSetting 階段以後,就會執行 Configure 階段,而配置階段所做的事情就是 把 gradle 腳本編譯成 class 文件並執行。由前可知,此時會執行 prepareProjects 方法,以下所示:
private void prepareProjects() {
if (this.stage == DefaultGradleLauncher.Stage.LoadSettings) {
// 一、調用 ProjectsPreparer 接口的實現類 DefaultProjectsPreparer 的 prepareProjects 方法。
this.projectsPreparer.prepareProjects(this.gradle);
this.stage = DefaultGradleLauncher.Stage.Configure;
}
}
複製代碼
這裏會繼續調用 ProjectsPreparer 接口的實現類 DefaultProjectsPreparer 的 prepareProjects 方法。其源碼以下所示:
public void prepareProjects(GradleInternal gradle) {
...
// 一、若是在 gradle.properties 文件中指定了參數 configure-on-demand,則只會配置主項目以及執行 task 所須要的項目。
if (gradle.getStartParameter().isConfigureOnDemand()) {
this.projectConfigurer.configure(gradle.getRootProject());
} else {
// 二、若是沒有指定在 gradle.properties 文件中指定參數 configure-on-demand,則會調用 ProjectConfigurer 接口的實現類 TaskPathProjectEvaluator 的 configureHierarchy 方法去配置全部項目。
this.projectConfigurer.configureHierarchy(gradle.getRootProject());
(new ProjectsEvaluatedNotifier(this.buildOperationExecutor)).notify(gradle);
}
this.modelConfigurationListener.onConfigure(gradle);
}
複製代碼
在註釋1處,若是在 gradle.properties 文件中指定了參數 configure-on-demand,則只會配置主項目以及執行 task 所須要的項目。咱們這裏只看默認沒有指定的狀況。不然,在註釋2處,則會調用 ProjectConfigurer 接口的實現類 TaskPathProjectEvaluator 的 configureHierarchy 方法去配置全部項目。
咱們接着繼續看到 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);
}
}
複製代碼
能夠看到在 configureHierarchy 方法中使用了 Iterator 遍歷並配置了全部 Project。而 configure 方法最終會調用到 EvaluateProject 類的 run 方法,以下所示:
public void run(final BuildOperationContext context) {
this.project.getMutationState().withMutableState(new Runnable() {
public void run() {
try {
EvaluateProject.this.state.toBeforeEvaluate();
// 一、 回調 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 {
// 二、在 evaluate 方法中會設置默認的 init、wrapper task 和 默認插件,而後便會編譯、執行 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();
// 三、回調 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();
}
}
});
}
複製代碼
在 EvaluateProject 的 run 方法中有以下 三個重要的處理:
執行完 初始化階段 與 配置階段 以後,就會 調用到 DefaultGradleLauncher 的 prepareTaskExecution 方法去建立一個由 Tasks 組成的一個有向無環圖。該方法以下所示:
private void prepareTaskExecution() {
if (this.stage == DefaultGradleLauncher.Stage.Configure) {
// 一、調用 TaskExecutionPreparer 接口的實現類 BuildOperatingFiringTaskExecutionPreparer 的 prepareForTaskExecution 方法。
this.taskExecutionPreparer.prepareForTaskExecution(this.gradle);
this.stage = DefaultGradleLauncher.Stage.TaskGraph;
}
}
複製代碼
這裏繼續調用了 TaskExecutionPreparer 接口的實現類 BuildOperatingFiringTaskExecutionPreparer 的 prepareForTaskExecution 方法,以下所示:
public void prepareForTaskExecution(GradleInternal gradle) {
this.buildOperationExecutor.run(new BuildOperatingFiringTaskExecutionPreparer.CalculateTaskGraph(gradle));
}
複製代碼
能夠看到,這裏使用 buildOperationExecutor 實例執行了 CalculateTaskGraph 這個構建操做,咱們看到它的 run 方法,以下所示:
public void run(BuildOperationContext buildOperationContext) {
// 一、填充任務圖
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();
}
});
}
複製代碼
在註釋1處,直接調用了 populateTaskGraph 填充了 Tasks 有向無環圖。源碼以下所示:
TaskExecutionGraphInternal populateTaskGraph() {
// 一、這裏又調用了 TaskExecutionPreparer 接口的另外一個實現類 DefaultTaskExecutionPreparer 的 prepareForTaskExecution 方法。
BuildOperatingFiringTaskExecutionPreparer.this.delegate.prepareForTaskExecution(this.gradle);
return this.gradle.getTaskGraph();
}
複製代碼
能夠看到,在註釋1處,又調用了 TaskExecutionPreparer 接口的另外一個實現類 DefaultTaskExecutionPreparer 的 prepareForTaskExecution 方法。該方法以下所示:
public void prepareForTaskExecution(GradleInternal gradle) {
// 1
this.buildConfigurationActionExecuter.select(gradle);
TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
// 二、根據 Tasks 與 Tasks 間的依賴信息填充 taskGraph 實例。
taskGraph.populate();
this.includedBuildControllers.populateTaskGraphs();
if (gradle.getStartParameter().isConfigureOnDemand()) {
(new ProjectsEvaluatedNotifier(this.buildOperationExecutor)).notify(gradle);
}
}
複製代碼
在註釋1處,調用了 buildConfigurationActionExecuter 接口的 select 方法,這裏採用了 策略 + 接口隔離 設計模式,後續會依次調用 ExcludedTaskFilteringBuildConfigurationAction 的 configure 方法、 DefaultTasksBuildExecutionAction 的 configure 方法、TaskNameResolvingBuildConfigurationAction 的 configure 方法。
下面,咱們依次來分析下其中的處理。
public void configure(BuildExecutionContext context) {
// 一、獲取被排除的 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));
}
// 二、給 TaskGraph 實例添加要 filter 的 Tasks
gradle.getTaskGraph().useFilter(Specs.intersect(filters));
}
context.proceed();
}
複製代碼
在註釋1處,先獲取了被排除的 Tasks 名稱,並依次把它們放入 filters 中,接着在註釋2處給 TaskGraph 實例添加了要 filter 的 Tasks。
能夠看到,這裏給 TaskGraph 設置了 filter 去處理須要排除的 task,以便在後面計算依賴的時候排除相應的 task。
public void configure(BuildExecutionContext context) {
StartParameter startParameter = context.getGradle().getStartParameter();
Iterator var3 = startParameter.getTaskRequests().iterator();
TaskExecutionRequest request;
// 一、若是指定了要執行的 Task,則什麼也不作。
do {
if (!var3.hasNext()) {
ProjectInternal project = context.getGradle().getDefaultProject();
this.projectConfigurer.configure(project);
List<String> defaultTasks = project.getDefaultTasks();
// 二、若是沒有指定 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));
}
// 三、不然,添加默認的 Task。
startParameter.setTaskNames(defaultTasks);
context.proceed();
return;
}
request = (TaskExecutionRequest)var3.next();
} while(request.getArgs().isEmpty());
context.proceed();
}
複製代碼
能夠看到,DefaultTasksBuildExecutionAction 類的 configure 方法的處理分爲以下三步:
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();
// 一、解析 Tasks。
List<TaskSelection> taskSelections = this.commandLineTaskParser.parseTasks(taskParameter);
Iterator var8 = taskSelections.iterator();
// 二、遍歷並添加全部已選擇的 Tasks 至 taskGraph 實例之中。
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();
}
複製代碼
這裏主要作了 兩個處理
:
解析 Tasks
:分析命令行中的 Task 的參數前面是否指定了 Project,例如 ':project:assembleRelease',若是沒有指定則選中 Project 下全部符合該 taskName 的 Task。遍歷並添加全部已選擇的 Tasks 至 taskGraph 實例之中
: 在內部會處理 dependson finalizedby mustrunafter shouldrunafter 等 Tasks 間的依賴關係,並會把信息保存在 TaskInfo 之中。最後,咱們再回到 DefaultTaskExecutionPreparer 的 prepareForTaskExecution 方法,在註釋2處,咱們就能夠 調用 taskGraph 的 populate 方法去根據這些 Tasks 與 Tasks 之間的依賴信息去填充 taskGraph 實例了。
填充完 taskGraph 以後,咱們就能夠開始來執行這些 Tasks 了,咱們看到 DefaultGradleLauncher 實例的 executeTasks 方法,以下所示:
public GradleInternal executeTasks() {
this.doBuildStages(DefaultGradleLauncher.Stage.RunTasks);
return this.gradle;
}
複製代碼
在 doBuildStages 方法中又會調用 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();
}
}
}
}
複製代碼
在註釋1處,繼續調用了 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;
}
}
}
複製代碼
這裏又繼續 調用了 buildExecuter 接口的實現類 DefaultBuildWorkExecutor 的 execute 方法,其實現以下所示:
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() {
// 二、執行完 executionActions 列表中的第一項後,便開始執行下一項。
DefaultBuildWorkExecutor.this.execute(gradle, index + 1, taskFailures);
}
}, taskFailures);
}
}
複製代碼
能夠看到,這裏又調用了 BuildExecutionAction 接口的實現類 DryRunBuildExecutionAction 的 execute 方法,以下所示:
public void execute(BuildExecutionContext context, Collection<? super Throwable> taskFailures) {
GradleInternal gradle = context.getGradle();
// 一、若是命令行裏包含 --dry-run 參數,則會跳過該 Task 的執行,並輸出 Task 的名稱與執行的前後關係。
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();
}
}
複製代碼
在註釋1處,若是命令行裏包含了 --dry-run 參數,則會跳過該 Task 的執行,並輸出 Task 的名稱與執行的前後關係。
執行完 DryRunBuildExecutionAction 後,咱們再回到 DefaultBuildWorkExecutor 類的 execute 方法,在註釋2處,會執行 executionActions 列表中的下一項,即第二項:SelectedTaskExecutionAction,咱們看看它的 execute 方法,以下所示:
public void execute(BuildExecutionContext context, Collection<? super Throwable> taskFailures) {
...
taskGraph.addTaskExecutionGraphListener(new SelectedTaskExecutionAction.BindAllReferencesOfProjectsToExecuteListener());
// 一、
taskGraph.execute(taskFailures);
}
複製代碼
能夠看到,這裏直接調用了 TaskExecutionGraphInternal 接口的實現類 DefaultTaskExecutionGraph 的 execute 方法去執行 Tasks,其關鍵源碼以下所示:
public void execute(Collection<? super Throwable> failures) {
ProjectExecutionServiceRegistry projectExecutionServices = new ProjectExecutionServiceRegistry();
try {
// 使用線程池執行 Task
this.executeWithServices(projectExecutionServices, failures);
} finally {
projectExecutionServices.close();
}
}
複製代碼
這裏又繼續調用了 DefaultTaskExecutionGraph 的 executeWithServices 方法使用線程池並行執行 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 {
...
}
}
複製代碼
最終,這裏是 調用了 PlanExecutor 接口的實現類 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();
// 一、開始使用線程池異步執行 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();
}
}
複製代碼
在註釋1處,使用了線程池去異步執行 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));
}
}
複製代碼
須要瞭解的是,用於執行 Task 的線程默認是 8 個線程。這裏使用線程池執行了 DefaultPlanExecutor 的 ExecutorWorker,在它的 run 方法中最終會調用到 DefaultBuildOperationExecutor 的 run 方法去執行 Task。但在 Task 執行前還須要作一些預處理。
在 DefaultBuildOperationExecutor 的 run 方法中只作了兩件事,這裏咱們只需大體瞭解下便可,以下所示:
CatchExceptionTaskExecuter#execute
:增長 try catch,避免執行過程當中發生異常。ExecuteAtMostOnceTaskExecuter#execute
:判斷 task 是否執行過。SkipOnlyIfTaskExecuter#execute
:判斷 task 的 onlyif 條件是否知足執行。SkipTaskWithNoActionsExecuter#execute
:跳過沒有 action 的 task,若是沒有 action 說明 task 不須要執行。ResolveTaskArtifactStateTaskExecuter#execute
:設置 artifact 的狀態。SkipEmptySourceFilesTaskExecuter#execut
:跳過設置了 source file 且 source file 爲空的 task,若是 source file 爲空則說明 task 沒有須要處理的資源。ValidatingTaskExecuter#execute
:確認 task 是否能夠執行。ResolveTaskOutputCachingStateExecuter#execute
:處理 task 輸出緩存。SkipUpToDateTaskExecuter#execute
:跳過 update-to-date 的 task。ExecuteActionsTaskExecuter#execute
:用來真正執行 Task 的 executer。能夠看到,在真正執行 Task 前須要經歷一些通用的 task 預處理,最後纔會調用 ExecuteActionsTaskExecuter 的 execute 方法去真正執行 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 對象去真正執行 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());
}
});
...
}
複製代碼
能夠看到,這裏使用了 workExecutor 對象去真正執行 Task,在執行時便會回調 ExecuteActionsTaskExecuter.TaskExecution 內部類的 execute 方法,其實現源碼以下所示:
public WorkResult execute(@Nullable InputChangesInternal inputChanges) {
this.task.getState().setExecuting(true);
WorkResult var2;
try {
ExecuteActionsTaskExecuter.LOGGER.debug("Executing actions for {}.", this.task);
// 一、回調 TaskActionListener 的 beforeActions 接口。
ExecuteActionsTaskExecuter.this.actionListener.beforeActions(this.task);
// 二、內部會遍歷執行全部的 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);
// 三、回調 TaskActionListener.afterActions。
ExecuteActionsTaskExecuter.this.actionListener.afterActions(this.task);
}
return var2;
}
複製代碼
在 ExecuteActionsTaskExecuter.TaskExecution 內部類的 execute 方法中作了三件事,以下所示:
當執行完 Task 的全部 Action 以後,便會最終在 DefaultBuildOperationExecutor 的 run 方法中回調 TaskExecutionListener.afterExecute 來標識 Task 最終執行完成。
在 Finished 階段僅僅只幹了一件比較重要的事情,就是 回調 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;
...
}
}
複製代碼
從對 Gradle 執行 Task 的分析中能夠看到 Task 的本質,其實就是一系列的 Actions。深刻了解了 Gradle 的構建流程以後,咱們再從新迴歸頭來看看開始的那一張 Gradle 的構建流程圖,以下所示:
此外,zhangyi54 作的 Gradle原理動畫講解 將枯燥的原理流程視覺化了,值得推薦。須要注意區分的是,動畫講解的 Gradle 版本比較老,可是主要的原理仍是一致的,能夠放心觀看。
注意:build.gradle 腳本的 buildscript 會在腳本的其它內容以前執行。
咱們都知道,DependencyHandler 是用來進行依賴聲明的一個類,可是在 DependencyHandler 並無發現 implementation(), api(), compile() 這些方法,這是怎麼回事呢?
其實這是 經過 MethodMissing 機制,間接地調用 DependencyHandler 的實現 DefaultDependencyHandler 的 add() 方法將依賴添加進去的。
它是 Groovy 語言的一個重要特性,這個特性容許在運行時 catch 對於未定義方法的調用。
而 Gradle 對這個特性進行了封裝,一個類要想使用這個特性,只要實現 MixIn 接口便可。代碼以下所示:
public interface MethodMixIn {
MethodAccess getAdditionalMethods();
}
複製代碼
例如以下兩個依賴:
DependencyStringNotationConverter
: 將相似於 'androidx.appcompat:appcompat:1.1.0' 的常規依賴聲明轉換爲依賴。DependencyProjectNotationConverter
: 將相似於 'project(":mylib")' 的依賴聲明轉換爲依賴。此外,除了 project 依賴,其它的依賴最終都會轉換爲 SelfResolvingDependency, 而這個依賴能夠實現自我解析。
implementation 與 api。可是,承擔 moudle 或者 aar 依賴僅僅是 Configuration 表面的任務,依賴的實質就是獲取被依賴項構建過程當中產生的 Artifacts。
而對於大部分的 Task 來講,執行完以後都會有產物輸出。而在各個 moudle 之間 Artifacts 的產生與消費則構成了一個完整的生產者-消費者模型。
每個 task 都會調用 VariantScopeImpl 中的 publishIntermediateArtifact 方法將本身的產物進行發佈,最後會調用到 DefaultVariant 的 artifact 方法對產物進行發佈。
一、Android Gradle Plugin V3.6.2 源碼
二、Gradle V5.6.4 源碼
三、Android Plugin DSL Reference
七、連載 | 深刻理解Gradle框架之一:Plugin, Extension, buildSrc
九、連載 | 深刻理解gradle框架之三:artifacts的發佈
十、Android Gradle Plugin 源碼解析(上)
十一、Android Gradle Plugin 源碼解析(下)
1三、Gradle 庖丁解牛(構建生命週期核心委託對象建立源碼淺析)