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

缘由

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

插件类型

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

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

Gradle相关语法

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

Gradle插件开发

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

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

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

发布到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

耐心等待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 %sn",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,就会输出像下面的信息。

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

 源码

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

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

以上是来客网为你收集整理的详解如何使用Android Studio开发Gradle插件全部内容,希望文章能够帮你解决详解如何使用Android Studio开发Gradle插件所遇到的程序开发问题。

如果觉得来客网网站内容还不错,欢迎将来客网网站推荐给程序员好友。