原理:
context.startActivity跳转间接使用Instrumentation对象execStartActivity方法,而Instrumentation存在于ActivityThread中,有趣的是在应用启动后,有且只有一个ActivityThread对象,那么Instrumentation也只有一个,也就是说不管哪个Context使用startActivity方法都是间接使用同一个Instrumentation对象。既然要过滤startActivity请求,那么可以通过替换原来的Instrumentation来达到我们的目的。这里使用代理模式,在做具体实现之前,先执行我们设定的动作(过滤)。
注:如果使用JDK自带的代理处理模块,在Android上不能运行,因为Android使用的Dalvik字节码,而不是java字节码,需要使用第三方库dexmaker。
1、实现代理接口
作用:在执行execStartActivity方法前先过滤。
public class MyInvocationHandler implements InvocationHandler {
private Instrumentation instrumentation;
public void bind(Instrumentation instrumentation) {
this.instrumentation = instrumentation;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
boolean flag = false;
if ("execStartActivity".equals(method.getName())) {
Intent intent = (Intent) args[4];
String className = intent.getComponent().getClassName();
Log.v("class-name:", String.valueOf(className));
if (className != null && "com.example.select.TestB".equals(className)) {
flag = true;
Log.v("filter", String.valueOf(className));
}
}
/*如果不是我们过滤的意图,那么按照原来的方式运行.*/
if (!flag) {
result= method.invoke(instrumentation, args);
}
return result;
}
}
2、替换Instrumentation
作用:自定义Instrumentation功能
private void selectActivity() {
try {
Class
c = Class.forName("android.app.ActivityThread");
Field mInstrumentationField = c.getDeclaredField("mInstrumentation");
mInstrumentationField.setAccessible(true);
// 通过currentActivityThread静态方法获得ActivityThread对象.
Object activityThread = c.getMethod("currentActivityThread").invoke(null);
Instrumentation instrumentation = (Instrumentation) mInstrumentationField.get(activityThread);
MyInvocationHandler myMyInvocationHandler = new MyInvocationHandler();
myMyInvocationHandler.bind(instrumentation); //绑定Instrumentation
/*生成Instrumentation代理对象*/
Instrumentation minInstrumentation = ProxyBuilder.forClass(Instrumentation.class).dexCache(getApplicationContext().getDir("dx", Context.MODE_PRIVATE))
.handler(myMyInvocationHandler)
.build();
/*替换原来的Instrumentation对象.*/
mInstrumentationField.set(activityThread, minInstrumentation);
} catch (Exception e) {
e.printStackTrace();
}
}