谈起Gradle开发,自然就需要先从最基础的两个配置文件build.gradle以及settings.gradle说起,那其实对应的Gradle API类就是org.gradle.api.Project和org.gradle.api.initialization.Settings,而定义在文件中熟悉的闭包配置对应的则是类方法以及各种拓展Extension。
Settings
对于Settings的认识,相信大多数都是停留在settings.gradle文件中添加include项目配置,但是能做的不仅于此,我们就此从创建、设置加载来完整了解一遍。
创建
Settings的创建跟org.gradle.initialization.ScriptEvaluatingSettingsProcessor以及org.gradle.initialization.SettingsFactory两个类息息相关。
Gradle首先会通过BuildScopeServices的createSettingsProcessor方法创建一个SettingsProcessor,这个类主要是通过ScriptEvaluatingSettingsProcessor来进行构造,然后借助其process方法来创建Settings的实例。
public SettingsInternal process(GradleInternal gradle,
SettingsLocation settingsLocation,
ClassLoaderScope buildRootClassLoaderScope,
StartParameter startParameter) {
Timer settingsProcessingClock = Time.startTimer();
Map<String, String> properties = propertiesLoader.mergeProperties(Collections.<String, String>emptyMap());
TextResourceScriptSource settingsScript = new TextResourceScriptSource(textResourceLoader.loadFile("settings file", settingsLocation.getSettingsFile()));
SettingsInternal settings = settingsFactory.createSettings(gradle, settingsLocation.getSettingsDir(), settingsScript, properties, startParameter, buildRootClassLoaderScope);
applySettingsScript(settingsScript, settings);
LOGGER.debug("Timing: Processing settings took: {}", settingsProcessingClock.getElapsed());
return settings;
}
从上述代码中得知该方法主要做了三件事情:
- 根据
settings.gradle文件构造TextResourceScriptSource对象settingsScript - 通过
settingsFactory创建一个SettingsInternal实例 - 调用
applySettingsScript方法将settings.gradle中的闭包配置装载到SettingsInternal实例中
第2和3步都需要用到TextResourceScriptSource,这个具体作用是什么呢?
TextResourceScriptSource
public class TextResourceScriptSource implements ScriptSource {
private final TextResource resource;
private String className;
...
}
这个类主要作用是通过URI读取指定的配置脚本源码以及生成对应的className,这里对应的就是settings.gradle配置文件,并且作为构造函数参数生成ScriptCompiler来把脚本文件编译成一个object对象。
SettingsFactory
再来看下SettingsFactory的createSettings方法:
public class SettingsFactory {
...
public SettingsInternal createSettings(GradleInternal gradle, File settingsDir, ScriptSource settingsScript,
Map<String, String> gradleProperties, StartParameter startParameter,
ClassLoaderScope buildRootClassLoaderScope) {
ClassLoaderScope settingsClassLoaderScope = buildRootClassLoaderScope.createChild("settings");
ScriptHandlerInternal settingsScriptHandler = scriptHandlerFactory.create(settingsScript, settingsClassLoaderScope);
DefaultSettings settings = instantiator.newInstance(DefaultSettings.class,
serviceRegistryFactory, gradle,
settingsClassLoaderScope, buildRootClassLoaderScope, settingsScriptHandler,
settingsDir, settingsScript, startParameter
);
...
return settings;
}
}
通过Instantiator创建了一个DefaultSettings类型的实例。
到这里settings.gradle对应的Settings实例就创建完毕了,接着就是把定义在文件中的闭包设置加载到实例中,整个过程就结束了。
配置
还记得上面的SettingsInternal中process第三步吗,那就是对settings.gradle文件中定义的配置进行应用。
private void applySettingsScript(TextResourceScriptSource settingsScript, final SettingsInternal settings) {
ClassLoaderScope settingsClassLoaderScope = settings.getClassLoaderScope();
ScriptPlugin configurer = configurerFactory.create(settingsScript, settings.getBuildscript(), settingsClassLoaderScope, settings.getRootClassLoaderScope(), true);
configurer.apply(settings);
}
通过ScriptPluginFactory生成ScriptPlugin,然后调用其apply方法加载对应的配置。
Settings.gradle
对于settings.gradle文件来说,我们最常见的配置如下:
include ':app'
那除此之外还能干什么呢?
其实,这里主要作用是用来定义这个工程有哪些module,并且定义其ProjectName以及对应的工程目录。那这里我们可以用来在整个工程的Project配置装载前做一些初始化的事情,例如生成动态module、配置构建缓存、配置module对应的BuildFile、插件冲突配置等。
具体能应用的配置可以查看org.gradle.api.initialization.Settings公开的API,每一个方法对应的都是一种配置选项。
例如,include ':app'对应的是void include(String... projectPaths)方法,而project(':annotation')对应的是ProjectDescriptor project(String path)方法,更多的脚本配置可以自行查询。
另外,这里也能applyGradle插件,会在后续的插件文章中详细说明,至此Settings就先到此为止了。
Project
对于每一个在settings.gradle中用include进行申明配置的module都对应一个Project实例,而对project而已,相应的构建配置是在对应项目根目录下的build.gradle中进行申明。
build.gradle
虽然配置文件中闭包配置对应都是同一个org.gradle.api.Project中的API,但是因为不同project所需要apply的gradle plugin会有所不同,因此导致看起来配置会稍有差异,尤其rootProject和project,但是根源本质是一致的。
我们先从接触最多的project配置文件开始着手
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
defaultConfig {
applicationId "xx.yy.demo"
minSdkVersion 14
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
}
这是最常见的一个配置,简单但是功能齐全,接着我们来根据配置从上到下分析gradle到底干了什么,配置的选项在编译过程中起什么作用。
- 首先调用
project的void apply(Map<String, ?> options)方法把com.android.build.gradle.AppPlugin插件进行装载,如果apply的是com.android.library则对应的是com.android.build.gradle.LibraryPlugin插件。 - 接下来是熟悉的
andoird{ ... },这其实是上述提到的AppPlugin插件的extension配置,对应的是com.android.build.gradle.AppExtension,当然如果是LibraryPlugin插件则对应的是com.android.build.gradle.LibraryPlugin,闭包中的每一个配置选项都是对应相应extension类中的方法。 - 最后是
dependencies{...},这里是配置当前module编译所需要依赖的第三方库,实际对应的是先getDependencies()获取org.gradle.api.artifacts.dsl.DependencyHandler对象,然后调用其Dependency add(String configurationName, Object dependencyNotation)方法对其中定义的依赖配置进行添加。
至此,所对应的配置会在configure project过程中调用其对应的方法进行配置装载,后续应用到编译过程中。
build.gradle闭包配置先到此为止,更多配置例如task ...等其实跟上述一样是调用Task task(String name)方法,接下来说说project常用的几个方法。
DependencyHandler
从上述我们得知,增加第三方库依赖是调用Dependency add(String configurationName, Object dependencyNotation)方法,其中的api、implementation、runtimeOnly等其实是AppPlugin等插件中预先声明的configurationName,而dependencyNotation进行添加后则返回对应的实例对象。例如:
-
fileTree(dir: 'libs', include: ['*.jar'])---org.gradle.api.internal.artifacts.dependencies.DefaultSelfResolvingDependency -
project(':xxxx')---org.gradle.api.internal.artifacts.dependencies.DefaultProjectDependency -
'com.android.support:appcompat-v7:27.1.1'---org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency
因此,我们也可以在自己的插件中自定义configurationName,例如:
project.beforeEvaluate {
Configuration customConfiguration = it.configurations.create("configurationName")
customConfiguration.allDependencies.all{dependency ->
//dependency进行处理
...
}
}
beforeEvaluate / afterEvaluate
这两个方法是project最常用的两个方法:
-
beforeEvaluate是设置project进行evaluate也就是对build.gradle进行配置加载之前的回调,适合apply plugin、定义Configuration等场景。 -
afterEvaluate则是project进行配置加载之后的回调,适合需要根据配置的信息来进行操作的场景,因为在build.gradle中配置的extension要在afterEvaluate才能拿到。
hasProperty / getProperties
从方法名就可以猜到,是对project定义的属性数据进行操作,也就是闭包配置
ext{
key = "value"
}
好了,project就先介绍到这了,更多的方法可以自行查询API和对应的注释信息。
后记
project和settings的介绍就先到这了,这是gradle开发的基础,了解清楚就相当于迈过了入门的门槛石,随节会对其中的task进行深入介绍。













网友评论