要实现免注册跳转需要解决的问题:
1、未注册的activity怎么通过系统验证
2、怎么在handleMessage中监听 LAUNCH_ACTIVITY 的消息
解决的方法
1、使用动态代理activity替换未注册activity,使其通过系统验证
2、hook到ActivityThread、mH变量、H类;在Callback中监听 LAUNCH_ACTIVITY 的消息
//第一步:
Class<?> clazz = Class.forName("android.app.ActivityManagerNative"); //第一种 方式获取 通过gDefault Field gDefault = clazz.getDeclaredField("gDefault"); gDefault.setAccessible(true); //静态类型字段不用传入所属对象 Object defaultValue = gDefault.get(null); Class<?> aClass = Class.forName("android.util.Singleton"); Field mInstace = aClass.getDeclaredField("mInstance"); mInstace.setAccessible(true); Object iActivityManagerValue = mInstace.get(defaultValue);// 第二种方式 // Method getDefault = clazz.getDeclaredMethod("getDefault"); //获取的是子类 ActivityManagerProxy // getDefault.setAccessible(true); // //获取主线程对象 // Object defaultValue = getDefault.invoke(null); // Class<?> aClass = Class.forName("android.util.Singleton"); // Field mInstace = aClass.getDeclaredField("mInstance"); // mInstace.setAccessible(true); // Object iActivityManagerValue = mInstace.get(defaultValue); //不能获取//创建新的接口对象Class<?> iActivityManagerProxy = Class.forName("android.app.IActivityManager");AmsInvocationHandler handler = new AmsInvocationHandler(iActivityManagerValue);Object IActivityManager = Proxy.newProxyInstance(context.getClassLoader(), new Class[]{iActivityManagerProxy}, handler);// 替换掉原有的IActivityManagermInstace.set(defaultValue, IActivityManager);
/** * 拦截未注册的Activity ,替换为已 注册代理Activity */class AmsInvocationHandler implements InvocationHandler { private Object iActivityManagerValue; public AmsInvocationHandler(Object iActivityManagerValue) { this.iActivityManagerValue = iActivityManagerValue; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 替换系统方法 if ("startActivity".contains(method.getName())) { int index = 0; for (int i = 0; i < args.length; i++) { //找到 参数中的意图 if (args[i] instanceof Intent) { index = i;//非法意图的索引 break; } } for (int i = 0; i < args.length; i++) { Log.e("tag", "args:" + args[i]); } Intent proxyIntnet = new Intent(); ComponentName cn = new ComponentName(context, proxyActivity); proxyIntnet.setComponent(cn); //将 非法的意图附带在合法的意图中 作为参数 proxyIntnet.putExtra("oldIntent", (Intent)args[index]); args[index] = proxyIntnet;return method.invoke(iActivityManagerValue, args); } return method.invoke(iActivityManagerValue, args); } }//第二步:// 获取到回调 使用插件意图 替换 public void hookSystemHandler() { try { Class<?> aClass = Class.forName("android.app.ActivityThread"); //获取ActivityThread 方式一 (api17 以上适用) // Field sCurrentActivityThread = aClass.getDeclaredField("sCurrentActivityThread"); // sCurrentActivityThread.setAccessible(true); // ActivityThreadValue = sCurrentActivityThread.get(null); // 获取ActivityThread 方式二 Method currentActivityThreadMethod = aClass.getDeclaredMethod("currentActivityThread"); currentActivityThreadMethod.setAccessible(true); //获取主线程对象 Object activityThread = currentActivityThreadMethod.invoke(null); //ActivityThread 的mH字段 Field mH = aClass.getDeclaredField("mH"); mH.setAccessible(true); Handler handlerObject = (Handler) mH.get(activityThread);//获取H类中mCallback字段 Field mCallbackField = Handler.class.getDeclaredField("mCallback"); mCallbackField.setAccessible(true);//将处理后的 Handler对象替换系统的
mCallbackField.set(handlerObject, new ActivityThreadHandlerCallback(handlerObject));} catch (ClassNotFoundException e) {e.printStackTrace();} catch (IllegalAccessException e) {
e.printStackTrace();} catch (NoSuchFieldException e) {
e.printStackTrace();} catch (NoSuchMethodException e) {
e.printStackTrace();} catch (InvocationTargetException e) {
e.printStackTrace();}}class ActivityThreadHandlerCallback implements Handler.Callback {Handler handler;
public ActivityThreadHandlerCallback(Handler handler) {
super();
this.handler = handler;} @Overridepublic boolean handleMessage(Message msg) {//把非法intent替换回来if (msg.what == 100) {try {
handleLaunchActivity(msg);} catch (NoSuchFieldException e) {
e.printStackTrace();} catch (IllegalAccessException e) {
e.printStackTrace();}}handler.handleMessage(msg);
return true;
}}//替换原有的验证前的合法意图 private void handleLaunchActivity(Message msg) throws NoSuchFieldException, IllegalAccessException { Object obj = msg.obj; //获取当前ActivityRecord的记录信息 Field intentField = obj.getClass().getDeclaredField("intent"); intentField.setAccessible(true); Intent proxyIntent = (Intent) intentField.get(obj); Intent oldIntent = proxyIntent.getParcelableExtra("oldIntent"); //判断如果使用的动态代理,就使用插件intent替换掉 if (oldIntent != null) { proxyIntent.setComponent(oldIntent.getComponent()); } }//第三步在Application中调用AmsUtils amsUtils = new AmsUtils(ProxyActivity.class, this); amsUtils.hookSystemHandler(); try { amsUtils.hookAms(); } catch (Exception e) { e.printStackTrace(); }
1、api18 以下没有 sCurrentActivityThread 静态变量,但是都有一个 静态方法 currentActivityThread 返回值为 ActivityThread,可以通过返回值 获取
2、未注册的类(OtherActivity)只能直接继承自Activity才能正常跳转,继承AppCompatActivity 显示找不到