1. 代码如下
public class HookApplication extends Application {
private static final String TAG = "HookApplication";
@Override
public void onCreate() {
super .onCreate();
hookInstrumentation();
}
private void hookInstrumentation() {
try {
Field mMainThread = getBaseContext().getClass().getDeclaredField("mMainThread");
mMainThread.setAccessible(true);
Object o = mMainThread.get(getBaseContext());
Field mInstrumentation = o.getClass().getDeclaredField("mInstrumentation");
mInstrumentation.setAccessible(true);
Instrumentation instrumentation = (Instrumentation) mInstrumentation.get(o);
InstrumentationProxy proxy = new InstrumentationProxy(instrumentation);
mInstrumentation.set(o, proxy);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public static class InstrumentationProxy extends Instrumentation {
protected Instrumentation instrumentation;
public InstrumentationProxy(Instrumentation instrumentation) {
this.instrumentation = instrumentation;
}
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
Log.i(TAG, "proxy execStartActivity");
// 带欺骗标志则用注入欺骗activity的ComponentName(即下方的MainActivity)
String activityTag = intent.getStringExtra("isUnRegister");
if(activityTag != null) {
ComponentName realComponentName = intent.getComponent();
intent.putExtra("realComponentName", realComponentName);
ComponentName fakeComponentName = new ComponentName(MainActivity.class.getPackage().getName(), MainActivity.class.getName());
intent.setComponent(fakeComponentName);
}
Class[] classes = new Class[]{Context.class, IBinder.class, IBinder.class, Activity.class, Intent.class, int.class, Bundle.class};
try {
Method method = getClass().getSuperclass().getDeclaredMethod("execStartActivity", classes);
Log.i(TAG, "proxy execstartActivity Method:"+ method);
if (method != null) {
//注意这里的obj必须用原本的Instrumentation
return (ActivityResult) method.invoke(instrumentation, new Object[]{who, contextThread, token, target, intent, requestCode, options});
}
} catch (NoSuchMethodException | IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.getTargetException().printStackTrace();
}
return null;
}
public Activity newActivity(ClassLoader cl, String className, Intent intent)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
Log.i(TAG, "proxy newActivity");
String newClassName = className;
String activityTag = intent.getStringExtra("isUnRegister");
ComponentName componentName = intent.getParcelableExtra("realComponentName");
if(activityTag != null && componentName != null) {
newClassName = componentName.getClassName();
intent.setComponent(componentName);
}
return instrumentation.newActivity(cl, newClassName, intent);
}
}
}
2. 简单逻辑说明
startActivity(Intent) 时会走android.app.Activity中的startActivityForResult,然后通过mInstrumentation的execStartActivity开始启动,
经过一系列操作后,在ActivityThread中handleLaunchActivity,然后调用mInstrumentation的newActivity获取activity实例。
so 只要重写下mInstrumentation的两个方法就可以简单实现免注册启动activity