Hook是一種思想,也就是將原來的事件,替換到我們自己的事件,方便我們做一些切入處理。目的是不修改原來的代碼,同時也避免遺漏的N多類里面處理。
最近需要在現有的app中設置統計埋點。去業務代碼里埋的話似乎耦合度太高。所以決定使用hook的方法對事件進行埋點處理。
這里先記一下對點擊事件hook的基本流程。
1.先建一個代理類實現View.OnClickListener,用來做點擊后的后續處理。
import android.view.View;/** * 實現點擊監聽 */public class OnClickListenerProxy implements View.OnClickListener{ private View.OnClickListener mOriginalListener; //直接在構造函數中傳進來原來的OnClickListener public OnClickListenerProxy(View.OnClickListener originalListener) { mOriginalListener = originalListener; } @Override public void onClick(View v) { if (mOriginalListener != null) { mOriginalListener.onClick(v); } Log.d("LOGCAT","hooked!"); }}2.通過java的反射機制進行hook
public static void hookOnClickListener(View view) { try { // 得到 View 的 ListenerInfo 對象 Method getListenerInfo = View.class.getDeclaredMethod("getListenerInfo"); //修改getListenerInfo為可訪問(View中的getListenerInfo不是public) getListenerInfo.setAccessible(true); Object listenerInfo = getListenerInfo.invoke(view); // 得到 原始的 OnClickListener 對象 Class<?> listenerInfoClz = Class.forName("android.view.View$ListenerInfo"); Field mOnClickListener = listenerInfoClz.getDeclaredField("mOnClickListener"); mOnClickListener.setAccessible(true); View.OnClickListener originOnClickListener = (View.OnClickListener) mOnClickListener.get(listenerInfo); // 用自定義的 OnClickListener 替換原始的 OnClickListener View.OnClickListener hookedOnClickListener = new OnClickListenerProxy(originOnClickListener); mOnClickListener.set(listenerInfo, hookedOnClickListener); } catch (Exception e) { Log.d("LOGCAT","hook clickListener failed!", e); } }3.在你需要hook的事件后調用上面這個hookOnClickListener
Button btnSend = (Button) findViewById(R.id.btn_send); btnSend.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { log.info("onClick"); } }); HookManager.hookOnClickListener(btnSend);4.作為統計埋點,不免需要帶點參數
在原業務代碼的onClick里設置參數
private View.OnClickListener clickBtn = new Button.OnClickListener(){ @Override public void onClick(View v) { Map map = new HashMap(); map.put("name",v.getClass().getName()); v.setTag(v.getId(),map); HookManager.hookOnClickListener(v); } };在自定義的代理onClick里接收參數
@Override public void onClick(View v) { if (mOriginalListener != null) { mOriginalListener.onClick(v); }// Log.d("LOGCAT","hooked!"+v.getId()); //拿到之前傳遞的參數 Object obj = v.getTag(v.getId()); Log.d("LOGCAT","hooked!"+v.getId()+"_"+obj.toString()); }至此就可以在hook里隨意加入后續操作而不用改動原來的邏輯代碼了。
相關github地址: https://github.com/codeqian/android-class-lib/tree/master/utilDemo/app/src/main/java/Hook
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。
新聞熱點
疑難解答