Gradle浅析之生命周期
我们在日常开发中,无论是使用图形构建按钮还是使用命令开启构建任务,其会经历设置,陪着,构建任务依赖图,最终执行我们输入的任务。但是其内部如何进行这一系列过程的,今天我们就分析Android中输入 ./gradlew assembleBuild后, gradle的生命周期原理。
Gradle命令入口
在我们每一个android下面都有一个 gradlew.bat脚本文件,其为我们执行 ./gradlew命令的入口。其最终会执行下面的命令
@rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 复制代码
其最终会调用GradleWrapperMain类,调用其main方法,其为gradle源码中的类。也是我们执行gradlew命令的入口。到这里我们要继续看起源码,必须下载对应的gradle源码。
Gradle源码
我们可以从github下载对应的源码,我这里分析的源码下载的是7.3的。下载下来用Intellij idead编译需要一段时间,后续开启缓存模式构建就快了。
Gradle下载
接下来我们准备好源码,进入GradleMain看起源码。我们开发中知道,如果第一次构建项目其会更加我们项目下的gradle目录下的wrapper.properties进行下载对应的版本,如果本地有其就不会下载,今天我们就探究一下其原理。
wrapper.properties配置
distributionBase=GRADLE_USER_HOME distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME 复制代码
GradleWrapperMain
读取wrapper的配置
其首先从我们目录下gradle的配置文件读取配置信息,即上面列出的
然后创建WrapperExeucter
接着执行其ececute,其会传入Install和BootstrapMainStarter
public static void main(String[] args) { File wrapperJar = wrapperJar(); File propertiesFile = wrapperProperties(wrapperJar); .... WrapperExecutor wrapperExecutor = WrapperExecutor.forWrapperPropertiesFile(propertiesFile); wrapperExecutor.execute( args, new Install(logger, new Download(logger, "gradlew", UNKNOWN_VERSION), new PathAssembler(gradleUserHome, rootDir)), new BootstrapMainStarter()); } 复制代码
WrapperExecuter
其executer方法,内部会首先调用Install对应的方法,去判断是否需要下载Gradle,然后调用bootstrapMainStarter的启动方法
public void execute(String[] args, Install install, BootstrapMainStarter bootstrapMainStarter) throws Exception { File gradleHome = install.createDist(config); bootstrapMainStarter.start(args, gradleHome); } 复制代码
Install配置Gradle
其createDist方法,就是根据配置里的信息去下载对应版本的gradle,如果本地存在,则直接加载缓存。
public File createDist(final WrapperConfiguration configuration) { //下载地址 final URI distributionUrl = configuration.getDistribution(); // 文件256校验码 final String distributionSha256Sum = configuration.getDistributionSha256Sum(); //本地对应的配置 final PathAssembler.LocalDistribution localDistribution = pathAssembler. getDistribution(configuration); final File distDir = localDistribution.getDistributionDir(); final File localZipFile = localDistribution.getZipFile(); ... //是否需要下载,本地文件是否存在 boolean needsDownload = !localZipFile.isFile(); URI safeDistributionUrl = Download.safeUri(distributionUrl); if (needsDownload) { File tmpZipFile = new File(localZipFile.getParentFile(), localZipFile.getName() + ".part"); tmpZipFile.delete(); logger.log("Downloading " + safeDistributionUrl); //开始下载 download.download(distributionUrl, tmpZipFile); tmpZipFile.renameTo(localZipFile); } ... //校验文件是否下载正确 verifyDownloadChecksum(configuration.getDistribution().toString(), localZipFile, distributionSha256Sum); //解压 unzip(localZipFile, distDir); } 复制代码
经过上面的步骤,就按照gradle目录下的配置,下载好对应的gradle版本包,即我们后面整体gradle执行代码。
BootstrapMainStarter开启任务
其start方法,开始gradle的构建流程,其调用流程比较复杂,不同版本代码逻辑有些不同。具体过程不是我们本文的重点,我简单梳理了一个大致调用流程,感兴趣的可以作为参看查看其源码。其最终会调用VintageBuildModelController的doBuildState。
流程图
接下来我们分析其生命周期的每个阶段做了什么。
Gradle生命周期
查看对应VintageBuildModelController类State,其主要有四个阶段。
生命周期阶段
private enum Stage implements StateTransitionController.State { Created, LoadSettings, Configure, ScheduleTasks, TaskGraph } 复制代码
�其doBuilldState会根据对应要执行到的阶段,依次调用对应的方法。下面我们依次分析。
LoadSettings
进入doBuildStages会根据传递的状态执行到对应的状态
private void doBuildStages(Stage upTo) { prepareSettings(); if (upTo == Stage.LoadSettings) { return; } prepareProjects(); if (upTo == Stage.Configure) { return; } prepareTaskGraph(); if (upTo == Stage.ScheduleTasks) { return; } prepareTaskExecution(); } 复制代码
最终执行的为prepareTaskExecution。最初执行的为prepareSetting,对应的周期阶段为LoadtingSetting.
SettingPreparer开启LoadSetting
preparesetting方法内部调用SettingPrepare的preparesetting方法,开始任务,同时执行前,将Stage设置为LoadSetting。
private void prepareSettings() { controller.transitionIfNotPreviously(Stage.Created, Stage.LoadSettings, () -> settingsPreparer.prepareSettings(gradle)); } 复制代码
其对应的实现类为DefaultSettingsPreparer,其具体流程如下
判断是否为RootBuild,如果是,从顶层开始,否则从内部开始
然后查找对应的Setting.gradle并加载
@Override public void prepareSettings(GradleInternal gradle) { SettingsLoader settingsLoader = gradle.isRootBuild() ? settingsLoaderFactory.forTopLevelBuild() : settingsLoaderFactory.forNestedBuild(); settingsLoader.findAndLoadSettings(gradle); } 复制代码
我们以RootBuild为例分析,其调用forTopLenvelBuild方法,返回对应的SettingLoader,其类似其他代码,通过逐级代理,预处理任务,最终的SettingLoader为DefaultSettingsLoader�
public SettingsLoader forTopLevelBuild() { return new GradlePropertiesHandlingSettingsLoader( new InitScriptHandlingSettingsLoader( new CompositeBuildSettingsLoader( new ChildBuildRegisteringSettingsLoader( new CommandLineIncludedBuildSettingsLoader( defaultSettingsLoader() ), buildRegistry, buildIncluder), buildRegistry), initScriptHandler), buildLayoutFactory, gradlePropertiesController ); } 复制代码
DefalutSeetingLoader查找处理_setting.gradle_
�其类注释说明其功能,定位和处理setting.gradle文件,读取里面配置的Module. 上面最后会调用findAndLoadSettings,我们查看源码,探究其如何定位和处理对应的文件
public SettingsInternal findAndLoadSettings(GradleInternal gradle) { StartParameter startParameter = gradle.getStartParameter(); //获取构建项目下setting文件或目录 SettingsLocation settingsLocation = buildLayoutFactory.getLayoutFor(new BuildLayoutConfiguration(startParameter)); //根据查找的文件,加载读取内容 SettingsInternal settings = findSettingsAndLoadIfAppropriate(gradle, startParameter, settingsLocation, gradle.getClassLoaderScope()); ProjectSpec spec = ProjectSpecs.forStartParameter(startParameter, settings); if (useEmptySettings(spec, settings, startParameter)) { settings = createEmptySettings(gradle, startParameter, settings.getClassLoaderScope()); } //根据setting项目描述配置rootProjet相关信息 setDefaultProject(spec, settings); return settings; } 复制代码
定位setting文件
其首先获取我们项目整体目录,然后在其目录下获取setting.gradle文件
构建项目是否使用空setting结构,如是则直接返回空
获取目录下setting文件
如果存在检测是否为文件,否则抛出异常
如果存在则返回对应的Buildlayout
BuildLayout会保护具体文件的地址信息
public BuildLayout getLayoutFor(BuildLayoutConfiguration configuration) { if (configuration.isUseEmptySettings()) { return buildLayoutFrom(configuration, null); } File explicitSettingsFile = configuration.getSettingsFile(); if (explicitSettingsFile != null) { if (!explicitSettingsFile.isFile()) { throw new MissingResourceException(explicitSettingsFile.toURI(), String.format("Could not read settings file '%s' as it does not exist.", explicitSettingsFile.getAbsolutePath())); } return buildLayoutFrom(configuration, explicitSettingsFile); } return getLayoutFor(configuration.getCurrentDir(), configuration.isSearchUpwards()); } 复制代码
public BuildLayout(File rootDirectory, File settingsDir, @Nullable File settingsFile, ScriptFileResolver scriptFileResolver) { super(settingsDir, settingsFile); this.rootDirectory = rootDirectory; this.scriptFileResolver = scriptFileResolver; } 复制代码
加载setting.gradle文件
其通过SettingProcessor处理对应的文件,然后返回SettingInternal类
/** * Finds the settings.gradle for the given startParameter, and loads it if contains the project selected by the * startParameter, or if the startParameter explicitly specifies a settings script. If the settings file is not * loaded (executed), then a null is returned. */ private SettingsInternal findSettingsAndLoadIfAppropriate( GradleInternal gradle, StartParameter startParameter, SettingsLocation settingsLocation, ClassLoaderScope classLoaderScope ) { SettingsInternal settings = settingsProcessor.process(gradle, settingsLocation, classLoaderScope, startParameter); validate(settings); return settings; } 复制代码
SettingInternal具体实现类为DefalutSetting,其中settingsProcessor有多个实现类,类似上面的处理,其也是逐级嵌套,最终的为**ScriptEvaluatingSettingsProcessor,**我们看起代码 �发现其会加载对应文件里的内容,然后创建SettingsInternal
public SettingsInternal process(GradleInternal gradle, SettingsLocation settingsLocation, ClassLoaderScope baseClassLoaderScope, StartParameter startParameter) { //统计时间配置 Timer settingsProcessingClock = Time.startTimer(); //解析gradleProperties文件的配置信息 Map<String, String> properties = gradleProperties.mergeProperties(emptyMap()); //解析里面的内容,并加载 TextResourceScriptSource settingsScript = new TextResourceScriptSource(textFileResourceLoader.loadFile("settings file", settingsLocation.getSettingsFile())); //创建SettingInternal SettingsInternal settings = settingsFactory.createSettings(gradle, settingsLocation.getSettingsDir(), settingsScript, properties, startParameter, baseClassLoaderScope); gradle.getBuildListenerBroadcaster().beforeSettings(settings); applySettingsScript(settingsScript, settings); LOGGER.debug("Timing: Processing settings took: {}", settingsProcessingClock.getElapsed()); return settings; } 复制代码
创建Settinginternal
public SettingsInternal createSettings(...){ ClassLoaderScope classLoaderScope = baseClassLoaderScope.createChild("settings[" + gradle.getIdentityPath() + "]"); ScriptHandlerInternal settingsScriptHandler = scriptHandlerFactory.create(settingsScript, classLoaderScope); DefaultSettings settings = instantiator.newInstance(DefaultSettings.class, serviceRegistryFactory, gradle, classLoaderScope, baseClassLoaderScope, settingsScriptHandler, settingsDir, settingsScript, startParameter ); DynamicObject dynamicObject = ((DynamicObjectAware) settings).getAsDynamicObject(); ((ExtensibleDynamicObject) dynamicObject).addProperties(gradleProperties); return settings; } 复制代码
总结
到这里LoadSetting就结束了,其主要做了以下工作
查找setting文件
加载解析gradle.properties文件
解析setting文件内容,并创建对应的类:DefalutSetting
Configure
项目配置阶段入口方法为 prepareProjects,与LoadSetting类似,其也有对应的Prepare处理,其为ProjectPrepare
private void prepareProjects() { controller.transitionIfNotPreviously(Stage.LoadSettings, Stage.Configure, () -> projectsPreparer.prepareProjects(gradle)); } 复制代码
ProjectsPreparer
其方法传入的参数GradleInternal,包含了上一阶段处理完的settings 对象配置,即DefalutSetting. 其对应的实现类为DefalutProjectsPreparer.同样与LoadSetting类似,其也判断是否为RootBuild,同时其也会判断是否配置的后台
if (buildModelParameters.isConfigureOnDemand() && gradle.isRootBuild()) { projectConfigurer.configure(gradle.getRootProject()); } else { projectConfigurer.configureHierarchy(gradle.getRootProject()); new ProjectsEvaluatedNotifier(buildOperationExecutor).notify(gradle); } 复制代码
无论何种情况,都有ProjectConfigurer处理
TaskPathProjectEvaluator处理Project
ProjectConfigurer的实现类为TaskPathProjectEvaluator。两个方法的区别时,configureHierarchyFully会先配置自己,然后依次遍历配置每一个项目,最终入口都是config.因此我们就直接分析config。
@Override public void configureHierarchy(ProjectInternal project) { configure(project); for (Project sub : project.getSubprojects()) { configure((ProjectInternal) sub); } } @Override public void configure(ProjectInternal project) { if (cancellationToken.isCancellationRequested()) { throw new BuildCancelledException(); } // Need to configure intermediate parent projects for configure-on-demand ProjectInternal parentProject = project.getParent(); if (parentProject != null) { configure(parentProject); } project.getOwner().ensureConfigured(); } 复制代码
最终调用eensureConfigured,通过层层导演,最终会调用ProjectConfigureAction的execute方法
//in class ConfigureActionsProjectEvaluator @Override public void evaluate(ProjectInternal project, ProjectStateInternal state) { for (ProjectConfigureAction configureAction : configureActions) { configureAction.execute(project); } } 复制代码
ProjectConfigureAction的实现类有多个,我们看该类注释
/** * Can be implemented by plugins to auto-configure each project. * * <p>Implementations are discovered using the JAR service locator mechanism (see {@link org.gradle.internal.service.ServiceLocator}). * Each action is invoked for each project that is to be configured, before the project has been configured. Actions are executed * in an arbitrary order. */ public interface ProjectConfigureAction extends Action<ProjectInternal> { } 复制代码
其可被对应的插件实现,去配置每一个项目,这样结合我们在开发android项目都会使用插件,这样当执行到此阶段,即会自动配置,因此我们直接看对应的实现,即PluginsProjectConfigureActions�
PluginsProjectConfigureActions自动配置每个Project
@Override public void execute(ProjectInternal project) { for (Action<ProjectInternal> action : actions) { action.execute(project); } } 复制代码
到这里配置阶段结束,具体的配置有具体的插件实现,其会在此阶段配置好自己。我们WrapperPluginAutoApplyAction为例,其最终会调用我们对应插件的apply方法。
public void execute(ProjectInternal project) { project.getPluginManager().apply("org.gradle.wrapper"); } 复制代码
这里配置的是wrapper这个插件。我们查看给方法注释
/** * Applies the plugin with the given ID. Does nothing if * the plugin has already been applied. * <p> * Plugins in the {@code "org.gradle"} namespace can be applied *directly via name. * That is, the following two lines are equivalent… * <pre> * pluginManager.apply "org.gradle.java" * pluginManager.apply "java" * </pre> * * @param pluginId the ID of the plugin to apply * @since 2.3 */ void apply(String pluginId); 复制代码
总结
该阶段主要会默认配置org.gradle下的Project,然后调用具体每个插件的实现,配置每个插件。
TaskGraph
接下来是task有向图的构建,其在上一阶段的基础上,配置每个task的依赖关系。
ScheduleTasks
分析任务图的构建我们需要回到流程图分析那里,其调用VintageBuildController.doBuildStage的发起点是在DefaultTreeWorkPrepare.这里其分成了多个阶段,即其首先调用doBuildStage达到_TaskSchedule_ �阶段,然后调用populateTaskGraph真正的构建任务图**。**我们看起代码
// in the DefaultTreeWorkPrepare @Override public void scheduleRequestedTasks() { //该方法到达TaskSchedule buildController.prepareToScheduleTasks(); //完成真正task有向图构建 includedBuildTaskGraph.prepareTaskGraph(() -> { //处理初步任务有向图 buildController.scheduleRequestedTasks(); //填充任务图 includedBuildTaskGraph.populateTaskGraphs(); //结束构建,根据输入发起任务 buildController.finalizeWorkGraph(true); }); } 复制代码
prepareTaskGraph
doBuildStages内部,在执行完配置后,进入下一个阶段,调用该方法,将其Stage转移到ScheduTasks,我们查看源码看起做了什么工作 其通过TaskGraphPrepares的prepareForTaskScheduling开启处理
private void prepareTaskGraph() { controller.transitionIfNotPreviously(Stage.Configure, Stage.ScheduleTasks, () -> taskGraphPreparer.prepareForTaskScheduling(gradle)); } 复制代码
TaskGraphPrepares有两个实现类,类似上面的处理也是逐级嵌套依次处理。其分别是:
DefaultTaskSchedulingPreparer
�ExcludedTaskFilteringProjectsPreparer
其中 DefaultTaskSchedulingPreparer存在delegate,因此其不是不最终的调用而是ExcludedTaskFilteringProjectsPreparer
//DefaultTaskSchedulingPreparer @Override public void prepareForTaskScheduling(GradleInternal gradle) { // Make root build substitutions available if (gradle.isRootBuild()) { buildStateRegistry.afterConfigureRootBuild(); } delegate.prepareForTaskScheduling(gradle); } // ExcludedTaskFilteringProjectsPreparer @Override public void prepareForTaskScheduling(GradleInternal gradle) { Set<String> excludedTaskNames = gradle.getStartParameter().getExcludedTaskNames(); if (!excludedTaskNames.isEmpty()) { final Set<Spec<Task>> filters = new HashSet<Spec<Task>>(); for (String taskName : excludedTaskNames) { filters.add(taskSelector.getFilter(taskName)); } gradle.getTaskGraph().useFilter(Specs.intersect(filters)); } } 复制代码
查看代码我们知道,这里主要做了两部分工作
DefaultTaskSchedulingPreparer通知项目配置完成
将不需要添加到依赖图的任务排除
prepareTaskGraph
IncludedBuildTaskGraph在VintageBuildController.doBuildStage到达ScheduleTask后,完成前期工作后开始构建任务图,其实现类为DefalutIncludedBuildTaskGraph
/** * Does the work to schedule tasks and prepare the task graphs for execution. */ void prepareTaskGraph(Runnable action){ withState(() -> { expectInState(State.NotPrepared); state = State.QueuingTasks; buildOperationExecutor.run(new RunnableBuildOperation() { @Override public void run(BuildOperationContext context) { action.run(); context.setResult(new CalculateTreeTaskGraphBuildOperationType.Result() { }); } @Override public BuildOperationDescriptor.Builder description() { return BuildOperationDescriptor .displayName("Calculate build tree task graph") .details(new CalculateTreeTaskGraphBuildOperationType.Details() { }); } }); expectInState(State.Populated); state = State.ReadyToRun; return } 复制代码
该方法是通过CalculateTreeTaskGraphBuildOperationType告知我们做了什么,同时保存结果。其真正的工作是action.run,其实际调用的就是里面包裹的方法
/** * Computing the task graph for the build tree based on the inputs * and build configuration. */ public final class CalculateTreeTaskGraphBuildOperationTyp 复制代码
includedBuildTaskGraph.prepareTaskGraph(() -> { buildController.scheduleRequestedTasks(); includedBuildTaskGraph.populateTaskGraphs(); buildController.finalizeWorkGraph(true); }) 复制代码
TaskExecution
其主要为task的执行配置Gradle对象,其是通过TaskExecutionPreparer的prepareForTaskExecution发起
/** * Responsible for preparing `Gradle` instances for task execution. The result is passed to a {@link org.gradle.execution.BuildWorkExecutor} for execution. Prior to preparing for task execution, the `Gradle` instance has its projects configured by a {@link org.gradle.configuration.ProjectsPreparer}. * * <p>This includes resolving the entry tasks and calculating the task graph.</p> */ public interface TaskExecutionPreparer { void prepareForTaskExecution(GradleInternal gradle); } 复制代码
�查看类注释,其主要解决Task入口,和任务图计算,其实现类为DefaultTaskExecutionPreparer,
@Override public void prepareForTaskExecution(GradleInternal gradle) { buildConfigurationActionExecuter.select(gradle); if (buildModelParameters.isConfigureOnDemand() && gradle.isRootBuild()) { new ProjectsEvaluatedNotifier(buildOperationExecutor).notify(gradle); } } 复制代码
�其核心在第一个调用,其会对任务进行选择. 其通过buildConfigurationActionExecuter的seletc发起
@Override public void select(final GradleInternal gradle) { // We know that we're running single-threaded here, so we can use coarse grained locks projectStateRegistry.withMutableStateOfAllProjects(() -> { configure(taskSelectors, gradle, 0); }); } 复制代码
其中configure内部为遍历taskSelectors,依次取出每一个taskSelector,即BuildConfigurationAction �然后调用其config去筛选计算任务。
rivate void configure(final List<? extends BuildConfigurationAction> processingConfigurationActions, final GradleInternal gradle, final int index) { if (index >= processingConfigurationActions.size()) { return; } processingConfigurationActions.get(index).configure(new BuildExecutionContext() { @Override public GradleInternal getGradle() { return gradle; } @Override public void proceed() { configure(processingConfigurationActions, gradle, index + 1); } }); } 复制代码
BuildConfigurationAction
其默认有两个实现类,因此遍历即分别调用这两个类
DefaultTasksBuildExecutionAction
TaskNameResolvingBuildConfigurationAction
TaskNameResolvingBuildConfigurationAction
其根据平常去构建taskGraph
@Override public void configure(BuildExecutionContext context) { GradleInternal gradle = context.getGradle(); TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph(); List<TaskExecutionRequest> taskParameters = gradle.getStartParameter().getTaskRequests(); for (TaskExecutionRequest taskParameter : taskParameters) { List<TaskSelection> taskSelections = commandLineTaskParser.parseTasks(taskParameter); for (TaskSelection taskSelection : taskSelections) { LOGGER.info("Selected primary task '{}' from project {}", taskSelection.getTaskName(), taskSelection.getProjectPath()); //添加到taskGraph taskGraph.addEntryTasks(taskSelection.getTasks()); } } context.proceed(); } 复制代码
DefaultTasksBuildExecutionAction
�其是处理project默认的task,如果没有会为其添加helpTask
public void configure(BuildExecutionContext context) { StartParameter startParameter = context.getGradle().getStartParameter(); for (TaskExecutionRequest request : startParameter.getTaskRequests()) { if (!request.getArgs().isEmpty()) { context.proceed(); return; } } // 获取Project默认的Tasks ProjectInternal project = context.getGradle().getDefaultProject(); //so that we don't miss out default tasks projectConfigurer.configure(project); //处理默认的task List<String> defaultTasks = project.getDefaultTasks(); if (defaultTasks.size() == 0) { defaultTasks = new ArrayList<>(); for (BuiltInCommand command : builtInCommands) { defaultTasks.addAll(command.asDefaultTask()); } LOGGER.info("No tasks specified. Using default task {}", GUtil.toString(defaultTasks)); } else { LOGGER.info("No tasks specified. Using project default tasks {}", GUtil.toString(defaultTasks)); } //将处理后的tasks,设置到参数里,交由我们上面分析的TaskNameResolvingBuildConfigurationAction //处理 startParameter.setTaskNames(defaultTasks); context.proceed(); } 复制代码
到这里,通过doBuildStage中的prepareForTaskExecution,我们将处理后的任务添加到了taskGraph中。
populateTaskGraphs
该方法完成任务图的填充。
/** * Finish populating task graphs, once all entry point tasks have been scheduled. */ void populateTaskGraphs(); @Override public void populateTaskGraphs() { withState(() -> { assertCanQueueTask(); includedBuilds.populateTaskGraphs(); state = State.Populated; return null; }); } 复制代码
Controller填充任务图
填充任务图具体有对应的IncludeBuildControllers完成
@Override public void populateTaskGraphs() { boolean tasksDiscovered = true; while (tasksDiscovered) { tasksDiscovered = false; for (IncludedBuildController buildController : ImmutableList.copyOf(buildControllers.values())) { if (buildController.populateTaskGraph()) { tasksDiscovered = true; } } } for (IncludedBuildController buildController : buildControllers.values()) { buildController.prepareForExecution(); } } 复制代码
到这里就完成了任务图的构建,同时为下一步任务执行做好准备,触发时间开始执行任务
finalizeWorkGraph
�其会调用taskGraph的polulate,如果一切就绪
@Override public void finalizeWorkGraph(boolean workScheduled) { if (workScheduled) { TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph(); taskGraph.populate(); } finalizeGradleServices(gradle); } 复制代码
我们查看该方法对应的注释
/** * Does the work to populate the task graph based on tasks that have been added. Fires events and no further tasks should be added. */ void populate(); 复制代码
后续具体执行这里就不分析了。
总结
经过上面的整个分析,我们就清楚的知道了,当我们在AndroidStudio中敲下命令后,其如何去检测我们gradle的版本,并进行下载。同时我们项目中的setting.gradle的作用,最后就是任务如何添加,依赖关系如何构建。其中有的地方逻辑比较复杂,这里没有去深入分析,重点是掌握其整个流程。后续有需要,我们就可深入去分析研究它。
作者:莫名Font
链接:https://juejin.cn/post/7032885152132890637