android studio利用TransformApi配合ASM(ClassReader,ClassWriter,ClassVisitor)重新生成java字节码

目录

          • 1.Some Docs
          • 2.add `buildSrc` directory and `sync project`
          • 3.ide auto tip add named directory in `main`
          • 4.add `build.gradle` file in buildSrc directory
          • 5.app `build.gradle` add apply AsmPlugin
          • 6.plugin code
          • 7.gradle task

文章来自:http://blog.csdn.net/intbird 转载请说明出处

1.Some Docs

下面的示例代码也是查看这些官网文档后编写的
文档都比较详细, 实现起来也很简单
注意gradle版本和gradle-api版本

  1. Gradle BuildSrc Doc
  2. Gradle Custom Plugin
  3. Gradle Transform Api Doc
  4. ASM Guiles
  5. ASM IDE Plugin
  6. Jadx
2.add buildSrc directory and sync project

android studio利用TransformApi配合ASM(ClassReader,ClassWriter,ClassVisitor)重新生成java字节码_第1张图片

3.ide auto tip add named directory in main

android studio利用TransformApi配合ASM(ClassReader,ClassWriter,ClassVisitor)重新生成java字节码_第2张图片

4.add build.gradle file in buildSrc directory

android studio利用TransformApi配合ASM(ClassReader,ClassWriter,ClassVisitor)重新生成java字节码_第3张图片
NOTE:

  1. gradle-api 依赖在 google() 仓库中
  2. [ ASM Maven Url ]
  3. buildSrc build.gradle code
plugins {
    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"
}
5.app build.gradle add apply AsmPlugin

android studio利用TransformApi配合ASM(ClassReader,ClassWriter,ClassVisitor)重新生成java字节码_第4张图片
NOTE:

  1. [ use gradle plugin doc ]
  2. app.build.gradle apply plugin
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: intbird.soft.gradle.asm.AsmPlugin
...
6.plugin code

AsmPlugin code

  1. [ use gradle custom plugin ]
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

  1. [ Transform API ]
  2. [ Transform API Doc ]
  3. [ Gradle Api Maven Url]
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

  1. [ ASM DOC ]
  2. [ASM Plugin]
  3. [ ASM Maven Url ]
  4. [Class Api]
    [ClassReader]
    [ClassWrite]
    [ClassVisitor]
    [ClassNote]
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
    }
}
7.gradle task
Executing task 'transformClassesWithIntbird.soft.gradle.asm.transform.string.StringTransformForDebug'

android studio利用TransformApi配合ASM(ClassReader,ClassWriter,ClassVisitor)重新生成java字节码_第5张图片
文章来自:http://blog.csdn.net/intbird 转载请说明出处

你可能感兴趣的:(Java代码,ASM,ClassVisitor)