ASM动态创建类

1,414 阅读2分钟

动态创建类:

import org.apache.commons.io.FileUtils;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.io.File;
import java.io.IOException;

import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.V1_5;

public class CreateClass {

    public static void createFakeClass(String builddir) throws IOException {
        ClassWriter cw = new ClassWriter(0);
        // public, 类名, 父类,接口
        cw.visit(V1_5, ACC_PUBLIC, "com/example/autolog/FakeClass", null, "java/lang/Object", null);

        ClassVisitor cv = new AddFieldVisitor(Opcodes.ASM5, cw);
        //增加一个成员mName
        cv.visitField(ACC_PUBLIC, "mName", "Ljava/lang/String;", null, null);
        //增加构造方法
        cv.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null).visitCode();
        //增加setName方法,参数为String,返回类型为void
        cv.visitMethod(ACC_PUBLIC, "setName", "(Ljava/lang/String;)V", null, null).visitCode();
        //增加getName方法,无参数,返回类型为String
        cv.visitMethod(ACC_PUBLIC, "getName", "()Ljava/lang/String;", null, null).visitCode();
        cv.visitEnd();
        //拷贝到javac
        FileUtils.writeByteArrayToFile(
                new File(builddir + "/intermediates/javac/debug/classes/com/example/autolog/FakeClass.class"),
                cw.toByteArray());
        //将生成类拷贝到transforms,用于dex
        FileUtils.writeByteArrayToFile(
                new File(builddir + "/intermediates/transforms/auto-log/debug/0/com/example/autolog/FakeClass.class"),
                cw.toByteArray());
    }

    public static class AddFieldVisitor extends ClassVisitor {

        public AddFieldVisitor(int api, ClassVisitor cv) {
            super(api, cv);

        }

        @Override
        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
            if ("<init>".equals(name)) {
                //在构造方法中进行变量初始化
                return new InitField(Opcodes.ASM5, super.visitMethod(access, name, desc, signature, exceptions));
            } else if ("getName".equals(name)) {
                //给getName方法增加字节码
                return new GetName(Opcodes.ASM5, super.visitMethod(access, name, desc, signature, exceptions));
            } else if ("setName".equals(name)) {
                //给setName增加字节码
                return new SetName(Opcodes.ASM5, super.visitMethod(access, name, desc, signature, exceptions));
            }
            return super.visitMethod(access, name, desc, signature, exceptions);
        }

        class InitField extends MethodVisitor {
            public InitField(int api, MethodVisitor cv) {
                super(api, cv);
            }

            @Override
            public void visitCode() {
                mv.visitVarInsn(Opcodes.ALOAD, 0);
                mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
                mv.visitVarInsn(Opcodes.ALOAD, 0);
                mv.visitLdcInsn("haha");
                mv.visitFieldInsn(Opcodes.PUTFIELD, "com/example/autolog/FakeClass", "mName", "Ljava/lang/String;");
                mv.visitInsn(Opcodes.RETURN);
                mv.visitMaxs(2, 1);
                mv.visitEnd();
            }

        }

        class GetName extends MethodVisitor {
            public GetName(int api, MethodVisitor mv) {
                super(api, mv);
            }

            @Override
            public void visitCode() {
                mv.visitVarInsn(Opcodes.ALOAD, 0);
                mv.visitFieldInsn(Opcodes.GETFIELD, "com/example/autolog/FakeClass", "mName", "Ljava/lang/String;");
                mv.visitInsn(Opcodes.ARETURN);
                mv.visitMaxs(1, 1);
                mv.visitEnd();
            }
        }

        class SetName extends MethodVisitor {
            public SetName(int api, MethodVisitor mv) {
                super(api, mv);
            }

            @Override
            public void visitCode() {
                mv.visitVarInsn(Opcodes.ALOAD, 0);
                mv.visitVarInsn(Opcodes.ALOAD, 1);
                mv.visitFieldInsn(Opcodes.PUTFIELD, "com/example/autolog/FakeClass", "mName", "Ljava/lang/String;");
                mv.visitInsn(Opcodes.RETURN);
                mv.visitMaxs(2, 2);
                mv.visitEnd();
            }
        }
    }
}

在Transform中进行创建类

 class LogTransform extends Transform {
    Project project;

    LogTransform(Project project) {
        this.project = project
    }

    @Override
    String getName() {
        return 'auto-log'
    }

    @Override
    Set<QualifiedContent.ContentType> getInputTypes() {
        return TransformManager.CONTENT_CLASS
    }

    @Override
    Set<? super QualifiedContent.Scope> getScopes() {
        return TransformManager.PROJECT_ONLY
    }

    @Override
    boolean isIncremental() {
        return false
    }

    @Override
    void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
      //...
        CreateClass.createFakeClass(project.getBuildDir().getAbsolutePath())
    }

运行时使用该类

try {
    Class fake = Class.forName("com.example.autolog.FakeClass");
    Object obj = fake.newInstance();
    Method setname = fake.getDeclaredMethod("setName", String.class);
    setname.setAccessible(true);
    setname.invoke(obj, "mainactivity");

    Method getname = fake.getDeclaredMethod("getName");
    getname.setAccessible(true);
    Log.e("onresume ", "mname : " + getname.invoke(obj));
} catch (Exception e) {
     e.printStackTrace();
}

Android中不能在运行时动态创建类:

因为创建类之后,ClassWriter生成的byte[],不能被自定义的ClassLoader加载