Android 自定义Task添加到任务队列
Posted 好人静
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 自定义Task添加到任务队列相关的知识,希望对你有一定的参考价值。
前言
逐步整理的一系列的总结:
android 自定义Task添加到任务队列(四)
Android Gradle 中的使用ASMified插件生成.class的技巧(九)
Android Gradle 中的实例之动态修改AndroidManifest文件(十)
在Android 自定义Gradle插件的完整流程(三)的3.Task中的属性扩展部分主要介绍的是将自定义插件中的自定义Task加入到被依赖module(即通过apply或者plugins添加该插件的那个module),其实我又仔细的想了想,为什么不直接把自定义的Task直接加入到当前插件的任务队列中呢?
一 关系梳理
在Android 自定义Gradle插件的完整流程(三)的3.Task中的属性扩展的第(3)步中主要在被依赖module执行apply或者plugins来应用该插件的时候,会执行到自定义插件的入口类的apply(project)的方法,我们此时将我们自定义的HandleTemplateTask添加到了依赖module的任务队列中,在编译阶段相应的输出内容如下:
//开始配置app这个module
> Configure project :app
<<<<<<<settings.gradle<<<<<<<<<< beforeProject Project name = app
//app 执行plugins,调用到该自定义插件的apply()方法
%%%%%%%%% FirstPluginProject %%%%%%%%% Apply the First Plugin Project
// app module已经完成配置
@@@@@@@@@@@@@@ app @@@@@@@@@@@@@ afterEvaluate
//开始配置自定义插件:即完成将插件的build.gradle的配置以及task的依赖关系图
> Configure project :firstplugin
<<<<<<<settings.gradle<<<<<<<<<< beforeProject Project name = firstplugin
//完成自定义插件工程的配置阶段
<<<<<<<settings.gradle<<<<<<<<<< projectsEvaluated 已经完成Gradle构建的配置阶段
//执行自定义插件的所有Tasks
> Task :firstplugin:compileJava NO-SOURCE
.........
//该自定义Task放到app的任务队列中执行
> Task :app:handleTemplateTask
%%%%%%%%% FirstPluginProject %%%%%%%%% HandleTemplateTask is running
%%%%%%%%% FirstPluginProject %%%%%%%%% Set the file format is " .java
%%%%%%%%% FirstPluginProject %%%%%%%%% Set the file source dir is " /Users/j1/Documents/android/code/AndroidPlugin/app/src/main/java/mvp
> Task :app:preBuild
> Task :app:preDebugBuild
.........
从这个任务输出信息中可以看到:
- (1)首先开始配置的是被依赖module(此实例为app这个module),即 “> Configure project :app”信息输出;
- (2)在配置被依赖module(此实例为app这个module)的时候,会首先调用到自定义插件(此实例为firstplugin这个module)的入口类的apply(project)的方法,即“%%%%%%%%% FirstPluginProject %%%%%%%%% Apply the First Plugin Project”信息的输出;
- (3)然后完成整个被依赖module(此实例为app这个module)的配置,然后才去配置自定义插件(此实例为firstplugin这个module),即“> Configure project :firstplugin”信息的输出;
- (4)最后就是依次执行自定义插件(此实例为firstplugin这个module)和被依赖module(此实例为app这个module)的任务队列,并且发现该自定义的HandleTemplateTask被加入到了被依赖module(此实例为app这个module)的任务队列中,即“> Task :app:handleTemplateTask”信息输出
从这些输出信息中可以得到以下结论:
- (1)在构建项目的生命周期中,被依赖module的配置阶段完成后,然后才会去配置自定义插件的配置阶段(这里重点标记下)
- (2)在被依赖module的配置阶段中,当配置apply或plugins的时候,会回调到自定义插件的入口类的apply(project)方法
- (3)当被依赖module以及该module下所有的plugins的配置阶段都完成后,会以此执行里面的task队列
二 在自定义插件中添加Task
本次主要就是去尝试下是不是可以将自定义的Task直接添加到自定义插件的task队列中,因为这个Task所执行的功能本来就是该插件自身的作用。另外如果上述的功能可以实现,那现在怎么去做属性扩展呢?
反思一下,那如果想把自定义的Task添加到自定义插件的task队列中,而入口类FirstPluginProject的apply(project)方法返回的project又是被依赖module,并且想到自定义插件的build.gradle就是该插件的Project对象,那么是不是就可以直接将自定义Task直接添加到该插件的build.gradle中呢?
为了区分在Android 自定义Gradle插件的完整流程(三)的3.Task中的属性扩展的添加task和扩展属性的方式:
- (1)重新定义HandleTemplateTaskInProject继承DefaultTask为自定义Task
- (2)重新定义TemplateSettingExtensionInProject为属性扩展类
具体代码的内容可参见github上面的代码,在这里不在贴出来。
1.添加属性扩展
- (1)第一次想到的实现方案
上一篇中也介绍了可以通过project.getExtensions().create()的方式来添加属性扩展,所以在该插件的build.gradle调用如下代码:
project.getExtensions().create(TemplateSettingExtensionInProject.TAG, TemplateSettingExtensionInProject)
但是发现当在被依赖module的build.gradle中使用templateSettingExtensionInProject的时候,直接语法错误,压根都不让编译。
因为此时的project仅仅是该插件的Project对象,那么上述代码的调用仅仅是对该插件的Project对象添加了属性扩展,所以在被依赖module的build.gradle中根本无法使用templateSettingExtensionInProject
- (2)第二次想到的实现方案
既然现在project返回的是该插件的Project对象,那么是不是可以找到被依赖那个module的Project对象,然后在被依赖module的Project对象添加属性扩展呢?然后就有了下面的实现方案:
/**
* 通过循环找到使用了该插件的module
*/
void createTemplateSettingExtensionInProjectForAllProject()
Set<Project> allProjectsInRoot = getRootProject().getAllprojects()
for (Project project : allProjectsInRoot)
List<Plugin> plugins = project.getPlugins().toList()
for (Plugin plugin : plugins)
//找到含有该插件的被依赖的project,添加该属性扩展
if (project.getPlugins().findPlugin(com.wj.plugin.FirstPluginProject))
project.getExtensions().create(TemplateSettingExtensionInProject.TAG, TemplateSettingExtensionInProject)
return
主要就是通过循环root project下所有的Project对象,然后看看哪个Project对象使用了该插件,然后在使用该插件的module下添加属性扩展。
本来信心十足,感觉现在已经可以在被依赖module中添加了属性扩展,并且在被依赖module中可以成功的添加templateSettingExtensionInProject属性扩展了,但是问题又来了,在编译的时候提示“ Could not find method templateSettingExtensionInProject() for arguments”。
为什么会出现这种情况呢?
这里就是前面在一 关系梳理中提到的需要重点标记的那个点“(1)在构建项目的生命周期中,被依赖module的配置阶段完成后,然后才会去配置自定义插件的配置阶段”。在被依赖module已经配置完成,而现在在插件的build.gradle中为才给被依赖module进行添加属性扩展,此时根本无法成功添加到被依赖module中了。
所以暂时认为要能够在被依赖module中进行属性扩展,那么只能在入口类的apply(project)中为返回的project(此时返回的就是被依赖module的Project对象)添加属性扩展,代码如下:
class FirstPluginProject implements Plugin<Project>
@Override
void apply(Project project)
........
/**为添加到build.gradle来增加扩展属性*/
createExtensionsForInProject(project)
void createExtensionsForInProject(project)
project.getExtensions().create(TemplateSettingExtensionInProject.TAG, TemplateSettingExtensionInProject)
........
但是问题又来了,因为这个属性扩展是添加到了被依赖module的getExtensions()中,那么在插件的build.gradle中怎么获取到getExtensions()呢?我找到了曲线救国的方式:
/**
* 找到设置了属性扩展的module中的属性扩展
* @return
*/
TemplateSettingExtensionInProject getTemplateSettingExtensionInProject()
Set<Project> allProjectsInRoot = getRootProject().getAllprojects()
for (Project project : allProjectsInRoot)
TemplateSettingExtensionInProject extension = project.getExtensions().findByName(TemplateSettingExtensionInProject.TAG)
if (extension != null)
return extension
return null
还是循环root project下的所有Project对象,然后获取哪个 Project对象的getExtensions()的内容不为null即可。
现在终于可以在被依赖module下可以对自定义插件进行属性扩展,现在在app的这个module的build.gradle中进行配置templateSettingExtensionInProject,如下:
templateSettingExtensionInProject
compileSdk = "1.0.0"
interfaceSourceDir = file("src/main/java/mvp")
2.将HandleTemplateTaskInProject添加到插件的project中
将HandleTemplateTaskInProject添加到自定义插件的build.gradle,代码如下:
/**(2)将功能的Task添加到app这个project的任务队列中*/
task handleTemplateTaskInProject(type: HandleTemplateTaskInProject)
this.afterEvaluate
//必须设置input,否则会抛出"No value has been specified for property"
String path = "/Users/j1/Documents/android/code/AndroidPlugin/firstplugin/src/main/groovy/com/wj/plugin/extension"
TemplateSettingExtensionInProject extension = getTemplateSettingExtensionInProject()
if (extension != null)
handleTemplateTaskInProject.setFileSourceDir(extension.interfaceSourceDir)
handleTemplateTaskInProject.setFileFormat(".java")
tasks.compileJava.dependsOn(handleTemplateTaskInProject)
因为TemplateSettingExtensionInProject只有在项目配置完成之后,才可以通过project.getExtensions().findByName()取到配置的值,所以在this.afterEvaluate将HandleTemplateTaskInProject添加到插件的任务队列中。
另外注意有一点:当增加HandleTemplateTaskInProject出现编译不通过的时候(譬如HandleTemplateTaskInProject里面新增或删除属性),需要删除plugins/里面的内容之后,删除在root project和被依赖的module中添加的插件依赖,重新编译该项目然后uploadArchives,最后在将该依赖添加到root project中 。
按照 Android Gradle插件开发初次交手(一)的4.插件发布方式进行发布插件,然后使用Android Studio编译整个工程,发现Build窗口输出的内容如下:
> Configure project :app
<<<<<<<settings.gradle<<<<<<<<<< beforeProject Project name = app
%%%%%%%%% FirstPluginProject %%%%%%%%% Apply the First Plugin Project
~~~~~~GlobalGradleProject~~~~~~~~ Apply the Global Gradle Project
@@@@@@@@@@@@@@ app @@@@@@@@@@@@@ afterEvaluate
> Configure project :firstplugin
<<<<<<<settings.gradle<<<<<<<<<< beforeProject Project name = firstplugin
<<<<<<<settings.gradle<<<<<<<<<< projectsEvaluated 已经完成Gradle构建的配置阶段
//此时handleTemplateTaskInProject已经添加到firstplugin中
> Task :firstplugin:handleTemplateTaskInProject
%%%%%%%%% FirstPluginProject %%%%%%%%% HandleTemplateTaskInProject is running
%%%%%%%%% FirstPluginProject %%%%%%%%% Set the file format is " .java
%%%%%%%%% FirstPluginProject %%%%%%%%% Set the file source dir is " /Users/j1/Documents/android/code/AndroidPlugin/app/src/main/java/mvp
> Task :firstplugin:compileJava NO-SOURCE
> Task :firstplugin:compileGroovy UP-TO-DATE
> Task :firstplugin:processResources UP-TO-DATE
> Task :firstplugin:classes UP-TO-DATE
> Task :firstplugin:jar UP-TO-DATE
> Task :firstplugin:makeJar UP-TO-DATE
> Task :firstplugin:assemble UP-TO-DATE
> Task :firstplugin:compileTestJava NO-SOURCE
> Task :firstplugin:compileTestGroovy NO-SOURCE
> Task :firstplugin:processTestResources NO-SOURCE
> Task :firstplugin:testClasses UP-TO-DATE
> Task :app:firstTask
此时发现 handleTemplateTaskInProject已经添加到firstplugin这个插件中。
具体的代码已经上传到至https://github.com/wenjing-bonnie/AndroidPlugin.git的firstplugin目录的相关内容。因为逐渐在这基础上进行迭代,可回退到Gradle_4.0该tag下可以查看相关内容。
三 总结
- 1.在构建项目的生命周期内,被依赖的module的配置阶段完成后,才去进行apply或plugins下的插件的配置阶段;所以如果想在自定义插件中对被依赖module的project进行配置内容,必须在入口类的apply(project)中;
- 2.当所有的module的配置阶段完成后,然后依次执行所有的任务队列;
- 3.对project对象的属性扩展必须放到对应的project中,否则会出现语法错误;
- 4.可在插件的build.gradle中添加自定义的task,那么该task就在该插件的任务队列中执行;
- 5.要想能够让被依赖的module进行属性扩展,那么必须在入口类的apply(project)中,对返回的project对象进行属性扩展
有了多次的碰壁,终于现在对概念也清晰了,在解决一些问题的时候,游刃有余,并且总能找到解决方案。
加油!!!!
以上是关于Android 自定义Task添加到任务队列的主要内容,如果未能解决你的问题,请参考以下文章
Android Gradle 插件自定义 Gradle 任务 ③ ( Gradle 自定义任务创建方法 Project#task 函数 | Task#doFirst 函数用法 )
Android Gradle 插件自定义 Gradle 任务 ③ ( Gradle 自定义任务创建方法 Project#task 函数 | Task#doFirst 函数用法 )
Android Gradle 插件自定义 Gradle 任务 ④ ( Task#doLast 函数用法 | 自定义 Gradle 任务代码示例 )
Android Gradle 插件自定义 Gradle 任务 ④ ( Task#doLast 函数用法 | 自定义 Gradle 任务代码示例 )