Hook是什么?
Hook 又叫“钩子”,它可以在事件传送的过程中截获并监控事件的传输,将自身的代码与系统方法进行融入。
这样当这些方法被调用时,也就可以执行我们自己的代码,这也是面向切面编程的思想(AOP)。
示例:Hook 修改 View.OnClickListener 事件
点击事件的方法:
将OnClickListener对象赋予给了ListenerInfo对象的mOnClickListener。
public void setOnClickListener(@Nullable OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
getListenerInfo().mOnClickListener = l;
}
@UnsupportedAppUsage
ListenerInfo getListenerInfo() {
if (mListenerInfo != null) {
return mListenerInfo;
}
mListenerInfo = new ListenerInfo();
return mListenerInfo;
}
ListenerInfo类是View的抽象内部类,声明了View的各种事件listener,而我们要找的mOnClickListener就在其中。
static class ListenerInfo {
@UnsupportedAppUsage
ListenerInfo() {
}
protected OnFocusChangeListener mOnFocusChangeListener;
private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;
protected OnScrollChangeListener mOnScrollChangeListener;
public OnClickListener mOnClickListener;
protected OnLongClickListener mOnLongClickListener;
private OnKeyListener mOnKeyListener;
private OnTouchListener mOnTouchListener;
private OnHoverListener mOnHoverListener;
private OnDragListener mOnDragListener;
实现思路:
1.利用反射获取 ListenerInfo 对象
2.获取原始的 OnClickListener事件方法
3.用 Hook代理类 替换原始的 OnClickListener
代码实现:
首先去创建自己需要hook的类:
class MyClickListener implements View.OnClickListener {
private View.OnClickListener onClickListener;
public MyClickListener(View.OnClickListener onClickListener) {
this.onClickListener = onClickListener;
}
@Override
public void onClick(View v) {
Toast.makeText(v.getContext(), "系统OnClickListener已经被我替换啦", Toast.LENGTH_SHORT).show();
onClickListener.onClick(v);
}
}
去实现偷梁换柱功能:
public class HookHelper {
public static void hookOnClickListener(View view) throws Exception {
Method getListenerInfo = View.class.getDeclaredMethod("getListenerInfo"); //获取getListenerInfo方法
getListenerInfo.setAccessible(true);
Object mListenerInfo = getListenerInfo.invoke(view); //执行完getListenerInfo方法即可返回ListenerInfo对象
//去得到原始OnClickListener
Class<?> aClass = Class.forName("android.view.View$ListenerInfo");
Field mOnClickListener = aClass.getDeclaredField("mOnClickListener");
mOnClickListener.setAccessible(true);
View.OnClickListener originOnClickListener = (View.OnClickListener) mOnClickListener.get(mListenerInfo);//从ListenerInfo中获取原始OnClickListener类对象
View.OnClickListener hookClickListener = new MyClickListener(originOnClickListener);
mOnClickListener.set(mListenerInfo, hookClickListener); //将原始的onClickListener替换成自己的
}
}
最后用一个textView测试结果:
findViewById<TextView>(R.id.textView).apply {
setOnClickListener { }
HookHelper.hookOnClickListener(this)
}
网友评论