ASMをつかってdex前にclass fileを覗き見る
Manipulating Java Class Files with ASM 4 - Part One : Hello World! をAndroidのプロジェクトにやってみた。
まず /buildSrc/build.gradle *1 に ASM の依存を書く。
apply plugin: 'groovy' repositories { mavenCentral() } dependencies { compile gradleApi() compile localGroovy() compile 'org.ow2.asm:asm:5.0.+' }
要はclass fileをコンパイルした直後、dex file (dalvik executable) を生成するまえにASMのClassVisitorで覗き見てやればいいわけで、moduleのbuild.gradleでこんな感じにするとよい。
android.applicationVariants.all { variant -> variant.javaCompile.doLast { String path = file('build/classes/debug/com/github/gfx/asmexample/app/MainActivity.class') ClassDumper.dump([path]) } }
あとは、ClassDumperを書く。今回は buildSrc/src/main/groovy/com/github/gfx/asmexample/ClassDumper.groovy にロジックを書いた。中身は上記ブログそのまま。
package com.github.gfx.asmexample import org.objectweb.asm.* public class ClassDumper extends ClassVisitor { public static void dump(ArrayList<String> args) throws IOException { ClassVisitor visitor = new ClassDumper(Opcodes.ASM5); for (String file : args) { InputStream ins = new FileInputStream(file); new ClassReader(ins).accept(visitor, 0); } } public ClassDumper(int v) { super(v); } @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { System.out.println("Visiting class: " + name); System.out.println("Class Major Version: " + version); System.out.println("Super class: " + superName); super.visit(version, access, name, signature, superName, interfaces); } @Override public void visitOuterClass(String owner, String name, String desc) { System.out.println("Outer class: " + owner); super.visitOuterClass(owner, name, desc); } @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { System.out.println("Annotation: " + desc); return super.visitAnnotation(desc, visible); } @Override public void visitAttribute(Attribute attr) { System.out.println("Class Attribute: " + attr.type); super.visitAttribute(attr); } @Override public void visitInnerClass(String name, String outerName, String innerName, int access) { System.out.println("Inner Class: " + innerName + " defined in " + outerName); super.visitInnerClass(name, outerName, innerName, access); } @Override public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { System.out.println("Field: " + name + " " + desc + " value:" + value); return super.visitField(access, name, desc, signature, value); } @Override public void visitEnd() { System.out.println("Ends here"); super.visitEnd(); } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { System.out.println("Method: " + name + " " + desc); return super.visitMethod(access, name, desc, signature, exceptions); } @Override public void visitSource(String source, String debug) { System.out.println("Source: " + source); super.visitSource(source, debug); } }
出力結果:
Visiting class: com/github/gfx/asmexample/app/MainActivity Class Major Version: 51 Super class: android/app/Activity Source: MainActivity.java Inner Class: layout defined in com/github/gfx/asmexample/app/R Inner Class: menu defined in com/github/gfx/asmexample/app/R Inner Class: id defined in com/github/gfx/asmexample/app/R Method: <init> ()V Method: onCreate (Landroid/os/Bundle;)V Method: onCreateOptionsMenu (Landroid/view/Menu;)Z Method: onOptionsItemSelected (Landroid/view/MenuItem;)Z Ends here