For more information on gradle plug-in writing, see the open source library Booster

You deserve sengo’s work.

Here is a step by step analysis of Booster’s technical details to learn booster’s code and design concept, which is convenient for us to write plug-ins in the future.

One of the painful things I felt when I was writing plug-ins was that my code could only be compatible with the agP version of one host. For example, the AGP version of my own project is currently 4.1. If AGP is upgraded to 7.0, some AGP interfaces change, so I have to modify my code to adapt to the new AGP version. This would cause my newly modified version of the plug-in to not fit the old project structure.

Booster can easily adapt to all agP versions. Let’s take a look at what Booster does

Booster’s infrastructure

First of all, the basic concept of Booster, namely, the dependency reversal and spi technology, will be explained in detail. You can easily understand the two technologies by searching a number of online tutorials. Focus on why Booster did this design

It is well known that Booster has many features. If you integrate these features into Booster’s base configuration, the plug-in will be very large because there are many people who only need one or two features.

Therefore, Sengo makes the best use of SPI technology, the basic function of Booster

booster-gradle-plugin

It just provides a run-time container for which functionality you want to use by adding a jar for that functionality. This allows the container to dynamically load your configured plug-ins at run time, thus separating the container from the specific functionality plug-ins

All plug-in portals actually inherit this interface

We can see how many classes inherit from it

Each class is a task entry to a specific functional plug-in.

Let’s take image compression as an example:

Notice that there is an autoService annotation here

This library is a google-generated spi library that allows you to annotate a meta-INF configuration file in your classpath, otherwise you would have to write it by hand

Version compatibility of the plug-in

With that in mind let’s look at how plug-ins are version-compatible

First of all, booster-Gradle-plugin includes our booster-Android-Gradle-API

As you can see from the dependencies, there are many projects whose names tell you that I’m compatible with the version of the plugin

Booster – Android – Gradle-compat

In fact, it defines two interfaces, we just need to implement our corresponding version adaptation according to this interface

So if you look at the APIInterface class and you see that it has all these exposed apis that we, the people who actually write the plug-in, can just call the interface methods and we’ll leave it up to somebody else to decide which imple will do the corresponding implementation. Here are the best practices for programming interfaces

Choose the best APIInterface implementation class based on the host situation

Return to the entry point for plug-in execution

Here’s the point:

The most important is the following code:

The AGP initializes with a “FACTORIES”, which is the process of spi. The “FACTORIES” initializer is a list of the APIInterface implementations

Version.ANDROID_GRADLE_PLUGIN_VERSION
Copy the code

This can actually print out our current AGP version. For example, in my demo project, it was 7.1.2, so the value returned here is 7.1.2. After we parse it as Revision, we can select an appropriate APIInterface object from the list

Note that the final instance is actually instantiated via factory.newapInterface

How to do agP compatibility for simple version?

What if you simply define a set of interfaces that return what you want to do, and then write the corresponding implementation classes for each version

Without SPI, ANDROID_GRADLE_PLUGIN_VERSION is the same as version. ANDROID_GRADLE_PLUGIN_VERSION, and the new Version is the same as the new Version.

Because if spi scheme is used, there is no need to change the code according to version judgment. Every time a new AGP version comes, we just need to adapt the new one. With our simple solution, wouldn’t we have to change the implementation in the WHEN statement every time a new version came along?