Gradle
Android Studio 项目是使用 Gradle 构建的,构建工具 Gradle 可以看做是一个脚本,包含一系列的Task,依次执行这些 Task 后,项目就打包成功了。而 Task 有一个重要的概念,那就是inputs 和outputs 。
Task 通过 inputs 拿到一些东西,处理完毕之后就输出 outputs ,而下一个 Task 的 inputs 则是上一个 Task 的outputs。
不同的 Plugin 提供了不同的 Task 来实际不同的功能。
可以简单的理解为: Gradle只是一个框架,真正起作用的是plugin。而plugin的主要作用是往Gradle脚本中添加Task
我们需要在整个 Gradle 工作的过程中,找到合适的时机来插入自定义的 Plugin,然后在 Plugin 中使用 Javassist 对字节进行操作 ,所以使用 Javassit 的前提是掌握自定义 Gradle 插件。
从Gradle1.5.0-beta1开始,android的gradle插件引入了Transform,我们刚好就可以利用这个 API 来使用 Javassist 。
Javassist
Javassist 是一个执行字节码操作的库。它可以在一个已经编译好的类中添加新的方法,或者是修改已有的方法,并且不需要对字节码方面有深入的了解。
Javassist 可以绕过编译,直接操作字节码,从而实现代码注入,所以使用 Javassist 的时机就是在构建工具 Gradle 将源文件编译成 .class 文件之后,在将 .class 打包成 dex 文件之前。
开发步骤:
1、创建自定义 Gradle plugin module
新建Android library module 留下src/main和build.gradle,其他的文件删除
2、在 插件的module 中添加依赖:
apply plugin: 'groovy'
apply plugin: 'maven'
dependencies {
compile gradleApi()
compile localGroovy()
compile fileTree(dir: 'libs', includes: ['*.jar'])
compile 'com.android.tools.build:transform-api:1.5.0'
compile 'javassist:javassist:3.12.1.GA'
compile 'commons-io:commons-io:2.5'
compile 'com.android.tools.build:gradle:3.4.2'
}
uploadArchives {
repositories {
mavenDeployer {
repository(url: 'file:///Users/xxx/Maven/transform-lib/')
}
}
}
group = 'com.xxx.transform'
version = '1.0.0'
3、Gradle Transform API
在main目录下创建 groovy 文件夹,然后在 groovy 目录下就可以创建我们的包名和 groovy 文件了,记得后缀要已 .groovy 结尾。在这个文件中引入创建的包名,然后写一个Class继承于Plugin< Project > 并重写apply方法,并注册Transform:
public class MyPlugin implements Plugin<Project> {
void apply(Project project) {
//AppExtension就是build.gradle中android{...}这一块
def android = project.extensions.getByType(AppExtension)
//todo 注册一个Transform
def classTransform = new MyClassTransform(project)
android.registerTransform(classTransform)
}
4、配置plugin
在main目录下创建resources文件夹,继续在resources下创建META-INF文件夹,在META-INF文件夹下创建gradle-plugins文件夹。
5、gradle-plugins文件夹下创建一个xxx.properties文件,
注意:这个xxx就是在app下的build.gradle中引入时的名字,例如:apply plugin: ‘xxx’。
在文件中写 implementation-class=com.xxx.plugin.MyPlugin
6、修改build.gradle 内容,然后执行 uploadArchives 这个task 上传到 maven 库,就将我们的这个插件打包上传到了本地 maven 中,可以去本地的 maven 库中查看
7、自定义 Transform
public class MyClassTransform extends Transform {
private static final NAME = "MyClassTransform"
public MyClassTransform(Project project) {
MyInjector.init(project)
}
/**
* Transform的名称
* */
@Override
public String getName() {
return NAME
}
/**
* 需要处理的数据类型,有两种枚举类型
* */
@Override
public Set<QualifiedContent.ContentType> getInputTypes() {
return TransformManager.CONTENT_CLASS
}
/**
* 指定操作范围,官方文档有其中范围
* */
@Override
public Set<QualifiedContent.Scope> getScopes() {
return TransformManager.SCOPE_FULL_PROJECT
}
/**
* 是否支持增量编译
* */
@Override
public boolean isIncremental() {
return false
}
/**
* 核心方法,文件输入、输出流,在这一步做注入操作
* */
@Override
public void transform(Context context,
Collection<TransformInput> inputs,
Collection<TransformInput> referencedInputs,
TransformOutputProvider outputProvider,
boolean isIncremental) throws IOException, TransformException, InterruptedException {
//使用javasist动态注入带代码
}
}
项目中使用
1、添加Maven仓库源,在工程的build.gradle中如下添加:
buildscript {
repositories {
//...
maven {
url 'file:///Users/xxx/Maven/transform-lib/'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.2'
classpath 'com.xxx.transform:plugin:1.0.0'
}
}
2、app中引入,在app的build.gradle目录下如下添加:
apply plugin: 'com.gerile.transform'
3、到此已经结束了gradle插件的创建及引用了,后续的就只是对class或xml文件的修改了,根据项目的需求插入或修改代码,具体实现请查看javasist的api。
网友评论