Android 自定义Gradle插件
简介、
首先新创建一个Android 项目,刚开始只有一个Android-app的application模块,其他的你先不要看,这整个项目模块结构是为了完成一个arouter项目,因为这是为了关注自定义Gradle插件,所以下面重点讲解ArouterPlugin这个Java模块的创建使用流程。
Arouter整体结果如下:
一、创建插件模块
1.1、new-》new module->选择java模块创建
1.2、创建好模块后
步骤:
- 首先将mian目录下所有东西删除
- 再创建一个groovy模块文件夹,按照下图创建好目录文件夹,内容后面再说
- 再创建一个resources文件夹,文件名称 META-INF/gradle-plugins/com.example.pluginarouter.properties,必须按照这个结构创建文件, 注意:com.example.pluginarouter 这个名称后续会用到
1.3、配置插件模块的build.gradle文件,创建插件仓库用于生成jar包,便于其他模块可以使用插件
下面的配置,注意 gradle版本为4.1.0,本来想用最新的gradle版本7.0.2但是,因为太新了,废弃了Transform(借助它编译时扫描Android所有的class文件,完成字节码插桩) Api,现在应该怎么做,官方文档也没说清楚,所以我暂时使用4.1.0 ,并且官网
gradle插件版本为7.0.1,插件版本7.0以上需要使用publishing的方式配置生成
apply plugin: 'groovy'
dependencies {
//gradle sdk
implementation gradleApi()
//groovy sdk
implementation localGroovy()
// implementation "com.android.tools.build:gradle:7.0.1"
implementation "com.android.tools.build:gradle:4.1.0"
}
//以下内容主要用于发布插件
//gradle 7.0之后过时 参考:https://docs.gradle.org/current/userguide/publishing_maven.html#publishing_maven:complete_example
//apply plugin: 'maven'
//repositories {
// mavenCentral()
//}
//group = 'com.example.myplugin'
//version = '1.0.3'
//
//uploadArchives {
// repositories {
// mavenDeployer {
//// ./是当前目录../是父级目录
// repository(url: uri('./../repo'))
// }
// }
//}
//以下内容主要用于发布插件---gradle插件版本7.0以上
apply plugin: 'maven-publish'
repositories {
mavenCentral()
}
group = 'com.example.arouterplugin'
version = '1.0.0'
publishing {
publications {
mavenJava(MavenPublication) {
groupId = group
artifactId = 'arouter'
version = version
from components.java
// versionMapping {
// usage('java-api') {
// fromResolutionOf('runtimeClasspath')
// }
// usage('java-runtime') {
// fromResolutionResult()
// }
// }
// pom {
// name = 'My Library'
// description = 'A concise description of my library'
// url = 'http://www.example.com/library'
// properties = [
// myProp: "value",
// "prop.with.dots": "anotherValue"
// ]
// licenses {
// license {
// name = 'The Apache License, Version 2.0'
// url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
// }
// }
// developers {
// developer {
// id = 'johnd'
// name = 'John Doe'
// email = 'john.doe@example.com'
// }
// }
// scm {
// connection = 'scm:git:git://example.com/my-library.git'
// developerConnection = 'scm:git:ssh://example.com/my-library.git'
// url = 'http://example.com/my-library/'
// }
// }
}
}
repositories {
maven {
// change URLs to point to your repos, e.g. http://my.org/repo
// def releasesRepoUrl = layout.buildDirectory.dir('repos/releases')
// def snapshotsRepoUrl = layout.buildDirectory.dir('repos/snapshots')
// url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
// ./是当前目录../是父级目录
url ='./../repo'
}
}
}
1.4、使用自定义的插件打印一句话这是最简单的
按照上图在groovy模块文件夹下,创建一个MyPlugin的java文件
package com.example.arouterplugin;
import com.android.build.gradle.AppExtension;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
/**
* @author tgw
* @date 2021/10/16
* @describe
*
* //Asm的使用:https://www.jianshu.com/p/905be2a9a700
* 使用asm提供的通过 ASMifier 自动生成对应的 ASM 代码。首先需要在ASM官网 下载 asm-all.jar 库,我下载的是最新的 asm-all-5.2.jar,然后使用如下命令,即可生成
* 命令:
* java -classpath E:\googleDowmload\asm-all-5.1.jar org.objectweb.asm.util.ASMifier E:\MyLearing\MyAptUseLearing\base-arouter\build\tmp\kotlin-classes\debug\com\example\base_arouter\ARouterUtils.class
*
* jar包下载地址:
* http://nexus.neeveresearch.com/nexus/content/repositories/public/org/ow2/asm/asm-all/5.1/
*/
class MyPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
AppExtension android = (AppExtension) project.getExtensions().getByType(AppExtension.class);
android.registerTransform(new ScanAllFileTransform(project));
System.out.println("MyPlugin自定义独立插件0.................");
}
}
上面的ScanAllFileTransform文件暂时不要管,这是为了做编译时扫描文件所用的,我们这只是为了打印一句话
1.5、配置插件文件在前面创建的插件配置文件com.example.pluginarouter.properties下:
内容如下
implementation-class = com.example.arouterplugin.MyPlugin
1.6、生成插件的jar包:
选择你的插件模块点击publish生成jar,jar包的生成路径就是你在1.3中配置的路径
仓库jar生成如下
1.7、使用插件jar包
1.7.1、在你想要使用插件的模块下配置,插件仓库路径,如app模块下
注意仓库地址要在最下面:如下图
1.7.2、使用插件,插件的名称就是,你前面创建的插件配置文件的文件名称
//引入插件ArouterPluginmodule下的MyPlugin,
// 不能放在上面的plugins中,
apply plugin: 'com.example.pluginarouter'
1.8、结果:
这时候你clear 项目 再次编辑就,能够在编译时看到你写的插件内容:
结语:我们使用插件肯定不是为了打印一句话
二、我们使用gradle中的Transform这个类去扫描class文件,收集自己想要的去进行字节码插桩
具体的大家可以参考阿里的Arouter组件大体用法差不多
大致思路如下:
遍历所有的class文件,找出你想要插桩的文件存入集合(这里存在规则匹配,具体的看你自己),利用Asm进行字节码插桩
篇幅过长下次再说: