详细讲解下Hook技术,以Hook点击事件来示范

Hook技术:  Hook就是有一段程序逻辑一直走下去,我们可以捕获到其中间的一些逻辑,加于处理然后再让他接着执行下去;

比如Android里面的setOnclickListener这个方法. 正常我们是这样操作的

        TextView textView = findViewById(R.id.act_invoke_tv);
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(InvokeOnClickActivity.this, ((TextView)v).getText(), Toast.LENGTH_SHORT).show();
            }
        });

怎么在不改变这段代码的情况下,把里面的的Toast内容给替换掉

分析思路: 1肯定要用到动态代码,动态代码用到的是Proxy这个类

        Object proxyInstance = Proxy.newProxyInstance(getClassLoader(), new Class[]{View.OnClickListener.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Toast.makeText(InvokeOnClickActivity.this, "已经hokd到方法了", Toast.LENGTH_SHORT).show();
                return method.invoke(mOnClickListener, null);
            }
        });

等我们通过反射获取到textView设置的mClickListener的时候就将其替换

首先我们在setOnclickListener的时候传的是一个View.OnClickListener过去

   public void setOnClickListener(@Nullable OnClickListener l) {
        if (!isClickable()) {
            setClickable(true);
        }
        getListenerInfo().mOnClickListener = l;
    }

这方法里面将我们传入的OnclickListener附值给了getListenerInfo()获取的类的一个成员变量,而getListenerInfo()这个方法获取的是ListenerInfo这个类,也就是说,在这里操作的是将我们设置的OnClickListener传给了ListenerInfo,是他里面的一个成员变量,

所以我们第一步就是获取到View里面的getListenerInfo这个方法

Class.forName这个方法可以获取到一个Class类,然后通过这个Class类获取到getListenerInfo这个方法,然后再执行这个方法代码如下

Class<?> viewClass = Class.forName("android.view.View");
Method getListenerInfoMethod = viewClass.getDeclaredMethod("getListenerInfo");
getListenerInfo.setAccessible(true);
Object listenerInfo = getListenerInfoMethod.invoke(textView)

listenerInfo则就是通过VIew里的getListenerInfo获取到的对象  因为OnClickListener附给了ListenerInfo里的一个成员变量,这里我们继续通过反射获取到它的成员变量mOnClickListener

Object listenerInfoClass = Class.forName(android.view.View$ListenerInfo);
//获取到名字为mOnClickListener的成员变量
Field onClickListenerField = listenerInfoClass.getDeclaredField("mOnClickListener");
//获取到原来设置的OnClickListener,其实可以不用这个,只是为了不影响正常逻辑,因为我们代理完了要重新
//执行原来的方法
Object mOnClickListener = onClickListenerField.get(listenerInfo);

最后一步就是替换操作了

onClickListenerField.set(listenerInfo,proxyInstance);这样就远的成自己的了,当我们点击Teview的点击事件的时候就会先走到我们代码的proxyInstance里面的invoke方法,

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值