记得以前有做过应用内悬浮球的程序,通过自定义BaseActivity,然后重写startActivity方法达到监控的目的,从而实现提前预知程序状态,根据程序状态进而隐藏或显示悬浮球,以达到内置悬浮球的目的。
今天使用代理模式的思想实现监控startActivity
直接上代码
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
try {
Field mMainThreadField = base.getClass().getDeclaredField("mMainThread");
mMainThreadField.setAccessible(true);
Object mMainThread = mMainThreadField.get(base);
Field mInstrumentationField = mMainThread.getClass().getDeclaredField("mInstrumentation");
mInstrumentationField.setAccessible(true);
mInstrumentationField.set(mMainThread, new MyInstrumentation((Instrumentation) mInstrumentationField.get(mMainThread)));
} catch (Exception e) {
System.out.println(e.toString());
}
}
MyInstrumentation类
class MyInstrumentation extends Instrumentation {
Instrumentation mInstrumentation;
public MyInstrumentation(Instrumentation mInstrumentation) {
super();
this.mInstrumentation = mInstrumentation;
//加下面代码保险一点
try {
Method method = Class.class.getDeclaredMethod("getDeclaredFields");
Field[] declaredFields = (Field[]) method.invoke(Instrumentation.class);
//Android9.0后禁用了hide api,所以下面方法会有问题,已使用上面代码替换
// Field[] declaredFields = Instrumentation.class.getDeclaredFields();
for (Field field : declaredFields) {
field.setAccessible(true);
field.set(this, field.get(mInstrumentation));
}
} catch (Exception e) {
System.out.println(e.toString());
}
}
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
System.out.println("startActivity:" + intent.getComponent().getClassName());
try {
@SuppressLint("DiscouragedPrivateApi") Method execStartActivityMethod = Instrumentation.class.getDeclaredMethod(
"execStartActivity",
Context.class,
IBinder.class,
IBinder.class,
Activity.class,
Intent.class,
int.class,
Bundle.class
);
return (ActivityResult) execStartActivityMethod.invoke(mInstrumentation, who, contextThread, token, target, intent, requestCode, options);
} catch (Exception e) {
System.out.println(e.toString());
return null;
}
}
public int execStartActivitiesAsUser(
Context who,
IBinder contextThread,
IBinder token,
Activity target,
Intent[] intents,
Bundle options,
int userId) {
try {
@SuppressLint("DiscouragedPrivateApi") Method execStartActivitiesAsUserMethod = Instrumentation.class.getDeclaredMethod(
"execStartActivitiesAsUser",
Context.class,
IBinder.class,
IBinder.class,
Activity.class,
Intent[].class,
Bundle.class,
int.class
);
for (Intent intent :
intents) {
System.out.println("startActivties:" + intent.getComponent().getClassName());
}
return (int) execStartActivitiesAsUserMethod.invoke(mInstrumentation, who, contextThread, token, target, intents, options, userId);
} catch (Exception e) {
System.out.println(e.toString());
return 0;
}
}
}
敲一遍应该是可以看懂滴