反射与动态代理实现全局view点击监听

class ProxyClickListener(
    private val className: String?,
    private val originalListener: View.OnClickListener
) : View.OnClickListener {

    override fun onClick(p0: View?) {
        p0?.apply {
            Log.i(
                className + " " + this.javaClass.simpleName + " id:" + this.context.resources.getResourceEntryName(
                    this.id
                ) + " OnClick()"
            )

            originalListener.onClick(this)
        }
    }
}
object ProxyManager {
    
    @SuppressLint("DiscouragedPrivateApi", "PrivateApi")
    fun hookOnClickListener(className: String?, view: View) {
        try {
            val viewClass = Class.forName("android.view.View")
            // 得到 View 的 ListenerInfo 对象
            val getListenerInfo = viewClass.getDeclaredMethod("getListenerInfo")
            //修改getListenerInfo为可访问(View中的getListenerInfo不是public)
            getListenerInfo.isAccessible = true
            val listenerInfo = getListenerInfo.invoke(view)
            // 得到 原始的 OnClickListener 对象
            val listenerInfoClz = Class.forName("android.view.View\$ListenerInfo")
            val mOnClickListener: Field? = listenerInfoClz.getDeclaredField("mOnClickListener")
            mOnClickListener?.let {
                it.isAccessible = true
                val originOnClickListener = it.get(listenerInfo) as View.OnClickListener?
                // 用自定义的 OnClickListener 替换原始的 OnClickListener
                originOnClickListener?.apply {
                    val hookedOnClickListener = ProxyClickListener(className, this)
                    it.set(listenerInfo, hookedOnClickListener)
                }
            }


        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun hookView(className: String?, rootView: View) {

        if (rootView.visibility == View.VISIBLE) {
            if (rootView.isClickable) {
                hookOnClickListener(className, rootView)
            }
            if (rootView is ViewGroup) {
                val childCount = rootView.childCount
                repeat(childCount) {
                    val childView = rootView.getChildAt(it)
                    hookView(className,childView)
                }
            }
        }

    }
}
abstract class BaseActivity : AppCompatActivity() {

    lateinit var mView: View

    protected abstract val layoutId: Int

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(getLayout())
        initListener()
        //在view setOnClickListener后hook布局
        ProxyManager.hookView(this.javaClass.canonicalName,mView)
    }

    private fun getLayout(): View {
        mView = View.inflate(this, layoutId, null)
        return mView
    }

    open fun initListener() {

    }

}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值