下面的示例代码也是查看这些官网文档后编写的
文档都比较详细, 实现起来也很简单
注意gradle版本和gradle-api版本
buildSrc
directory and sync project
main
build.gradle
file in buildSrc directorybuild.gradle
codeplugins {
id 'java'
id 'groovy'
}
group 'intbird.soft.gradle'
version '1.0.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
google()
}
// https://repo.maven.apache.org/maven2/org/ow2/asm/asm/
def asmVersion = '8.0.1'
dependencies {
implementation gradleApi()
implementation localGroovy()
implementation 'com.android.tools.build:gradle-api:4.0.0'
implementation 'org.apache.directory.studio:org.apache.commons.io:2.4'
implementation "org.ow2.asm:asm:$asmVersion"
implementation "org.ow2.asm:asm-util:$asmVersion"
implementation "org.ow2.asm:asm-commons:$asmVersion"
}
build.gradle
add apply AsmPluginapp.build.gradle
apply pluginapply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: intbird.soft.gradle.asm.AsmPlugin
...
AsmPlugin code
import intbird.soft.gradle.asm.transform.string.StringTransform
import org.gradle.api.Plugin
import org.gradle.api.Project
class AsmPlugin implements Plugin {
@Override
void apply(Project project) {
println("----------intbird AsmPlugin start-----------")
StringTransform transform = new StringTransform()
// http://tools.android.com/tech-docs/new-build-system/transform-api
project.android.registerTransform(transform)
println("----------intbird AsmPlugin end-----------")
}
}
StringTransform.groovy
package intbird.soft.gradle.asm.transform.string
import com.android.build.api.transform.*
import intbird.soft.gradle.asm.transform.string.visitor.StringClassVisitor
import org.apache.commons.io.FileUtils
import org.apache.tools.ant.FileScanner
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassWriter
class StringTransform extends Transform {
@Override
String getName() {
return getClass().getName()
}
@Override
Set getInputTypes() {
return Collections.singleton(QualifiedContent.DefaultContentType.CLASSES)
}
@Override
Set getOutputTypes() {
return EnumSet.of(QualifiedContent.DefaultContentType.CLASSES)
}
@Override
Set getScopes() {
return EnumSet.of(QualifiedContent.Scope.PROJECT)
}
@Override
boolean isIncremental() {
return false
}
@Override
void transform(Context context,
Collection inputs, Collection referencedInputs,
TransformOutputProvider outputProvider, boolean isIncremental)
throws IOException, TransformException, InterruptedException {
println("----StringTransform-----")
inputs.forEach { input ->
println("----inputs-----\n" + input.toString() + "\n")
input.jarInputs.forEach { jarInput ->
println("----jar Input-----\n" + input.toString() + "\n")
File dest = outputProvider.getContentLocation(
jarInput.getFile().getAbsolutePath(),
jarInput.getContentTypes(),
jarInput.getScopes(),
Format.JAR)
transformJar(jarInput.file, dest)
}
input.directoryInputs.forEach { directoryInput ->
println("----directory Input-----\n" + directoryInput.toString() + "\n")
File dest = outputProvider.getContentLocation(
directoryInput.getName(),
directoryInput.getContentTypes(),
directoryInput.getScopes(),
Format.DIRECTORY)
transformDirectory(directoryInput.getFile(), dest)
}
}
}
private static void transformJar(File input, File dest) {
println("-----transformJar------\n" + input + "\n" + dest)
FileUtils.copyFile(input, dest)
}
private static void transformDirectory(File input, File dest) {
println("-----transformDirectory 1------\n" + input + "\n" + dest + "\n")
if (dest.exists()) {
FileUtils.forceDelete(dest)
}
FileUtils.forceMkdir(dest)
String srcDirPath = input.getAbsolutePath()
String destDirPath = dest.getAbsolutePath()
println("-----transformDirectory 2------\n" + srcDirPath + "\n" + destDirPath + "\n")
File[] files = input.listFiles()
for (File file : files) {
String destFilePath = file.absolutePath.replace(srcDirPath, destDirPath)
File destFile = new File(destFilePath)
println("-----transformDirectory 3------\n" + destFile + "\n")
if (file.isDirectory()) {
transformDirectory(file, destFile)
} else if (file.isFile()) {
FileUtils.touch(destFile)
transformSingleFile(file, destFile)
}
}
}
private static void transformSingleFile(File input, File dest) {
println("-----transformSingleFile------\n" + input + "\n" + dest + "\n")
String inputPath = input.getAbsolutePath()
String outputPath = dest.getAbsolutePath()
try {
FileInputStream fileInputStream = new FileInputStream(inputPath)
ClassReader classReader = new ClassReader(fileInputStream)
ClassWriter classWriter = new ClassWriter(classReader, 0)
StringClassVisitor classVisitor = new StringClassVisitor(classWriter)
classReader.accept(classVisitor, 0)
FileOutputStream fileOutputStream = new FileOutputStream(outputPath)
fileOutputStream.write(classWriter.toByteArray())
fileOutputStream.close()
} catch (Exception e) {
println("-----transformSingleFile Exception------\n" + inputPath + " " + e.printStackTrace())
}
}
}
StringClassVisitor.groovy
class StringClassVisitor extends ClassVisitor {
String testField = "helloField"
String testMethod = "helloMethod"
StringClassVisitor(ClassVisitor classVisitor) {
super(Opcodes.ASM7, classVisitor)
}
@Override
FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
println("------ClassVisitor visitField ------\n" + access + " " + name + " " + descriptor + " " + signature + " " + value + "\n")
FieldVisitor fieldVisitor = super.visitField(access, name, descriptor, signature, value)
if (name == testField) {
return new StringFieldsVisitor(fieldVisitor)
}
return fieldVisitor
}
@Override
MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
println("------ClassVisitor visitMethod ------\n" + access + " " + name + " " + descriptor + " " + signature + " " + exceptions + "\n")
MethodVisitor methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions)
if (name == testMethod) {
return new StringMethodVisitor(methodVisitor)
}
return methodVisitor
}
}
Executing task 'transformClassesWithIntbird.soft.gradle.asm.transform.string.StringTransformForDebug'