详解如何使用Android Studio开发Gradle插件

缘由

首先说明一下为什么会有这篇文章。前段时间,插件化以及热修复的技术很热,Nuwa热修复的工具NuwaGradle,携程动态加载技术DynamicAPK,还有希望做最轻巧的插件化框架的Small。这三个App有一个共同的地方就是大量的使用了Gradle这个强大的构建工具,除了携程的框架外,另外两个都发布了独立的Gradle插件提供自动化构建插件,或者生成热修复的补丁。所以学习一下Gradle插件的编写还是一件十分有意义的事。

插件类型

Gradle的插件一般有这么几种:

一种是直接在项目中的gradle文件里编写,这种方式的缺点是无法复用插件代码,在其他项目中还得复制一遍代码(或者说说复制一遍文件) 另一种是在独立的项目里编写插件,然后发布到中央仓库,之后直接引用就可以了,优点就是可复用。就和上面的Nuwa和Small一样。

Gradle相关语法

本篇文章不会详细说明Gradle相关的语法,如果要学习gradle相关的东西,请查看Gradle for Android

Gradle插件开发

Gradle插件是使用Groovy进行开发的,而Groovy其实是可以兼容Java的。Android Studio其实除了开发Android App外,完全可以胜任开发Gradle插件这一工作,下面来讲讲具体如何开发。

首先,新建一个Android项目。 之后,新建一个Android Module项目,类型选择Android Library。 将新建的Module中除了build.gradle文件外的其余文件全都删除,然后删除build.gradle文件中的所有内容。 在新建的module中新建文件夹src,接着在src文件目录下新建main文件夹,在main目录下新建groovy目录,这时候groovy文件夹会被Android识别为groovy源码目录。除了在main目录下新建groovy目录外,你还要在main目录下新建resources目录,同理resources目录会被自动识别为资源文件夹。在groovy目录下新建项目包名,就像Java包名那样。resources目录下新建文件夹META-INF,META-INF文件夹下新建gradle-plugins文件夹。这样,就完成了gradle 插件的项目的整体搭建,之后就是小细节了。目前,项目的结构是这样的。

打开Module下的build.gradle文件,输入

apply plugin: 'groovy' apply plugin: 'maven' dependencies { compile gradleApi() compile localGroovy() } repositories { mavenCentral() }

下面我们在包名下新建一个文件,命名为PluginImpl.groovy,注意有groovy后缀,然后在里面输入,注意包名替换为你自己的包名。

package cn.edu.zafu.gradle import org.gradle.api.Plugin import org.gradle.api.Project public class PluginImpl implements Plugin<Project> { void apply(Project project) { project.task('testTask') << { println "Hello gradle plugin" } } }

然后在resources/META-INF/gradle-plugins目录下新建一个properties文件,注意该文件的命名就是你只有使用插件的名字,这里命名为plugin.test.properties,在里面输入

implementation-class=cn.edu.zafu.gradle.PluginImpl

注意包名需要替换为你自己的包名。

这样就完成了最简单的一个gradle插件,里面有一个叫testTask的Task,执行该task后会输出一段文字,就像当初我们输出HelloWorld一样。

发布到本地仓库

接着,我们需要将插件发布到maven中央仓库,我们将插件发布到本地仓库就好了,在module项目下的buidl.gradle文件中加入发布的代码。

repositories { mavenCentral() } group='cn.edu.zafu.gradle.plugin' version='1.0.0' uploadArchives { repositories { mavenDeployer { repository(url: uri('../repo')) } } }

上面的group和version的定义会被使用,作为maven库的坐标的一部分,group会被作为坐标的groupId,version会被作为坐标的version,而坐标的artifactId组成即module名,我们让其取一个别名moduleName。然后maven本地仓库的目录就是当前项目目录下的repo目录。

这时候,右侧的gradle Toolbar就会在module下多出一个task

点击uploadArchives这个Task,就会在项目下多出一个repo目录,里面存着这个gradle插件。

目录就像上图这样,具体目录结构和你的包名等一系列有关,time是我的module名。

发布到本地maven仓库后,我们就使用它,在叫app的android项目下的gradle.build的文件中加入

buildscript { repositories { maven { url uri('../repo') } } dependencies { classpath 'cn.edu.zafu.gradle.plugin:time:1.0.0' } } apply plugin: 'plugin.test'

