An overview of the
I started a new series. The goal of this series of learning Gradle is to thoroughly understand Gradle. The main goal is to make notes on your own understanding to prevent forgetting
Gradle Series (1) : Groovy learning
Gradle Learning series (2) : Gradle core decryption
Gradle Plugins
Introduction to the
Gradle itself only provides the basic core functionality, other features such as the ability to compile Java source code, the ability to compile Android projects and so on are implemented through plug-ins. To apply a plug-in, you need to apply the plug-in to your Project, which is done through the project.apply () method. Gradle generally has two types of plug-ins, called script plug-ins and object plug-ins.
A script plugin is an extra build script that further configures the build and can be thought of as a normal build.gradle.
Object plug-ins, also known as binary plug-ins, are classes that implement the Plugin interface. Here’s how to use them.
Scripting plug-ins
For example, we create a utils. Gradle at the root of the project
def getxmlpackage(boolean x){
def file=new File(project.getProjectDir().getPath()+"/src/main/AndroidManifest.xml");
def paser = new XmlParser().parse(file)
return paser.@package
}
ext{
getpackage = this.&getxmlpackage
}
Copy the code
This is a simple script plug-in, and then reference the script plug-in in app Moudle
apply from: rootProject.getRootDir().getAbsolutePath() + "/utils.gradle"
Copy the code
Then you can call the method in the script plug-in
Object plug-in
Object plug-ins are plug-ins that implement the org.gradle.api.plugins interface. Object plug-ins can be classified into internal plug-ins and third-party plug-ins.
Inside the plugin
Gradle contains a large number of plugins, such as Java plugins and C plugins that we often use, which we can directly introduce
apply plugin:'java'
apply plugin:'cpp'
Copy the code
Tripartite plug-in
Third party object plug-ins are usually JAR files that need to be set up using BuildScrip to make the build script aware of the existence of the third party plug-ins. Define the original repository and dependencies of the plug-in in BuildScrip, then configure the apply method. Android Gradle plugin is also a third party plugin. If we want to introduce Android Gradle plugin, we can write:
buildscript {
repositories {
// Configure the repository
google()
jcenter()
}
dependencies {
// Configure plug-in dependencies
classpath 'com. Android. Tools. Build: gradle: 3.5.3'}}// Then you can introduce android plugins where needed
apply plugin: 'com.android.application'
Copy the code
Custom object plug-ins
Customizing a Plugin is to implement org.gradle.api.Plugin
Build script
This is a way to write the plugin code directly in the build script, but it can only be used in this file. For example, I added the following code directly in the app’s build.gradle
class myPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
println("MyPlugin executes.")
project.task("myTask"){
doLast {
println("MyTask executed.")}}}}Copy the code
Then introduce the plug-in defined in this file
apply plugin: myPlugin
Copy the code
Gradlew MyTask (MyTask) /gradlew MyTask (MyTask
> Task :mylibrary2:MyTask myTask executes the execution phase, task':mylibrary2:myTask'Time:1ms
Copy the code
Generally, we do not use plug-ins implemented in this way, because this way is too limited and can only be used in this Project, while other projects cannot be used
BuildSrc project
BuildSrc is Gradle’s default plugin directory. When building Gradle, this directory is automatically recognized and the code in it is compiled into a plugin.
-
First create a Java Module named buildSrc, then save build.gradle and SRC /main, delete everything else, make sure the name is buildSrc, otherwise you won’t find the plugin
-
Then modify the contents of Gradle
apply plugin: 'groovy' / / must
apply plugin: 'maven'
dependencies {
implementation gradleApi() / / must
implementation localGroovy() / / must
// If you want to use the Android API, you need to reference this, which will be used to implement the Transform
/ / implementation 'com. Android. View the build: gradle: 3.3.0'
}
repositories {
google()
jcenter()
mavenCentral() / / must
}
// Set the project entry to SRC /main/groovy
sourceSets {
main {
groovy {
srcDir 'src/main/groovy'}}}Copy the code
- Create the entry directory and create the code entry directory under SRC /main as follows:
- Then implement the plug-in code
Text.groovy
Note that the file suffix isgroovy
The file to be importedpackage com.renxh
package com.renxh
import org.gradle.api.Plugin
import org.gradle.api.Project
class Text implements Plugin<Project> {
@Override
void apply(Project project) {
println("Perform custom plug-ins")
project.task("haha"){
doLast{
println("Implementing a custom plug-in haha Task")}}}}Copy the code
- The next in
main
Create in directoryresources
Directory,resources
Create in directoryMETA-INF
Directory,META-INF
Create in directorygradle-plugins
Directory,gradle-plugins
Create in directoryproperties
file properties
The file can be named itself, but only after.properties
Ending, for examplecom.renxh.plugin.properties
- At the end of the day
properties
The file specifies the class in which we implement the plug-inimplementation-class=com.renxh.Text
So far our plugin project has been written. We will introduce our plugin apply plugin:’com.renxh.plugin’ in the module and then execute the plugin Task,./gradlew haha
The output
> Task :mylibrary:Haha Execution custom plug-in HAHA Task Execution phase, task':mylibrary:haha'Time:0ms
Copy the code
This form of writing, in our entire project module can be used, but only limited in this project, other projects can not use
Customize the Module and upload maven
The second way to write plugins can only be used in this project, but not in other projects. Sometimes we need a plugin to be used in multiple projects, and then we need to upload the plugin to Maven
- So let’s first set up one
java module
, the name can be arbitrary, only to retainbuild.gradle
andsrc/main
, other files are deleted - Modify Gradle contents
apply plugin: 'groovy' / / must
apply plugin: 'maven' // This plugin must be used in order to publish to Maven
dependencies {
implementation gradleApi() / / must
implementation localGroovy() / / must
}
repositories {
mavenCentral() / / must
}
def group='com.renxh.cusplugin' / / group
def version='2.0.0' / / version
def artifactId='myplugin' // Unique identifier
// Upload the package to your local Maven repository
uploadArchives {
repositories {
mavenDeployer {
pom.groupId = group
pom.artifactId = artifactId
pom.version = version
// Specify the local maven path, in the project root directory
repository(url: uri('.. /repos'))}}}Copy the code
In contrast to buildSrc, this adds Maven support and uploadArchives, a Task that packages local plugins and uploadArchives to the local Maven repository. /repos represents the repos under the project root, two of them. Go back two times to the root of the project
The steps to generate groovy files and properties files in SRC /main are the same as in the buildSrc schema
Writing a plug-in
class CustomPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
project.task("cusplugin"){
doLast{
println("Cusplugin task perform 111")}}}}Copy the code
Then execute. / gradlew CusPlugin: uploadArchivesuploadArchives tasks, and then you can decorate the repos directory to the project root directory, as shown in figure:
Repos directory is the local Maven repository, com/renxh/cusplugin is the group specified in the script, myplugin is the module name specified in the script and is a unique identifier, 1.0.0 is the version of the script
- After creating a local Maven repository, you need to reference the plugins in the local Maven repository. First, you need to add the following in the root directory of build.gralde:
buildscript {
repositories {
google()
jcenter()
// Import the local repository
maven {
url uri('./repos') // Specify the local maven path, in the project root directory
}
}
dependencies {
classpath 'com. Android. Tools. Build: gradle: 3.5.3'
// Import plug-in dependencies from the local repository
classpath 'com. Renxh. Cusplugin: myplugin: 1.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files}}Copy the code
- Classpath specifies the path format, as follows:
These three parameters are configured in the build.gradle script when the repository is built
classpath '[groupId]:[artifactId]:[version]'
Copy the code
- Once configured, you can use it in your Module
apply plugin: 'com.android.application'
apply from: rootProject.getRootDir().getAbsolutePath() + "/utils.gradle"
apply plugin:'com.renxh.cusplugin'
Copy the code
- Finally, you can perform the tasks in the plug-in
./gradlew app:cusplugin
> Task :app:Cusplugin The Cusplugin task is executed111Execution phase, task':app:cusplugin'Time:0ms
Copy the code
Extension Extension for a plug-in
We can also configure parameters for the plug-in while it is running, and the Extension is used to pass parameters back to the plug-in
I’ll add an Extension to the plugin above
First create an entity class to receive the parameters
package com.renxh.cusplugin
class MyExtension {
String name;
int age;
}
Copy the code
Then go to the plug-in class and add the extension
class CustomPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
// Add the extension
project.extensions.add('myextension',MyExtension)
project.task("cusplugin"){
doLast{
println("Cusplugin task perform 111")
MyExtension extension = project.myextension
//3. Output the extension properties of the plug-in
println ">>>>>> name: ${extension.name} age:${extension.age}"}}}}Copy the code
- Add the custom entity class to the extension with a name via project.extension.add
- Then get the extended entity class by name
- Finally get the attributes in the extension
Upload Maven again
Once the upload is complete, you can use the extended entity class in your Module
apply plugin: 'com.android.application'
apply from: rootProject.getRootDir().getAbsolutePath() + "/utils.gradle"
apply plugin:'com.renxh.cusplugin'
myextension{
name 'renxh'
age 27
}
Copy the code
Finally, execute the task,./gradlew app: Cusplugin in the plug-in
> Task :app:Cusplugin The Cusplugin task is executed111
>>>>>> name: renxh age:27Execution phase, task':app:cusplugin'Time:2ms
Copy the code
Nested Extension
We often see this nested extension in Android, as follows:
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.aliyun.idrs.app"
minSdkVersion 24
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"}}Copy the code
DefaultConfig is nested in Android, so how do we implement this form?
Start by creating an inner class
class Inner {
String b
void b(String b){
this.b=b
}
}
Copy the code
Then add the following code to the original extension
class MyExtension {
String name;
int age;
Inner text = new Inner()
// Create an internal Extension with the method name text
void text(Action<Inner> action) {
action.execute(text)
}
// Create an internal Extension with the method name text
void text(Closure c) {
org.gradle.util.ConfigureUtil.configure(c, text)
}
}
Copy the code
The key code here is
Inner text = new Inner()
// Create an internal Extension with the method name inner
void text(Action<Inner> action) {
action.execute(text)
}
// Create an internal Extension with the method name inner
void text(Closure c) {
org.gradle.util.ConfigureUtil.configure(c, text)
}
Copy the code
These two methods are used to create internal extensions. In actual use, only one of these methods is required. Note that the method name must be the same as the name of the member variable
Change the code in the plugin
class CustomPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
project.extensions.add('myextension',MyExtension)
project.task("cusplugin"){
doLast{
println("Cusplugin task perform 111")
MyExtension extension = project.myextension
//3. Output the extension properties of the plug-in
println ">>>>>> name: ${extension.name} age:${extension.age}inner:${extension.text.b}"}}}}Copy the code
Then you can use it in build.gradle
apply plugin:'com.renxh.cusplugin'
myextension{
name 'renxh'
age 27
text{
b "hahah"}}Copy the code
Execute the plug-in, output
> Task :app:Cusplugin The Cusplugin task is executed111
>>>>>> name: renxh age:27 inner:hahah
Copy the code
Nested Extension in Android
We can click in and look at their source code, which will eventually trace back to the BaseExtension class
private final DefaultConfig defaultConfig;
private final NamedDomainObjectContainer<BuildType> buildTypes;
public void defaultConfig(Action<DefaultConfig> action) {
this.checkWritability();
action.execute(this.defaultConfig);
}
public void buildTypes(Action<? super NamedDomainObjectContainer<BuildType>> action) {
this.checkWritability();
action.execute(this.buildTypes);
}
Copy the code
This is the same as the implementation we described above. If you have time to trace Gradle source code, but the parameters in the nested class are not required, as follows:
myextension{
name 'renxh'
age 27
// text{
// b "hahah"
/ /}
}
Copy the code
In other words, you don’t have to write text
Configure a variable number of extensions
Start by creating a class
class Student{
Student(String name){
this.name = name
}
String name
String age
boolean isMale
}
Copy the code
Then add it in the plug-in
class CustomPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
NamedDomainObjectContainer<Student> studentContainer = project.container(Student)
project.extensions.add('team', studentContainer)
project.task("cusplugin") {
doLast {
println("Cusplugin task perform 111")
NamedDomainObjectContainer<Student> team = project.team
team.findAll { Student student ->
println(student.name + "/" + student.age + "/" + student.isMale)
}
}
}
}
}
Copy the code
The most important of these is project.container(), which creates a container for managing named objects of the specified type. This is the container that creates Student, which can then be called in build.gradle
team{
xiaoming{
age = 19
isMale =true
}
xiaohong{
age = 18
isMale =false}}Copy the code
Where xiaoming and Xiaohong are name, the team tag can define multiple Student elements
Output the
> Task :app:Cusplugin The Cusplugin task is executed111
xiaohong18 / /false
xiaoming19 / /trueExecution phase, task':app:cusplugin'Time:1ms
Copy the code
reference
3 ways to customize Gradle plugins for Android
Gradle custom plugin