使用Javassist 在android运行时生成类
public class MainActivity extends Activity {
private static final String DEX_FILE_NAME_MYCLASSES = "myclasses.dex";
private static final boolean FORCE_GENRATE_DEX = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView view = (TextView)findViewById(R.id.textview_title);
final File dexFile = new File(getFilesDir(), DEX_FILE_NAME_MYCLASSES);
if (!dexFile.exists() || FORCE_GENRATE_DEX) {
// generate DEX and ODEX file.
try {
// generate "xxx.class" file via Javassist.
final ClassPool cp = ClassPool.getDefault(getApplicationContext());
final CtClass cls = cp.makeClass("hoge");
final CtConstructor ctor = new CtConstructor(null, cls);
ctor.setBody("{}");
cls.addConstructor(ctor);
final CtMethod m1 = CtMethod.make(
"public java.lang.String toString() { return \"hoge.toString() is called.\"; }",
cls);
cls.addMethod(m1);
final CtMethod m2 = CtMethod.make(
"public void setText(android.widget.TextView view) { view.setText((java.lang.CharSequence)\"hoge.setText() is called 222.\"); }",
cls);
// 创建注解
AnnotationsAttribute attr = new AnnotationsAttribute(m2.getMethodInfo().getConstPool(), AnnotationsAttribute.visibleTag);
Annotation annotation = new Annotation("android.annotation.TargetApi", m2.getMethodInfo().getConstPool());
attr.addAnnotation(annotation);
// 在方法上添加注解
m2.getMethodInfo().addAttribute(attr);
cls.addMethod(m2);
cls.writeFile(getFilesDir().getAbsolutePath());
// convert from "xxx.class" to "xxx.dex"
final DexFile df = new DexFile();
final String dexFilePath = dexFile.getAbsolutePath();
df.addClass(new File(getFilesDir(), "hoge.class"));
df.writeFile(dexFilePath);
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
}
if (dexFile.exists()) {
try {
final DexClassLoader dcl = new DexClassLoader(
dexFile.getAbsolutePath(),
getCacheDir().getAbsolutePath(),
getApplicationInfo().nativeLibraryDir,
getClassLoader());
String title = null;
final Class<?> class_hoge = dcl.loadClass("hoge");
final Constructor<?> ctor = class_hoge.getConstructor(new Class<?>[0]);
final Object obj = ctor.newInstance(new Object[0]);
title = obj.toString();
view.setText(title);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
try {
final Method m = obj.getClass().getDeclaredMethod("setText", TextView.class);
m.invoke(obj, view);
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}, 2000);
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}