本篇文章已受权微信公众号 guolin_blog (郭霖)独家发布
java
从Android Plugin源码开始完全理解gradle构建:初识AndroidDSL(一)json
上回咱们说到Android plugin的全部自定义plugin都须要重写的apply方法,并讲到该方法里最为重要的三个回调方法,咱们回顾一下:微信
//plugin的基础设置、初始化工做 threadRecorder.record( ExecutionType.BASE_PLUGIN_PROJECT_CONFIGURE, project.getPath(), null, this::configureProject); //EXTENSION的初始化工做 threadRecorder.record( ExecutionType.BASE_PLUGIN_PROJECT_BASE_EXTENSION_CREATION, project.getPath(), null, this::configureExtension); //plugin的task建立 threadRecorder.record( ExecutionType.BASE_PLUGIN_PROJECT_TASKS_CREATION, project.getPath(), null, this::createTasks);
上一篇文章咱们简单讲解第一个初始化方法,今天咱们的主角就是第二个configureExtension方法app
Extension到底是什么?就我理解,能够把gradle的Extension比喻为JAVA的成员变量。虽然不彻底相同,可是也有类似之处,何出此言?让咱们继续往下看。
ide
讲解以前咱们先看一段熟悉的代码:学习
android { compileSdkVersion 26 defaultConfig { applicationId "com.example.gradletest" minSdkVersion 15 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } }
相信这段代码在座的各位都看吐了吧?gradle
是的,笔者也同样。刚开始接触AS的时候,看这段代码感受就感受在看天书,反正按规定配置就对了。今天咱们就把他扒光了看看有什么特别。ui
仔细观察其实也比较好理解,就是android的一些配置:this
compileSdkVersion指的是当前的androidSDK版本、applicationId指的是包名、versionCode指的是版本号....balabala...
虽然通过几年的百度、谷歌熏陶已经很熟悉了,可是为何这么配置呢?接下来就为各位看官解答。
咱们能够把一个gradle项目看作一个Project,而这个Project就相似JAVA的类,而一个类天然就须要成员变量咯,因此咱们首先就来建立一个pojo类,就命名为Person吧:
public class Person { String name; int age; @Override public String toString() { return "I am $name, $age years old" } }
而后就像上篇文章那样建立一个自定义插件:
class MyPlugin implements Plugin<Project>{ @Override void apply(Project project) { project.extensions.add("person", Person) project.task('printPerson') { group 'atom' doLast{
Person ext = project.person println ext } } } }第一句调用了project的extensions,他能够视为变量的容器,只要往里加就OK了,而后就能够经过project调用到person了
第二句是咱们下节须要讲到的内容,能够暂时无视,直接看dolast里面的代码就行了
很简单,我直接打印了该person,接下来就是重点了,咱们须要在build.gradle里面配置person
person{ name 'atom' age 18 }
是否是就像android的标签同样?这下应该很好理解gradle里为什么这么写了吧。
其实这里就至关于咱们给person作了初始化,只是用有些像json的写法而已。
不过这样咱们就能够配置项目参数了,是否是很方便?
咱们来验证一下,执行一下gradle printPerson命令:
如咱们所想,打印了咱们配置的18岁的atom:)
private void configureExtension() { ObjectFactory objectFactory = project.getObjects(); //1============== final NamedDomainObjectContainer<BuildType> buildTypeContainer = project.container( BuildType.class, new BuildTypeFactory( objectFactory, project, extraModelInfo.getSyncIssueHandler(), extraModelInfo.getDeprecationReporter())); final NamedDomainObjectContainer<ProductFlavor> productFlavorContainer = project.container( ProductFlavor.class, new ProductFlavorFactory( objectFactory, project, extraModelInfo.getDeprecationReporter(), project.getLogger())); final NamedDomainObjectContainer<SigningConfig> signingConfigContainer = project.container( SigningConfig.class, new SigningConfigFactory( objectFactory, GradleKeystoreHelper.getDefaultDebugKeystoreLocation())); final NamedDomainObjectContainer<BaseVariantOutput> buildOutputs = project.container(BaseVariantOutput.class); project.getExtensions().add("buildOutputs", buildOutputs); sourceSetManager = createSourceSetManager(); //2============== extension = createExtension( project, projectOptions, androidBuilder, sdkHandler, buildTypeContainer, productFlavorContainer, signingConfigContainer, buildOutputs, sourceSetManager, extraModelInfo); ndkHandler = new NdkHandler( project.getRootDir(), null, /* compileSkdVersion, this will be set in afterEvaluate */ "gcc", "" /*toolchainVersion*/, false /* useUnifiedHeaders */); @Nullable FileCache buildCache = BuildCacheUtils.createBuildCacheIfEnabled(project, projectOptions); GlobalScope globalScope = new GlobalScope( project, projectOptions, androidBuilder, extension, sdkHandler, ndkHandler, registry, buildCache); //3=============================== variantFactory = createVariantFactory(globalScope, androidBuilder, extension); taskManager = createTaskManager( globalScope, project, projectOptions, androidBuilder, dataBindingBuilder, extension, sdkHandler, ndkHandler, registry, threadRecorder); variantManager = new VariantManager( globalScope, project, projectOptions, androidBuilder, extension, variantFactory, taskManager, sourceSetManager, threadRecorder); //省略部分代码 // create default Objects, signingConfig first as its used by the BuildTypes. variantFactory.createDefaultComponents( buildTypeContainer, productFlavorContainer, signingConfigContainer); }一、首先建立了四个NamedDomainObjectContainer,是由project的Container方法返回的,这些东东是什么有什么用,光靠百度谷歌基本上是很难找到了(笔者写这篇文章的时候gradle方面的资料仍是至关匮乏的),因此咱们得学会看官方文档咯~
因此根据上诉代码,不难知道建立了BuildType、ProductFlavor、SigningConfig、BaseVariantOutput这四个类的容器了。
稍微熟悉构建的童鞋应该很清楚这几个类的用处:
buildType
构建类型,在Android Gradle工程中,它已经帮咱们内置了debug和release两个构建类型,能够分别设置不一样包名等信息。
signingConfigs
签名配置,能够设置debug和release甚至自定义方式时的不一样keystore,及其密码等信息。
ProductFlavor
多渠道打包必备,用处不少笔者也有推荐文章介绍
而最后一个BaseVariantOutput,“望文生义“不难才到就是输出文件咯~
二、把project、androidBuilder以及刚刚提到的几个类做为参数建立了extension,这里使用了策略模式,createExtension是一个抽象方法,真正实现是在AppPlugin
protected BaseExtension createExtension( @NonNull Project project, @NonNull ProjectOptions projectOptions, @NonNull AndroidBuilder androidBuilder, @NonNull SdkHandler sdkHandler, @NonNull NamedDomainObjectContainer<BuildType> buildTypeContainer, @NonNull NamedDomainObjectContainer<ProductFlavor> productFlavorContainer, @NonNull NamedDomainObjectContainer<SigningConfig> signingConfigContainer, @NonNull NamedDomainObjectContainer<BaseVariantOutput> buildOutputs, @NonNull SourceSetManager sourceSetManager, @NonNull ExtraModelInfo extraModelInfo) { return project.getExtensions() .create( "android", AppExtension.class, project, projectOptions, androidBuilder, sdkHandler, buildTypeContainer, productFlavorContainer, signingConfigContainer, buildOutputs, sourceSetManager, extraModelInfo); }
就如同咱们以前介绍建立Extension的方式同样,经过project建立了名为“android”的Extension,类型为AppExtension,这个类就包含了咱们平时用到的版本号、包名等等信息,为咱们构建项目打下了基础。
三、用一样的方式建立了variantFactory、taskManager、variantManager,最后设置了默认的构建信息。
关于这几个类的做用分别是:
variantFactory构建信息的工厂、taskManager构建任务、variantManager各类不一样构建方式及多渠道构建的管理
这就涉及到gradle核心:task了,也是下一篇文章须要讲的内容,你们敬请关注。
本文主要介绍了build中配置信息写法的由来,让你们看到配置信息时再也不那么没有底气。
不知道你们有没有发现,我例子中使用的groovy语法来写插件,而Android Plugin确是使用Java来写的
具体缘由不明,可是能够看出,groovy是彻底兼容Java的,若是你想的话甚至可使用kotlin来写,最新版本的AndroidDSL也加入了kotlin代码。可是仍是推荐学习groovy的基本用法,毕竟也有喜欢使用groovy来写插件的,咱们得看的懂对吧,好比virtualAPK~