How to Use Android Studio to develop the Gradle plug-in
Reason
First, explain why this article exists. Some time ago, plug-ins and Hotfix technologies were very popular. Nuwa hotfix tool NuwaGradle, Ctrip dynamic loading technology DynamicAPK, and Small, which wanted to be the most lightweight plug-in framework. One common feature of these three apps is the extensive use of Gradle, a powerful build tool. Apart from Ctrip's framework, the other two have released independent Gradle plug-ins to provide automated build plug-ins or generate hotfix patches. So it makes sense to write the Gradle plug-in.
Plug-in type
Gradle plug-ins generally have the following types:
One is to write it directly in the gradle file of the project. The disadvantage of this method is that the plug-in Code cannot be reused, and you have to copy the code (or copy the file again) in other projects) the other is to compile the plug-in an independent project and publish it to the central repository. Then you can directly reference the plug-in. The advantage is that the plug-in can be reused. Just like Nuwa and Small above. Gradle syntax
This article will not detail the Gradle-related syntaxes. If you want to learn about gradle, see Gradle for Android.
Gradle plug-in development
The Gradle plug-in is developed using Groovy, and Groovy is actually compatible with Java. In fact, in addition to developing Android apps, Android Studio is fully competent for developing the Gradle plug-in. The following describes how to develop it.
First, create an Android project. Then, create an Android Module Project and select Android Library as the type. Delete all the files except the build. gradle file in the newly created Module, and then delete all the content in the build. gradle file. Create a folder src in the newly created module, create a main folder under the src file directory, and create a groovy directory under the main directory. At this time, the groovy folder will be recognized as the groovy source code directory by Android. In addition to creating a groovy directory under the main directory, you also need to create a new resources directory under the main directory. Similarly, the resources directory will be automatically recognized as a resource folder. Create a project package name in the groovy directory, just like the Java package name. New folder META-INF under the resources Directory, new gradle-plugins folder under the META-INF folder. In this way, the overall construction of the gradle plug-in project is completed, and then the details are small. Currently, the project structure is as follows.
Open the build. gradle file under Module and enter
apply plugin: 'groovy'apply plugin: 'maven'dependencies { compile gradleApi() compile localGroovy()}repositories { mavenCentral()}
Next we will create a new file named PluginImpl. groovy under the package name. Note that there is a groovy suffix, and enter it in it. Note that the package name is replaced with your own package name.
package cn.edu.zafu.gradleimport org.gradle.api.Pluginimport org.gradle.api.Projectpublic class PluginImpl implements Plugin
{ void apply(Project project) { project.task('testTask') << { println "Hello gradle plugin" } }}
Then create a new properties file under the resources/META-INF/gradle-plugins directory, note that the file name is that you only use the plug-in name, here the name isPlugin. test. properties, Enter
implementation-class=cn.edu.zafu.gradle.PluginImpl
Note that the package name must be replaced with your own package name.
This completes the simplest gradle plug-in, which contains a Task named testTask. After executing this task, a piece of text is output, just like the HelloWorld output.
Publish to local repository
Next, we need to release the plug-in to the maven central repository. Just release the plug-in to the local repository and add the released code to the buidl. gradle file under the module project.
repositories { mavenCentral()}group='cn.edu.zafu.gradle.plugin'version='1.0.0'uploadArchives { repositories { mavenDeployer { repository(url: uri('../repo')) } }}
The group and version definitions above will be used. As part of the coordinate of the maven database, the group will be used as the groupId of the coordinate, and the version will be used as the coordinate version, while the artifactId of coordinates is the module name. Let's get it an alias moduleName. Then, the maven local repository directory is the repo directory under the current project directory.
At this time, the gradle Toolbar on the right will have an additional task under the module.
Click the uploadArchives Task to create a repo directory under the project, which contains the gradle plug-in.
The directory is like this. The specific directory structure is related to your package name. time is my module name.
After it is released to the local maven repository, we will use it and add it to the gradle. build File called app's android project.
buildscript { repositories { maven { url uri('../repo') } } dependencies { classpath 'cn.edu.zafu.gradle.plugin:time:1.0.0' }}apply plugin: 'plugin.test'
The name enclosed in quotation marks after apply plugin is the file name of the previous plug-in. test. properties file. The content in the quotation marks behind the class path is jointly determined by the group, version, and moduleName defined in the above grade, which is the same as that in maven.
Synchronize gradle, and a testTask will be added under the other category under the app on the right. Double-click the Task and the console will output the string we just entered.
Publish to Jcenter Repository
Next we will release it to the jcenter central repository. Refer to the previous article to publish the Open Source Library to the central Jcenter library using Android Studio.
Add it to the build. gradle file under the root directory of the project.
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' }
Create a bintray. gradle file in the root path of the project, and enter
apply plugin: 'com.jfrog.bintray'apply plugin: 'maven-publish'def projectName = "timePlugin"def mavenDesc = 'your desc'def baseUrl = 'https://github.com/yourBaseUrl'def siteUrl = baseUrldef 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 }}
Modify the descriptive text to your own information, especially the first series of def definitions, and add BINTRAY_USER and BINTRAY_KEY to the gradle. properties file.
Apply this grade file in your module
apply from: '../bintray.gradle'
The toolbar of gradle on the right has several more tasks.
Then we run the install task under other and then the bintrayUpload task. If there is no accident, the task will be uploaded,Do not forget to add to jcenter in the background. After the link to jcenter is successfully added to the jcenter, the link to jcenter is displayed.
Wait patiently for the message that the add to center is successful, and then you can directly reference it. Define the maven part of the gradle file under module.
maven { url uri('../repo') }
Add
jcenter()
The final content is as follows:
buildscript { repositories { jcenter() maven { url uri('../repo') } } dependencies { classpath 'cn.edu.zafu.gradle.plugin:time:1.0.0' }}apply plugin: 'plugin.test'
It's that simple. Run the test again to check whether the test is successful.
Best practices
The source of the best practice is multidex. Why? Because when the number of methods exceeds the limit recently, if multidex is selected, the compilation process will be much slower, in order to check which step is time-consuming, You need to compile a plug-in to count the execution time of each task, so there is such a best practice.
Create the TimeListener. groovy file in the directory of the PluginImpl level. Input
package cn.edu.zafu.gradleimport org.gradle.BuildListenerimport org.gradle.BuildResultimport org.gradle.api.Taskimport org.gradle.api.execution.TaskExecutionListenerimport org.gradle.api.initialization.Settingsimport org.gradle.api.invocation.Gradleimport org.gradle.api.tasks.TaskStateimport org.gradle.util.Clockclass 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 %s\n", time } } } @Override void buildStarted(Gradle gradle) {} @Override void projectsEvaluated(Gradle gradle) {} @Override void projectsLoaded(Gradle gradle) {} @Override void settingsEvaluated(Settings settings) {}}
Then modify the apply method in the PluginImpl file
void apply(Project project) { project.gradle.addListener(new TimeListener()) }
Package and release the package to jcenter (). After that, you only need to reference the plug-in to calculate the execution time of each task, such as running the app, and then output the following information.
At the end of the best practice, I will promote this plug-in. I have released it to the jcenter repository. If you want to use it, add the following code.
buildscript { repositories { jcenter() } dependencies { classpath 'cn.edu.zafu.gradle.plugin:time:1.0.0' }}apply plugin: 'plugin.time'
PASS Parameters
The above is a small test, and then we need to get custom parameters.
First, create a module according to the above steps. Create PluginExtension. groovy and enter
public class PluginExtension { def param1 = "param1 defaut" def param2 = "param2 defaut" def param3 = "param3 defaut"}
Then we want to pass in nested parameters and create a new PluginNestExtension. groovy, and enter
public class PluginNestExtension { def nestParam1 = "nestParam1 defaut" def nestParam2 = "nestParam2 defaut" def nestParam3 = "nestParam3 defaut"}
Create a CustomTask. groovy, inherit the DefaultTask class, and use the @ TaskAction annotation to mark the implementation method.
public class CustomTask extends DefaultTask { @TaskAction void output() { println "param1 is ${project.pluginExt.param1}" println "param2 is ${project.pluginExt.param2}" println "param3 is ${project.pluginExt.param3}" println "nestparam1 is ${project.pluginExt.nestExt.nestParam1}" println "nestparam2 is ${project.pluginExt.nestExt.nestParam2}" println "nestparam3 is ${project.pluginExt.nestExt.nestParam3}" }}
Just get the parameters, and then do the simplest output operation, use$ {Project. pluginExt. param1}And$ {Project. pluginExt. nestExt. nestParam1}Obtain external parameters.
Don't forget to create a new properties file in the META-INF/gradle-plugins directory to specify the interface implementation class for the plug-in.
Copy the newly created PluginImpl. groovy to the package and modify the apply method.
public class PluginImpl implements Plugin
{ void apply(Project project) { project.extensions.create('pluginExt', PluginExtension) project.pluginExt.extensions.create('nestExt', PluginNestExtension) project.task('customTask', type: CustomTask) }}
Publish the plug-in to the local maven and reference it.
buildscript { repositories { maven { url uri('../repo') } } dependencies { classpath 'cn.edu.zafu.gradle.plugin:test:1.0.0' }}apply plugin: 'plugin.test'
Define external parameters. Here we define param1, param2, nestParam1, nestParam2. In addition, param3 and nestParam3 are kept by default.
pluginExt { param1 = 'app param1' param2 = 'app param2' nestExt{ nestParam1='app nestParam1' nestParam2='app nestParam2' }}
Synchronize gradle and execute customTask.
The above code is very simple and can be seen without explanation, so it is not explained.