要實現免註冊跳轉需要解決的問題:
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);
// 替換掉原有的IActivityManager
mInstace.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;
} @Override
public 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 顯示找不到