2018-08-06
文章目录
Hook过程:
- 寻找 Hook 点,原则是静态变量或者单例对象,尽量 Hook public 的对象和方法。
Hook的选择点:静态变量和单例,因为一旦创建对象,它们不容易变化,非常容易定位。 - 选择合适的代理方式,如果是接口可以用动态代理。
- 偷梁换柱——用代理对象替换原始对象。
注意Android 的 API 版本比较多,方法和类可能不一样,所以要做好 API 的兼容工作。还有不要hook太底层的东西,各个厂商的rom代码不一样
hookView的点击事件
先来个简单点的,View的点击事件。
hookOnLongClick
顺着View的setOnClickListener
方法找到了getListenerInfo
方法,进而找到了ListenerInfo
类,而view的click,longClick,ScrollChange的监听事件都存放在这里面。
private void hookOnLongCLickListener(View view) {
try {
//拿到mListenerInfo ,可以通过getListenerInfo方法
Class<?> clazzView = Class.forName("android.view.View");
Method getListenerInfoMethod = clazzView.getDeclaredMethod("getListenerInfo");
getListenerInfoMethod.setAccessible(true);
Object listenerInfo = getListenerInfoMethod.invoke(view);
//拿到 mOnLongClickListener字段,这里的ListenerInfo是View的内部类,需要用$符号链接。
Class<?> clazz = Class.forName("android.view.View$ListenerInfo");
Field field = clazz.getDeclaredField("mOnLongClickListener");
field.setAccessible(true);
//拿到原来的mOnLongClickListener字段的值
View.OnLongClickListener raw =(View.OnLongClickListener) field.get(listenerInfo);
//替换成我们自己的
field.set(listenerInfo, new HookOnLongClickListener(raw));
} catch (Exception e) {
e.printStackTrace();
}
}
class HookOnLongClickListener implements View.OnLongClickListener{
private View.OnLongClickListener raw;
public HookOnLongClickListener(View.OnLongClickListener raw){
this.raw = raw;
}
@Override
public boolean onLongClick(View v) {
Log.e("HookUtil","HookOnLongClickListener");
Toast.makeText(MainActivity.this,"替换之后",Toast.LENGTH_SHORT).show();
if(raw!=null){
//调用原来的onLongClick,保持原有逻