Example of hook click event under Android

  • 2021-10-15 11:30:56
  • OfStack

Hook is a kind of idea, that is, replacing the original events with our own events, so that we can do some cutting-in processing. The purpose is not to modify the original code, but also to avoid missing N multi-class processing.

Recently, it is necessary to set up statistical embedding points in the existing app. It seems that the coupling degree is too high if it is buried in the business code. Therefore, it is decided to use hook method to bury the event.

Here, first remember the basic process of hook for click events.

1. First, build a proxy class to implement View. OnClickListener, which is used to do the follow-up processing after clicking.


import android.view.View;

/**
 *  Realize click monitoring 
 */
public class OnClickListenerProxy implements View.OnClickListener{
  private View.OnClickListener mOriginalListener;

  // Pass the original directly into the constructor 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. Carry out hook through the reflection mechanism of java


public static void hookOnClickListener(View view) {
    try {
      //  Get  View  Adj.  ListenerInfo  Object 
      Method getListenerInfo = View.class.getDeclaredMethod("getListenerInfo");
      // Modify getListenerInfo Is accessible (View In getListenerInfo No public)
      getListenerInfo.setAccessible(true);
      Object listenerInfo = getListenerInfo.invoke(view);
      //  Get   Primitive  OnClickListener  Object 
      Class<?> listenerInfoClz = Class.forName("android.view.View$ListenerInfo");
      Field mOnClickListener = listenerInfoClz.getDeclaredField("mOnClickListener");
      mOnClickListener.setAccessible(true);
      View.OnClickListener originOnClickListener = (View.OnClickListener) mOnClickListener.get(listenerInfo);
      //  Use custom  OnClickListener  Replace the original  OnClickListener
      View.OnClickListener hookedOnClickListener = new OnClickListenerProxy(originOnClickListener);
      mOnClickListener.set(listenerInfo, hookedOnClickListener);
    } catch (Exception e) {
      Log.d("LOGCAT","hook clickListener failed!", e);
    }
  }

3. Call the above hookOnClickListener after the event you need hook


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. As a statistical embedding point, it is inevitable to take point parameters

Set parameters in onClick of the original business code


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);
    }
  };

Receive parameters in custom proxy onClick


@Override public void onClick(View v) {
    if (mOriginalListener != null) {
      mOriginalListener.onClick(v);
    }
//    Log.d("LOGCAT","hooked!"+v.getId());
    // Get the parameters passed before 
    Object obj = v.getTag(v.getId());
    Log.d("LOGCAT","hooked!"+v.getId()+"_"+obj.toString());
  }

At this point, you can add follow-up operations at will in hook without changing the original logic code.

Related github address: https://github.com/codeqian/android-class-lib/tree/master/master/src/src/main/java/Hook


Related articles: