写 Gradle 插件的一点经验
来源:互联网 发布:一骑当千动作数据 编辑:程序博客网 时间:2024/05/01 18:01
本着简单易用的原则,参考 android-resource-remover 写了一个删除无用资源文件的 Gradle 插件 - clean-unused-resources-gradle-plugin,结果微博发出来不到10分钟,陈启超就告诉我 AS2.0+ 已经提供了此功能。天哪,为了纪念这个短命无用的轮子,只好写篇博客,把造轮子的过程记录下来,也算对别人有点用处。
官方文档说了,自定义 Gradle 插件有三种方式:
- Build script
buildSrc
project- Standalone project
但是,AS 不完美支持第三种方式,我们用 AS 的爸爸 IntelliJ IDEA CE 就好了。
首先 New 一个基于 Gradle 的 Groovy 工程:
修改一下自动生成的 build.gradle 文件,把 repositories
和 dependencies
替换掉,其他保持不变。
repositories { jcenter()}dependencies { compile gradleApi() testCompile group: 'junit', name: 'junit', version: '4.11'}
然后创建 src
和 resources
目录(以 clean-unused-resources-gradle-plugin 为例):
resources/META-INF/gradle-plusings/
是必不可少,否则别人无法使用你的插件,目录下的 *.properties
文件名就是插件的名字,别人apply
的时候会用到:
apply plugin: 'com.youzan.mobile.cleaner'
文件内容是把 implementation-class
指向你插件类的全名。
implementation-class=com.youzan.mobile.CleanerPlugin
CleanerPlugin.groovy
实现了接口Plugin<Project>
,而 org.gradle.api.Plugin
就是由 compile gradleApi()
提供,我们在 build.gradle 的 dependencies
中已经添加过了。
准备就绪,开始写插件。
首先,实现 apply
方法:
class CleanerPlugin implements Plugin<Project> { @Override void apply(Project project) { // 创建一个 extension project.extensions.create('resourceCleaner', CleanerExtension); // 修改 lint report 路径 project.afterEvaluate { project.android.lintOptions.xmlOutput = new File(project.buildDir, "lintResult.xml"); } // 创建 task project.tasks.create('cleanResource', CleanTask) }}
第一步通过 project.extensions.create
创建一个 extension
:
CleanerExtension.groovy
class CleanerExtension { Iterable<String> excludedFiles}
这个 extension
用于别人向你的插件传递参数,例如:
resourceCleaner { excludedFiles = [ 'string_pos.xml', 'string_car.xml', ]}
第二步修改 lint report 的路径:
project.afterEvaluate { project.android.lintOptions.xmlOutput = new File(project.buildDir, "lintResult.xml");}
这里用到了 Android Gradle Plugin 的 DSL,所以 IDEA 无法动态提示,没关系,我们直接去翻文档,里面有详解的解释:
配置参数(CleanerExtension)和文件参数(lintOptions.xmlOutput)都准备好了。
第三步,主角上场,创建一个 task
:
class CleanTask extends DefaultTask { CleanTask() { super() dependsOn "lint" } @TaskAction def clean() { def lintResult = project.android.lintOptions.xmlOutput def excludedFiles = project.resourceCleaner.excludedFiles Cleaner.clean(lintResult, excludedFiles) }}
CleanTask
继承自 DefaultTask
,因为 CleanTask 的输入是 lint report,所以在构造方法中通过调用 dependsOn "lint"
让自己依赖于 lint 这个 task
。
CleanTask
就好像动物农场里面的猪,只负责发号施令,安排工作,真正干活的“人”是 Cleaner
:
class Cleaner { def static clean(File report, Iterable<String> excludedFiles) { def issues = new XmlSlurper().parse(report) issues.'*'.findAll { it.name() == 'issue' && it.@id == 'UnusedResources' }.each { def file = new File(it.location.@file.text()) if (file.name in excludedFiles) return; def line = it.location.@line def column = it.location.@column if ((line == '' && column == '') || column == '1') { println "deleting " + file.path file.delete() } else { def m = it.@message =~ $/`R.(\\w+).([^`]+)`/$ if (!m) return; def type = m.group(1) def entryName = m.group(2); def parsed = new XmlSlurper().parse(file) parsed.'**'.findAll { it.@name == entryName && it.name().contains(type) }*.replaceNode {} XmlUtil.serialize(parsed, new FileWriter(file)) } } }}
一个简单的独立工程的 Gradle Plugin 就这么写完了,是不是非常简单,先不要高兴,还有最后一步 - 发布到 jCenter。
继续修改 build.gralde
。
添加 bintray 插件。
plugins { id "com.jfrog.bintray" version "1.4"}Properties properties = new Properties();properties.load(project.rootProject.file('local.properties').newDataInputStream())bintray { user = properties.getProperty("bintray.user") key = properties.getProperty("bintray.apikey") publications = ['mavenJava'] pkg { repo = 'maven' name = 'cleaner-gradle-plugin' desc = 'a gradle plugin to clean unused resources detected by Lint' websiteUrl = 'https://github.com/YouzanMobile/clean-resource-gradle-plugin' issueTrackerUrl = 'https://github.com/YouzanMobile/clean-resource-gradle-plugin/issues' vcsUrl ='https://github.com/YouzanMobile/clean-resource-gradle-plugin' publicDownloadNumbers = true licenses = ['MIT'] }}
maven-publish 插件:
apply plugin: 'maven-publish'// custom tasks for creating source/javadoc jarstask sourcesJar(type: Jar, dependsOn: classes) { classifier = 'sources' from sourceSets.main.allSource}task javadocJar(type: Jar, dependsOn: javadoc) { classifier = 'javadoc' from javadoc.destinationDir}// add javadoc/source jar tasks as artifactsartifacts { archives sourcesJar, javadocJar}publishing { publications { mavenJava(MavenPublication) { from components.java artifact sourcesJar artifact javadocJar groupId 'com.youzan.mobile' artifactId 'cleaner-gradle-plugin' version versionName } }}
OK,大功告成,演出结束,下面是致谢:
- NuwaGradle
- 陈启超_V
- Gradle User Guide
- 写 Gradle 插件的一点经验
- 最近写DirectShow filter的一点经验
- 用VC++写ISAPI的一点经验
- 我写操作系统的一点经验【原创】
- 写oracle存储过程的一点小经验
- 写一点我自己使用Android small入门的经验
- 写一点我自己做平衡小车的经验吧
- 2.7-3 Android Studio 的Gradle一点理解, 查看gradle 版本和android 插件的版本
- 2.7-3 Android Studio 的Gradle一点理解, 查看gradle 版本和android 插件的版本
- 2.7-3 Android Studio 的Gradle一点理解, 查看gradle 版本和android 插件的版本
- GOOGLE的一点经验
- 的一点经验
- CGI的一点经验
- Hibernate的一点经验
- 爬虫的一点经验
- 程序员的一点经验
- gradle的jetty插件
- gradle的war插件
- jQuery.Validate验证库
- java拼接byte[]
- Android Proguard混淆打包经验总结
- 如何发现优秀的开源项目
- 基于qualcomm平台的无人机开发demo
- 写 Gradle 插件的一点经验
- 用bootstrapt写一个响应式的简单页面
- poj 1655树的重心入门
- python学习书单
- Caffe 初学拾遗(十二) Solver
- [HNOI2008]越狱
- Eclipse软件开发Android前的配置环境
- Windows命令行关闭IE代理
- 欢迎进入Hensen_的博客目录(全站式导航)