apply plugin后面引号内的名字就是前文plugin.test.properties文件的文件名。而class path后面引号里的内容,就是上面grade中定义的group,version以及moduleName所共同决定的,和maven是一样的。

同步一下gradle,右侧app下other分类下就会多出一个testTask,双击执行这个Task,控制台就会输出刚才我们输入的字符串

发布到Jcenter仓库

接下来我们将其发布到jcenter中央仓库。

在项目根目录下的build.gradle文件中加入。

dependencies { classpath 'com.android.tools.build:gradle:2.0.0-beta6' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0' classpath 'com.github.dcendents:android-maven-plugin:1.2' }

在项目根路径下新建bintray.gradle文件,输入

apply plugin: 'com.jfrog.bintray' apply plugin: 'maven-publish' def projectName = "timePlugin" def mavenDesc = 'your desc' def baseUrl = 'https://github.com/yourBaseUrl' def siteUrl = baseUrl def gitUrl = "${baseUrl}/yourGitUrl" def issueUrl = "${baseUrl}/yourGitIssueUrl" def licenseIds = ['Apache-2.0'] def licenseNames = ['The Apache Software License, Version 2.0'] def licenseUrls = ['http://www.apache.org/licenses/LICENSE-2.0.txt'] def inception = '2016' def username = 'lizhangqu' install { repositories { mavenInstaller { pom.project { // Description name projectName description mavenDesc url siteUrl // Archive groupId project.group artifactId archivesBaseName version project.version // License inceptionYear inception licenses { licenseNames.eachWithIndex { ln, li -> license { name ln url licenseUrls[li] } } } developers { developer { name username } } scm { connection gitUrl developerConnection gitUrl url siteUrl } } } } } task sourcesJar(type: Jar) { from sourceSets.main.allGroovy classifier = 'sources' } task javadocJar(type: Jar, dependsOn: groovydoc) { from groovydoc.destinationDir classifier = 'javadoc' } artifacts { archives javadocJar archives sourcesJar } bintray { user = BINTRAY_USER key = BINTRAY_KEY configurations = ['archives'] pkg { repo = 'maven' name = projectName desc = mavenDesc websiteUrl = siteUrl issueTrackerUrl = issueUrl vcsUrl = gitUrl labels = ['gradle', 'plugin', 'time'] licenses = licenseIds publish = true publicDownloadNumbers = true } }

将对应的描述性文字修改为你自己的信息,尤其是最前面的一系列的def定义,然后在gradle.properties文件中加入BINTRAY_USER和BINTRAY_KEY。

在你的module中apply该grade文件

apply from: '../bintray.gradle'

右侧的gradle的toolbar就会多出几个task

之后我们先运行other下的install这个task,再执行bintrayUpload这个task,如果不出意外,就上传了,之后不要忘记到后台add to jcenter。成功add到jcenter之后就会有link to jcenter的字样

耐心等待add to center成功的消息,之后就可以直接引用了,将module下的gradle文件maven部分的定义

maven { url uri('../repo') }

前面加入

jcenter()

最终的内容如下

buildscript { repositories { jcenter() maven { url uri('../repo') } } dependencies { classpath 'cn.edu.zafu.gradle.plugin:time:1.0.0' } } apply plugin: 'plugin.test'

就是这么简单,再次运行一下测试下是否成功。

最佳实践

最佳实践的来源是源自multidex,为什么呢,因为最近当方法数超了之后,如果选择multidex,编译的过程就会慢很多很多,为了检测到底是哪一步的耗时,需要编写一个插件来统计各个task执行的时间,因此就有了这么一个最佳实践。

在PluginImpl同级目录下新建TimeListener.groovy文件。输入

package cn.edu.zafu.gradle import org.gradle.BuildListener import org.gradle.BuildResult import org.gradle.api.Task import org.gradle.api.execution.TaskExecutionListener import org.gradle.api.initialization.Settings import org.gradle.api.invocation.Gradle import org.gradle.api.tasks.TaskState import org.gradle.util.Clock class TimeListener implements TaskExecutionListener, BuildListener { private Clock clock private times = [] @Override void beforeExecute(Task task) { clock = new org.gradle.util.Clock() } @Override void afterExecute(Task task, TaskState taskState) { def ms = clock.timeInMs times.add([ms, task.path]) task.project.logger.warn "${task.path} spend ${ms}ms" } @Override void buildFinished(BuildResult result) { println "Task spend time:" for (time in times) { if (time[0] >= 50) { printf "%7sms %s\n", time } } } @Override void buildStarted(Gradle gradle) {} @Override void projectsEvaluated(Gradle gradle) {} @Override void projectsLoaded(Gradle gradle) {} @Override void settingsEvaluated(Settings settings) {} }

然后将PluginImpl文件中的apply方法修改为

void apply(Project project) { project.gradle.addListener(new TimeListener()) }

完成后打包发布到jcenter()。之后你只要引用了该插件,就会统计各个task执行的时间,比如运行app,就会输出像下面的信息。

最佳实践的末尾,推广一下这个插件,这个插件我已经将其发布到jcenter仓库,如果要使用的话加入下面的代码即可

buildscript { repositories { jcenter() } dependencies { classpath 'cn.edu.zafu.gradle.plugin:time:1.0.0' } } apply plugin: 'plugin.time'

传递参数

上面的是小试牛刀了下,接下来我们需要获得自定义的参数。

首先按照上面的步骤新建一个module。新建PluginExtension.groovy,输入

public class PluginExtension { def param1 = "param1 defaut" def param2 = "param2 defaut" def param3 = "param3 defaut" }

然后我们希望能传入嵌套的参数,再新建一个PluginNestExtension.groovy,输入

public class PluginNestExtension { def nestParam1 = "nestParam1 defaut" def nestParam2 = "nestParam2 defaut" def nestParam3 = "nestParam3 defaut" }

然后新建一个CustomTask.groovy,继承DefaultTask类,使用 @TaskAction注解标注实现的方法

public class CustomTask extends DefaultTask { @TaskAction void output() { println "param1 is ${project.pluginExt.param1}" println "param2 is ${project.pluginExt.param2}" println "param3 is ${project.pluginExt.param3}" println "nestparam1 is ${project.pluginExt.nestExt.nestParam1}" println "nestparam2 is ${project.pluginExt.nestExt.nestParam2}" println "nestparam3 is ${project.pluginExt.nestExt.nestParam3}" } }

只是做了拿到了参数,然后做最简单的输出操作,使用 ${project.pluginExt.param1}和 ${project.pluginExt.nestExt.nestParam1}等拿到外部的参数。

别忘了在META-INF/gradle-plugins目录下新建properties文件指定插件的接口实现类。

复制之前新建的PluginImpl.groovy到包下,修改apply方法

public class PluginImpl implements Plugin<Project> { void apply(Project project) { project.extensions.create('pluginExt', PluginExtension) project.pluginExt.extensions.create('nestExt', PluginNestExtension) project.task('customTask', type: CustomTask) } }

将插件发布到本地maven后,进行引用。

buildscript { repositories { maven { url uri('../repo') } } dependencies { classpath 'cn.edu.zafu.gradle.plugin:test:1.0.0' } } apply plugin: 'plugin.test'

定义外部参数,这里我们定义了param1,param2,nestParam1,nestParam2,此外param3和nestParam3保持默认。

pluginExt { param1 = 'app param1' param2 = 'app param2' nestExt{ nestParam1='app nestParam1' nestParam2='app nestParam2' } }

同步一下gradle,执行customTask。

上面的代码很简单,不用解释也能看到,所以不再解释了。

源码

最后上本篇文章的源码 :GradlePlugin_jb51.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

时间: 2024-10-22 04:50:09

详解如何使用Android Studio开发Gradle插件的相关文章

Android studio利用gradle打jar包并混淆的方法详解

本文主要介绍了Android studio利用gradle打jar包并混淆的方法,下面话不多说,来看看详细的介绍吧. 首先打jar包的配置很简单,使用jar的task,可以参考gradle官方文档,具体代码如下: task buildJar(type: Jar, dependsOn: ['assembleRelease']) { destinationDir = file('build/outputs/jar/') appendix = "" baseName = "&quo

报错提示找不大符号-android studio开发为什么我创建类,也导入这个类的包了,可报错提示找不到符号

问题描述 android studio开发为什么我创建类,也导入这个类的包了,可报错提示找不到符号 5C android studio开发为什么我创建类,也导入这个类的包了,可报错提示找不到符号希望哪位遇到类似的问题帮我解答一下 解决方案 eclipse导入android报错找不到类 解决方案二: ,这个,不太好做啊,你可以 解决方案三: 没有引用依赖吧,检查下build.gradle文件里面的dependencies 解决方案四: 你得贴完整的 我看是包名错了

Android studio 开发,谷歌 API Key 如何 申请?

问题描述 Android studio 开发,谷歌 API Key 如何 申请? 在用Android studio开发过程中, 需要用到谷歌地图,请问怎么申请谷歌 API Key 了?帮帮忙!!! 解决方案 申请Google Map Android API Key申请 ANDROID GOOGLE MAP API KEY 解决方案二: 建议用BaiduMap等墙内的地图 解决方案三: 建议用高德地图,坐标跟google的算法是一个.

android配置-Linux下Android的SDK在哪下载?Android Studio开发环境该怎么安装?

问题描述 Linux下Android的SDK在哪下载?Android Studio开发环境该怎么安装? 如题,在ubuntu上搭建android studio开发环境由于要翻墙,set up时就没下载成功,只能另外下载SDK再把路径添加进去是吗?SDK在哪下呢? 解决方案 Android Studio 开发环境搭建及更新SDK安装下载问题Android Studio下载安装教程及开发环境搭建Linux(Ubuntu)环境下安装Android Studio 教程 解决方案二: http://jin

求救大神,我用android studio开发的项目,删除后能恢复找到不、我写了一个多月的程序

问题描述 求救大神,我用android studio开发的项目,删除后能恢复找到不.我写了一个多月的程序 如题,我写了一个多月的程序,今天不小心点右键删除了项目.请问一下大神有办法恢复没?我在百度上到处找也没有相关的解答.谢谢了啊. 解决方案 试试这个 http://www.xiazaiba.com/html/591.html 个人觉得数据恢复中比较好的

Android Studio 开发 真机测试 如何访问本地服务器下的内容

问题描述 Android Studio 开发 真机测试 如何访问本地服务器下的内容 请大神指点下,谢谢! win7 虚拟服务器用的是tomcat 本地电脑可以访问(localhost:8080/) 没有问题 APK编程用了 10.0.2.2:8080 没用 后来同时连入WiFi APK编程改为192.168.1.X:8080 (本地电脑的IP)还是没用 用手机浏览器连接192.168.1.X:8080 (本地电脑的IP) 刚连上就停在那里 什么内容都没有 注:电脑的杀毒软件都关了. 解决方案 w

《Android App开发入门:使用Android Studio 2.X开发环境》——第 1章 使用 Android Studio 开发 Android App

第 1章 使用 Android Studio 开发 Android App 1-1 创建第一个 Android App 项目 1-2 在计算机的仿真器上执行 App 1-3 Android Studio 快速上手 1-4 Android 项目的构成 本章将介绍如何使用 Android Studio 集成开发环境开发 Android App.我们将先说明在 Android Studio 中如何添加.创建 Android App,接着说明如何将完成的程序( App)放在仿真器上执行与测试.让读者先体

java-在使用Android studio 开发中,需要运行的代码到底应该写在哪?

问题描述 在使用Android studio 开发中,需要运行的代码到底应该写在哪? 先在src底下创建java文件,然后在Mainactivity.java中的onCreate(Bundle)中调用 还是直接写到MainActivity.java中 还是直接写到SRC中就会自己运行了 实在没懂 求解 解决方案 看你打算怎么运行程序,是app还是service.不同类型的程序不一样的. 解决方案二: 在xml配置起动的activity.然后在oncreate开始执行第一段代码. 你应该看看and

Android Studio 添加 Genymotion插件

原文:Android Studio 添加 Genymotion插件 1.下载Genymotion:官网地址,必须先注册才能下载,下载带有VirtualBox的版本 2.安装:安装时会连VirtualBox一起安装,直接next就行. 3.打开AndroidStudio,点击File-->Settings-->Plugins-->Browse`````,搜索genymotion安装,然后重启AndroidStudio.       4.重启后会出现genymotion的图标: 点击图标会出