In this post I'm going to detail the steps I went through to create a Gradle plugin for Android from scratch.
I've been meaning to write this post for a while, ever since I did my first post Monkeying around with gradle to generate code and the recent Caster.IO post by Annyce Davis - Gradle Plugin Basics - inspired me to actually get it done.
I've found it very difficult to create a standalone gradle plugin for Android Studio. There's a lot of documentation around, but it always seems to be missing something. Have you ever tried doing a Google search for create a gradle plugin for android? I have and the results that I get are pretty lack-lusture.
Even Gradle's own documentation on the subject
only helps a little. The section on creating a standalone project pretty much
consists of telling you to add two lines to your
build.gradle and adding a properties
file. It doesn't tell you how to build it. The publishing section assumes you
know about publishing and want to publish it to the public. What about if I just want to build it to run it myself
to see if the bloody thing works?
And what about if you want it to run as part of your Android Studio build process? A little help?
I'm not going to cover every possibility of everything you might want to do in this one little blog post, but hopefully it'll be a good starting point based on what I've learnt.
Anyway, enough chatter. Let's get to it.
Step 0 - Assumptions
I'm going to assume that you are already set up for Android development, that is you have Java installed, Android Studio and the appropriate build tools. I think it's a safe assumption; writing a Gradle plugin isn't the first thing you want to be doing as a brand-spanking new Android developer.
From your point you have to assume that I'm not an expert on Gradle. I really don't know that much about it. What I've written here is what I've found out and what works for me. You can also assume that I'm devilishly handsome and a great conversationalist if you wish. However those aren't necessary for the purposes of this blog post.
Step 1 - Getting set up
This is the one thing that I could find no decent information on at all; how to even get set up.
Android Studio is a customised IntelliJ. As such it isn't suitable for writing standalone Gradle plugins. If you try to create a new project it will be an Android project. This is fair enough. That's what it's for. So the first tip is to download and install IntelliJ.
Go, grab the community edition from https://www.jetbrains.com/idea/
This post was written using version 15.0.3. If you're reading this in the future and I haven't updated it for the new version then you'll have to wing it and try to work out what I'm on about.
It's free, has what you'll need, and will be hauntingly familiar if you've been using Android Studio. (Sorry for those still using Eclipse.)
Install it and when you run it for the first time just accept all the install defaults. If you really want to mess around with the plugins at least make sure you have groovy, gradle and maven integration installed.
When you're sitting, staring at the IntelliJ IDEA window, hit Create New Project and the fun begins. Hopefully you'll see a screen that looks a little like this:
If Gradle is missing from the left or Groovy is missing from the right then it means one of the needed plugins is missing. In this case hit Cancel and from the main screen hit Configure -> Plugins to enable more plugins and try again.
If your Project SDK isn't showing a Java version, hit the New... button and locate your Java install directory.
Tick the Groovy option and then hit Next
On the next screen you need to fill in the GroupID and ArtifactId. Whilst these
can be anything, let's stick to convention. Make the GroupID
the same as the Company Domain you use for your Android apps and the ArtifactId
is the name for this plugin you are going to create. (For this blog post
blogpost for GroupID and ArtifactId respectively.)
Leave the Version alone
for now at 1.0-SNAPSHOT and hit Next
Don't change anything on the next screen. It recommends "Use default gradle wrapper" and who are we to argue? Hit Next.
You probably don't want to change anything on the next screen unless you want to move your project to a different directory. When you're done, hit Finish.
Step 2 - The journey begins
Once IntelliJ has created your project you'll notice a complete lack of any source code directories. At the top of the Project tree, right click, go to New and then Directory.
Enter the name
src/main/groovy. If all is well
the groovy directory will have a different colour to indicate that it is a
If you right-click on the groovy directory you'll see that, under New, you can now create packages and classes rather than just files and directories. Create an appropriate package and then a Groovy class in that package for your plugin.
Modify the class definition to add
implements Plugin<Project> so it looks like
and what you'll find is the
Project class is unknown by IntelliJ. If you try
to use IntelliJ to auto-import it, it won't happen.
Step 3 - Building blocks
We're missing something. Why can't we import
Project? The documentation from
Gradle says that we need to add
build.gradle. Great. Add those two lines to the dependencies
section that already exists in the
By the way, when you load the build.gradle for the first time IntelliJ will probably say "You can configure Gradle wrapper to use distribution with sources. It will provide IDE with Gradle API/DSL documentation." It's probably a good idea, so hit "Ok, apply suggestion." If you don't see this then it probably means your copy of IntellJ doesn't like you but don't worry about it; it won't affect what we're doing here.
Once the two dependencies have been added to your
build.gradle hop back to
our plugin class and user the power of IntelliJ to import
Project, right? Maybe.
If you added the dependencies in before hitting the "Ok, apply suggestion" then
you can. There are multiple options so make sure you choose the
If you did it in the other order then you will find that the
of the Project class is missing. On my install I only get
which is wrong.
I'm used to Android Studio and when you add a dependency in the
it tells you that you need to sync the project. IntellJ doesn't do this.
You have to do it yourself. And you'll have to do it every time you add a
new dependency to your
To do it, go to the View menu, then to Tool Windows and then to Gradle.
When the Gradle tool window pops out, hit the refresh button in the top left.
You would not believe how much time I wasted trying to work out why I couldn't import Project.
Once you've imported Project and Plugin you'll see the red squiggly line of doom under your class definition. Time to implement a method.
Step 4 - Apply yourself
The missing method is
apply(). Use IntelliJ's intentions to add this in
automatically (CTRL + Return, ALT + Return depending on your O/S and keymap).
This is where the magic happens. If you were to put a
you'd see in your Android build that this happens right at the start of the
build process, before anything else really happens. Not useful.
So what's it for? Here we can create a Gradle Task to do the work at an appropriate time.
(To make the rest of this easier to follow assume that the plugin class I'm creating is
BlogPlugin in the package
com.afterecho.gradle. Note that the
package name for your plugin doesn't have to be the same at the GroupID configured
when creating the project.)
This is where we create a Gradle
Task. In the simplest case we can create one task that is executed only when
we explicitly request it rather than as part of the normal build flow.
An example of this in the standard set of tasks
for Android is the
uninstallAll task that uninstalls all builds and flavours
of builds of your app from all attached devices.
uninstallAll doesn't run
as part of your normal build process. You have to manually run it.
Let's create a task called
showDevices that simply executes
apply() method look like this:
1 2 3 4 5 6 7 8 9
Simple. A new task is created with the name
showDevices. This task
has an action that gets the path
adb and runs a command. The project (
target) has an
that we can use to get some useful information. In this case, the path to
The setting of the description is just to be
nice to people who run
./gradlew tasks or like to look at tooltips in Android
Studio so they can see what our
task does. The setting of the group is to make it easier to find in
Android Studio and the gradle tasks output.
Ultimately our class should look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
How do we use the plugin now that we've written it? Another source of frustration. I tried many ways to create JAR files that could be dropped in places and I got nowhere. I didn't want to publish my nascent plugin to Maven Central or JCenter.
Step 5 - When life gives you repos...
You can create a maven-like repo on your local file system. Yay!
Create a directory somewhere on your machine. For this we need to modify
build.gradle again to add the following to the end
apply plugin: 'maven'
Replace 'repo' with the full path to your directory. If you just put 'repo' like I have then it will go into a 'repo' directory within your plugin's directory, which has the advantage that you can see it in Intellij.
Don't forget to bring out the Gradle tool window and hit refresh! Leave the
tool window open and you should now see a new task;
uploadArchives to run it. The first time you'll get a message
in the console window saying something about not being able to find metadata.
Don't worry. The metadata gets created and subsequent runs will not complain.
If you look in your repo directory you will find something like this
It's your very own maven repo. :)
You can see that all the files have a timestamp in them. This is because you
have specified this build is a snapshot (remember the version number right at
at the beginning?) Every time you run the
uploadArchives task it will create
another set of files.
To stop ourselves from getting overloaded, change the version in your
to remove the "-SNAPSHOT", delete all the files in your repo directory and run
Our plugin still isn't quite ready to use. There's one missing file.
Step 6 - Searching for plugins (in all the wrong places)
We need one more file in our archive that tells Gradle which class our plugin is
in. Back in our project structure, right click on "main" and create a
In this directory create a new File. The filename is the name you want to
give your plugin (the PluginId) followed by ".properties".
build.gradle for a standard Android app there's a
apply plugin: 'com.android.application'
so the file for this would be
I don't recommend you call your plugin com.android.application so let's call
In this file put a single line;
implementation-class= and the fully qualified
name of the class that extends
Plugin<Project>. In my case it is
Step 7 - Publish and be damned
uploadArchives task again. Now we can leave IntellJ alone for a while
and go to the totally different environment of Android Studio.
Create a new Android application or load one that you prepared earlier. Open
the Project level
build.gradle and in the
repositories section of the
section, add in
(Change the path as appropriate for where you put your repo earlier.) Your project now has a new place to look for plugins.
dependencies section of
buildscript add in
This declares the dependency of our Android build on our plugin. The name here relates back to when the plugin was created. The bit before the first colon is the GroupId, the bit between the colons is the ArtifactId
If you created a new project, it should look something like this:
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
Now open the Module level
build.gradle and, after the
apply plugin: com.android.application
apply plugin: 'com.afterecho.blogplugin'
This is where the PluginId comes in - remember the name of the properties file?
To clarify there is
The PluginId can be - but probably shouldn't be - totally unrelated to the GroupId and ArtifictId.
Android Studio should be asking you to Sync Now. Go for it. A bit of an anti-climax isn't it? Nothing seems to have happened.
Step 8 - The Grand Finale
The reason is we created the task but we haven't called it. You can run the task within Android Studio from the Gradle tool window.
Look in the "blogplugin" section for
showDevices. If you hover your mouse over it
you'll see the description we set earlier pop up in a tooltip. Double-click
showDevices and behold the output in the run tool window.
You can also run it from the command line within the applications project directory. By running
you should see in the "Blogplugin tasks" section our "showDevices" task, along with the description. Run it with
There we have our first Gradle plugin for Android. I know it's not much, but it's a start. In a future blog post I hope to expand the plugin to something that's a little more useful.
Darren @ Æ