使用Hook技术屏蔽控件的点击事件

17 篇文章 1 订阅

1.其实里面用的就是反射技术;先来看一个简单例子:

public class HookActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = findViewById(R.id.tv1);

        tv.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                System.out.println("点击事件触发!");
                Toast.makeText(HookActivity.this, "点击事件触发!", Toast.LENGTH_LONG).show();
            }
        });
        HookClickHelper.hook(this, tv);
    }

}

2.avtivity简单的调用了一个HookClickHelper的hook方法;

public class HookClickHelper {
    public static void hook(final Context context, View v){
        try {
            Class<?> view = View.class;
            Method getListenerInfo = view.getDeclaredMethod("getListenerInfo");
            getListenerInfo.setAccessible(true);
            //通过方法名调用invoke方法,并传入调用者对象,以及方法所需参数class;就可得到此方法获取的对象
            Object mListenerInfo = getListenerInfo.invoke(v);
            //内部类的调用方式
            Class<?> listenerInfo = Class.forName("android.view.View$ListenerInfo");
            //获取属性
            Field onClickListener = listenerInfo.getDeclaredField("mOnClickListener");
            //传入属性所属的对象,就可得到属性真实的值;
            OnClickListener realOnClickListener = (OnClickListener) onClickListener.get(mListenerInfo);
            //传入属性所属的对象,以及要给此属性设置的值,就可改变此属性原有的值
//            onClickListener.set(mListenerInfo, null);
            onClickListener.set(mListenerInfo, new MyOnClickListener(realOnClickListener, context));
            Log.d("SetOnClickListener", "点击事件被hook到了");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 还真是这样,自定义代理类
    public static class MyOnClickListener implements View.OnClickListener {
        private final Context context;
        View.OnClickListener onClickListener;

        public MyOnClickListener(View.OnClickListener onClickListener, Context context){
            this.onClickListener = onClickListener;
            this.context = context;
        }

        @Override
        public void onClick(View v) {
            Log.d("SetOnClickListener", "点击事件被hook到了");
            Toast.makeText(context,"哈哈哈,事件被我吃了!",Toast.LENGTH_SHORT).show();
//            if (onClickListener != null) {
//                onClickListener.onClick(v);
//            }
        }
    }
}

3.其实上面代码中的每一步都写的很清楚了;可以发现就是使用反射来替换里面的对象;

4.分析过程:

首先查看点击事件源码:

这里可以发现,把我们new的onclicklisterner对象赋值给了getListenerInfo().mOnClickListener;

我们来看看getListenerInfo得到了什么:

看到ListenerInfo是一个对象,点进去发现是View类中的一个内部类(所以上面代码中使用发射时填入了内部类的类名);而mOnClickListener就是此内部类的一个属性;所以上面代码中,我们用反射获取到了这个属性,并且得到了刚刚我们传进去的那个真实的clicklistener对象;

当我们拿到了这个真实的clicklistener对象后,就可以为所欲为了;

接下来给这个属性重新赋值;我们可以传个null;直接把点击事件屏蔽掉;也可以自己实现一个点击事件,把真实的点击事件传进去;但在执行点击事件的前后都可以加入我们自己的功能。这样就达到了屏蔽点击事件或修改点击事件或直接给我我们想做的事情。

5.参考:https://www.jianshu.com/p/74c12164ffca;非常感谢!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值