Creating your own plugins

If you have a collection of Gradle tasks that you want to reuse in several projects, it makes sense to extract these tasks into a custom plugin. This makes it possible to reuse build logic yourself, and to share it with others.

Plugins can be written in Groovy, but also in other languages that make use of the JVM, such as Java and Scala. In fact, big parts of the Android plugin for Gradle are written in Java in combination with Groovy.

Creating a simple plugin

To extract build logic that is already stored in your build configuration file, you can create a plugin within the build.gradle file. This is the easiest way to get started with custom plugins.

To create a plugin, create a new class that implements the Plugin interface. We will use the code we wrote previously in this chapter, which dynamically creates run tasks. Our plugin class looks like this:

class RunPlugin implements Plugin<Project> {
  void apply(Project project) {
    project.android.applicationVariants.all { variant ->
      if (variant.install) {
        project.tasks.create(name: "run${variant.name.capitalize()}", dependsOn: variant.install) {
            // Task definition
        }
      }
    }
  }
}

The Plugin interface defines an apply() method. Gradle calls this method when the plugin is used in a build file. The project is passed as a parameter so that the plugin can configure the project or use its methods and properties. In the preceding example, we cannot call properties from the Android plugin directly. Instead, we need to access the project object first. Note that this requires the Android plugin to be applied to the project before our custom plugin is applied. Otherwise, project.android will cause an exception.

The code for the task is the same as it was earlier, except for one method call: instead of calling exec(), we now need to call project.exec().

To make sure the plugin is applied to our build configuration, add this line to build.gradle:

apply plugin: RunPlugin

Distributing plugins

In order to distribute a plugin and share it with others, you need to move it into a standalone module (or project). A standalone plugin has its own build file to configure dependencies and means of distribution. This module produces a JAR file, containing the plugin classes and properties. You can use this JAR file to apply the plugin in several modules and projects, and to share it with others.

As with any Gradle project, create a build.gradle file to configure the build:

apply plugin: 'groovy'

dependencies {
    compile gradleApi()
    compile localGroovy()
}

Since we are writing the plugin in Groovy, we need to apply the Groovy plugin. The Groovy plugin extends on the Java plugin, and enables us to build and package Groovy classes. Both Groovy and plain Java are supported, so you can mix them if you like. You can even go so far as to extend a Java class using Groovy, or the other way around. This makes it easy to get started, even if you do not feel confident using Groovy for everything.

Our build configuration file contains two dependencies: gradleApi() and localGroovy(). The Gradle API is required to access Gradle namespaces from our custom plugin, and localGroovy() is a distribution of the Groovy SDK that comes with the Gradle installation. Gradle provides these dependencies by default for our convenience. If Gradle did not provide these dependencies out of the box, we would have to download and reference them manually.

Note

If you plan to distribute your plugin publically, make sure to specify the group and version information in the build configuration file, like this:

group = 'com.gradleforandroid'
version = '1.0'

To get started with the code in our standalone module, we first need to make sure to use the correct directory structure:

plugin
└── src
    └── main
        ├── groovy
        │   └── com
        │       └── package
        │           └── name
        └── resources
            └── META-INF
                └── gradle-plugins

As with any other Gradle module, we need to provide a src/main directory. Because this is a Groovy project, the subdirectory of main is called groovy instead of java. There is another subdirectory of main called resources, which we will use to specify our plugin's properties.

We create a file called RunPlugin.groovy in the package directory, where we define the class for our plugin:

package com.gradleforandroid

import org.gradle.api.Project
import org.gradle.api.Plugin

class RunPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.android.applicationVariants.all { variant ->
            // Task code
        }
    }
}

In order for Gradle to be able to find the plugin, we need to provide a properties file. Add this properties file to the src/main/resources/META-INF/gradle-plugins/ directory. The name of the file needs to match the ID of our plugin. For the RunPlugin, the file is named com.gradleforandroid.run.properties, and this is its content:

implementation-class=com.gradleforandroid.RunPlugin

The only thing that the properties file contains is the package and name of the class that implements the Plugin interface.

When the plugin and the properties file are ready, we can build the plugin using the gradlew assemble command. This creates a JAR file in the build output directory. If you want to push the plugin to a Maven repository instead, you first need to apply the Maven plugin:

apply plugin: 'maven'

Next, you need to configure the uploadArchives task, like this:

uploadArchives {
    repositories {
        mavenDeployer {
          repository(url: uri('repository_url'))
}
    }
}

The uploadArchives task is a predefined task. Once you configure a repository on the task, you can execute it to publish your plugin. We will not cover how to set up a Maven repository in this book.

If you want to make your plugin publically available, consider publishing it to Gradleware's plugin portal (https://plugins.gradle.org). The plugin portal has a great collection of Gradle plugins (not just specific to Android development) and is the place to go when you want to extend Gradle's default behavior. You can find information on how to publish a plugin in the documentation at https://plugins.gradle.org/docs/submit.

Tip

Writing tests for custom plugins is not covered in this book, but is highly recommended if you plan to make your plugins publically available. You can find more information on writing tests for plugins in the Gradle user guide at https://gradle.org/docs/current/userguide/custom_plugins.html#N16CE1.

Using a custom plugin

To use a plugin, we need to add it as a dependency to the buildscript block. First, we need to configure a new repository. The configuration of the repository depends on the way that the plugin is distributed. Second, we need to configure the classpath of the plugin in the dependencies block.

If we want to include the JAR file that we created in the earlier example, we can define a flatDir repository:

buildscript {
    repositories {
        flatDir { dirs 'build_libs' }
    }
    dependencies {
        classpath 'com.gradleforandroid:plugin'
    }
}

If we had uploaded the plugin to a Maven or Ivy repository, this would look a little different. We covered dependency management already in Chapter 3, Managing Dependencies, so we will not repeat the different options here.

After we set up the dependency, we need to apply the plugin:

apply plugin: com.gradleforandroid.RunPlugin

When using the apply() method, Gradle creates an instance of the plugin class, and executes the plugin's own apply() method.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.181.36