本文记录插件化学习过程中,如何以插件化apk方式启动带WebView的Activity,分三大步骤完成。
通过反射实现,会影响性能。
通过接口实现,dynamic-load-apk的实现原理。
通过Hook技术实现,本文采用此方式实现。
public class HookUtils {
public static void executeInstrumentationHook(Context context){
try {
Class<?> activityThreadClass=Class.forName("android.app.ActivityThread");
Field activityThreadField=activityThreadClass.getDeclaredField("sCurrentActivityThread");
activityThreadField.setAccessible(true);
//获取ActivityThread对象sCurrentActivityThread
Object activityThread=activityThreadField.get(null);
Field instrumentationField=activityThreadClass.getDeclaredField("mInstrumentation");
instrumentationField.setAccessible(true);
//从sCurrentActivityThread中获取成员变量mInstrumentation
Instrumentation instrumentation= (Instrumentation) instrumentationField.get(activityThread);
//创建代理对象InstrumentationProxy
ProxyInstrumentation proxy = new ProxyInstrumentation(instrumentation, context.getPackageManager());
//将sCurrentActivityThread中成员变量mInstrumentation替换成代理类InstrumentationProxy
instrumentationField.set(activityThread,proxy);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
public class ProxyInstrumentation extends Instrumentation {
private final Instrumentation instrumentation;
private final PackageManager mPackageManager;
public ProxyInstrumentation(Instrumentation instrumentation, PackageManager mPackageManager){
this.instrumentation = instrumentation;
this.mPackageManager = mPackageManager;
}
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options){
List<ResolveInfo> infos = mPackageManager.queryIntentActivities(intent, 0);
if (infos == null || infos.size() == 0) {
//Hook成功,执行了startActivity
intent.putExtra("TARGET_INTENT_NAME",intent.getComponent().getClassName());
// 将要送去AMS验证的Activity换成占坑的
intent.setClassName(who,"ProxyActivity完整路径");
}
try {
Method execStartActivity = Instrumentation.class.getDeclaredMethod("execStartActivity", Context.class, IBinder.class, IBinder.class, Activity.class, Intent.class, int.class, Bundle.class);
return (ActivityResult) execStartActivity.invoke(instrumentation, who, contextThread, token, target, intent, requestCode, options);
} catch (Exception e) {
e.printStackTrace();
}
return