开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1天,点击查看活动详情
接上回Flavor配置文章介绍接入Transform,继续来讲Transform需要实现的几个方法实现及定义
继承 com.android.build.api.transform.Transform ,创建⼀个 Transform 的子类
其创建步骤可以细分为五步,如下所示:
- 重写 getName 方法:返回对应的 Task 名称。
- 重写 getInputTypes 方法:确定对那些类型的结果进行转换。
- 重写 getScopes 方法:指定插件的适用范围。
- 重写 isIncremental 方法:表示是否支持增量更新。
- 重写 transform 方法:进行具体的转换过程。
getName
每一个 Transform 都有一个与之对应的 Transform task,这里便是返回的 task name。 它会出现在 app/build/intermediates/transforms 目录下。
/**
* 每一个 Transform 都有一个与之对应的 Transform task,
* 这里便是返回的 task name。它会出现在
* app/build/intermediates/transforms 目录下
*
* @return Transform Name
*/
@Override
String getName() {
return "MyCustomTransform"
}
重写 getInputTypes 方法
getInputTypes 方法用于确定我们需要对哪些类型的结果进行转换:如字节码、资源⽂件等等。 目前 ContentType 有六种枚举类型,通常我们使用比较频繁的有前两种,如下所示:
- 1、CONTENT_CLASS:表示需要处理 java 的 class 文件。
- 2、CONTENT_JARS:表示需要处理 java 的 class 与 资源文件。
- 3、CONTENT_RESOURCES:表示需要处理 java 的资源文件。
- 4、CONTENT_NATIVE_LIBS:表示需要处理 native 库的代码。
- 5、CONTENT_DEX:表示需要处理 DEX 文件。
- 6、CONTENT_DEX_WITH_RESOURCES:表示需要处理 DEX 与 java 的资源文件。
因为我们需要修改的是字节码,所以直接返回 TransformManager.CONTENT_CLASS 即可,代码如下所示:
/**
* 需要处理的数据类型,目前 ContentType
* 有六种枚举类型,通常我们使用比较频繁的有前两种:
* 1、CONTENT_CLASS:表示需要处理 java 的 class 文件。
* 2、CONTENT_JARS:表示需要处理 java 的 class 与 资源文件。
* 3、CONTENT_RESOURCES:表示需要处理 java 的资源文件。
* 4、CONTENT_NATIVE_LIBS:表示需要处理 native 库的代码。
* 5、CONTENT_DEX:表示需要处理 DEX 文件。
* 6、CONTENT_DEX_WITH_RESOURCES:表示需要处理 DEX 与 java 的资源文件。
*
* @return
*/
@Override
Set<QualifiedContent.ContentType> getInputTypes() {
// 用于确定我们需要对哪些类型的结果进行转换:如字节码、资源⽂件等等。
// return TransformManager.RESOURCES
return TransformManager.CONTENT_CLASS
}
重写 getScopes 方法:指定插件的适用范围
目前 Scope 有 五种基本类型,如下所示:
- 1、PROJECT:只有项目内容。
- 2、SUB_PROJECTS:只有子项目。
- 3、EXTERNAL_LIBRARIES:只有外部库,
- 4、TESTED_CODE:由当前变体(包括依赖项)所测试的代码。
- 5、PROVIDED_ONLY:只提供本地或远程依赖项。
此外,还有一些复合类型,它们是都是由这五种基本类型组成,以实现灵活确定自定义插件的范围,这里通常是指定整个 project,也可以指定其它范围,其代码如下所示:
SCOPE_FULL_PROJECT 是一个 Scope 集合,包含 Scope.PROJECT,
Scope.SUB_PROJECTS, Scope.EXTERNAL_LIBRARIES 这三项,即当前 Transform
的作用域包括当前项目、子项目以及外部的依赖库
/**
* 表示 Transform 要操作的内容范围,目前 Scope 有五种基本类型:
* 1、PROJECT 只有项目内容
* 2、SUB_PROJECTS 只有子项目
* 3、EXTERNAL_LIBRARIES 只有外部库
* 4、TESTED_CODE 由当前变体(包括依赖项)所测试的代码
* 5、PROVIDED_ONLY 只提供本地或远程依赖项
* SCOPE_FULL_PROJECT 是一个 Scope 集合,包含 Scope.PROJECT,
Scope.SUB_PROJECTS, Scope.EXTERNAL_LIBRARIES 这三项,即当前 Transform
的作用域包括当前项目、子项目以及外部的依赖库
*
* @return
*/
@Override
Set<? super QualifiedContent.Scope> getScopes() {
// 适用范围:通常是指定整个 project,也可以指定其它范围
return TransformManager.SCOPE_FULL_PROJECT
}
重写 isIncremental 方法:表示是否支持增量更新
isIncremental 方法用于确定是否支持增量更新,如果返回 true,TransformInput 会包含一份修改的文件列表,如果返回 false,则会进行全量编译,并且会删除上一次的输出内容。
@Override
boolean isIncremental() {
// 是否支持增量更新
// 如果返回 true,TransformInput 会包含一份修改的文件列表
// 如果返回 false,会进行全量编译,删除上一次的输出内容
return false
}
重写 transform 方法:进行具体的转换过程
在 transform 方法中,就是用来给我们进行具体的转换过程的。其实现代码如下所示:
/**
* 进行具体的转换过程
*
* @param transformInvocation
*/
@Override
void transform(TransformInvocation transformInvocation) throws
TransformException, InterruptedException, IOException {
super.transform(transformInvocation)
println '--------------- MyTransform visit start --------------- '
def startTime = System.currentTimeMillis()
def inputs = transformInvocation.inputs
def outputProvider = transformInvocation.outputProvider
// 1、删除之前的输出
if (outputProvider != null)
outputProvider.deleteAll()
// Transform 的 inputs 有两种类型,一种是目录,一种是 jar
包,要分开遍历
inputs.each { TransformInput input ->
// 2、遍历 directoryInputs(本地 project 编译成的多个 class
⽂件存放的目录)
input.directoryInputs.each { DirectoryInput directoryInput ->
handleDirectory(directoryInput, outputProvider)
}
// 3、遍历 jarInputs(各个依赖所编译成的 jar 文件)
input.jarInputs.each { JarInput jarInput ->
handleJar(jarInput, outputProvider)
}
}
def cost = (System.currentTimeMillis() - startTime) / 1000
println '--------------- MyTransform visit end --------------- '
println "MyTransform cost : $cost s"
}
- 删除之前的输出。
- 遍历 directoryInputs(本地 project 编译成的多个 class ⽂件存放的目录)。
- 遍历 jarInputs(各个依赖所编译成的 jar 文件)。