问题:
你想用自己的任务定制gradle的构建过程。
解决方案:
在gradle的build文件里面增加task元素。用Android插件支持的extra属性使得开发更容易。
讨论:
Gradle的DSL支持使用task块来定义自己的任务。API包括的非常广范围的task(像 Copy,Wrapper和Exec),你可以简单的通过配置来使用。
举例子,Copy任务包含from和to属性,from块可以设置排除指定格式文件名的文件。将那些没有签名的apk以外的所有apk复制到新的文件夹下,任务如下:
task copyApks(type: Copy) { from("$buildDir/outputs/apk") { exclude '**/*unsigned.apk', '**/*unaligned.apk' } into '../apks' }
buildDir属性和默认的build目录相关,$符号被用来将它插入到Groovy字符串里面(使用双引号)。Copy任务的文档显示,exclude块支持Ant风格的文件目录名,意味着**匹配所有的子目录。
如果你想要简单的配置一个已有的gradle任务,你需要理解gradle里面configuration和execution阶段的区别。在configuration阶段,Gradle基于依赖构建了一个DAG。然后执行特点的任务。所有任务在执行前都被配置过。
Gradle喜欢陈述性的任务。像上面的例子,你具体说明你想要做什么,而不是怎么做。如果你需要执行命令,在Gradle任务里面增加一个doLast块:
task printVariantNames() { doLast { android.applicationVariants.all { variant -> println variant.name } } }
任何doLast块前面或者后面的task中执行的,都会在configuration期间执行。doLast块里面的代码在execution期间执行。
Android插件增加一个android属性,相应的有一个applicationVariants属性可以返回所有的buildType/flavor的组合。在这种情况下,他们能够在控制台上输出。
将所有debug flavors装到同一个设备上面(假设他们有唯一的applicationId值),可以使用下面的任务:
task installDebugFlavors() { android.applicationVariants.all { v -> if (v.name.endsWith('Debug')) { String name = v.name.capitalize() dependsOn "install$name" } } }
dependsOn方法显示这是configuration阶段的一部分,而不是execution的。每个变体的名字,像friendlyDebug,被大写(FriendlyDebug),然后相应的安装任务(installFriendlyDebug)被添加到installDebugFlavors任务里面。
这个任务是在configuration阶段,installArrogantDebug,installFriendlyDebug,installObsquiousDebug都作为依赖添加到installDebugFlavors里面。因此执行installDebugFalvors任务也会要求三个flavor安装。
写自定义任务需要一点Groovy的只是。进一步讨论有点超出本书的范围。但是有一些不错的书,额外的Groovy概念在里面有介绍。