Hook 函数

引言

什么是hook函数?

在计算机编程中,hook函数是指在特定的事件发生时被调用的函数,用于在事件发生前或后进行一些特定的操作。

通常,hook函数作为回调函数注册到事件处理器中,当事件发生时,事件处理器会自动调用相应的hook函数。

简单理解就是回调函数的触发。

那么我突然想到 我们在java开发中,自定义接口,做监听接口回调或者kotlin的高阶函数。

Java中回调函数的触发或kotlin 高阶函数的invoke。

这不就是hook函数么。

脑子开始发散了,记得以前做Android的热更新不是用的hook 技术么?hook技术是劫持,通过反射和代理实现‘偷梁换柱’。

react 的hook 函数  创建 useEfffect 对象,做一些逻辑处理。

???????这是不是不太对呀。

下面就开始整理分析一下。

正文

  先说结论:

概念:钩子函数的运作通常依赖于操作系统或框架的内部机制。操作系统为开发者提供了一组API,用于注册和管理钩子函数。当系统事件发生时,操作系统会调用对应的钩子函数,此时开发者可以在钩子函数中编写自己的代码,并对事件进行处理。

理解:钩子函数就是操作系统或者框架提供的一组api,我们理解为回调函数。

我们Android端用的hook技术,就是利用反射和代理这类回调函数的调用,做劫持,改变目标函数的调用(就是替换原来的函数‘偷梁换柱’)。

react 中的 hooks ,例如useState, 首先函数执行这块根源都是到类,类都要extends Component 这个component 是from React 框架的,框架源码类有生命周期出发时的 特定的回调函数,这就是useState、useEffect 等。 使用这个特定的回调函数就会触发对应的生命周期的动作。

Android 端的HOOK

下面通过 Hook View 的 OnClickListener 来说明 Hook 的使用方法。

首先进入 View 的 setOnClickListener 方法,我们看到 OnClickListener 对象被保存在了一个叫做 ListenerInfo 的内部类里,其中 mListenerInfo 是 View 的成员变量。ListeneInfo 里面保存了 View 的各种监听事件,比如 OnClickListener、OnLongClickListener、OnKeyListener 等等。

public void setOnClickListener(@Nullable OnClickListener l) {
    if (!isClickable()) {
        setClickable(true);
    }
    getListenerInfo().mOnClickListener = l;
}

ListenerInfo getListenerInfo() {
    if (mListenerInfo != null) {
        return mListenerInfo;
    }
    mListenerInfo = new ListenerInfo();
    return mListenerInfo;
}

我们的目标是 Hook OnClickListener,所以就要在给 View 设置监听事件后,替换 OnClickListener 对象,注入自定义的操作。

private void hookOnClickListener(View view) {
    try {
        // 得到 View 的 ListenerInfo 对象
        Method getListenerInfo = View.class.getDeclaredMethod("getListenerInfo");
        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 HookedOnClickListener(originOnClickListener);
        mOnClickListener.set(listenerInfo, hookedOnClickListener);
    } catch (Exception e) {
        log.warn("hook clickListener failed!", e);
    }
}

class HookedOnClickListener implements View.OnClickListener {
    private View.OnClickListener origin;

    HookedOnClickListener(View.OnClickListener origin) {
        this.origin = origin;
    }

    @Override
    public void onClick(View v) {
        Toast.makeText(MainActivity.this, "hook click", Toast.LENGTH_SHORT).show();
        log.info("Before click, do what you want to to.");
        if (origin != null) {
            origin.onClick(v);
        }
        log.info("After click, do what you want to to.");
    }
}

到这里,我们成功 Hook 了 OnClickListener,在点击之前和点击之后可以执行某些操作,达到了我们的目的。下面是调用的部分,在给 Button 设置 OnClickListener 后,执行 Hook 操作。点击按钮后,日志的打印结果是:Before click → onClick → After click。

    Button btnSend = (Button) findViewById(R.id.btn_send);
    btnSend.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            log.info("onClick");
        }
    });
    hookOnClickListener(btnSend);

 这里是不是看到源码这块了,后续我会写点framwork的东西,至于什么时候就看缘分了。

android hook 存在两种模式:

native 模式

java 模式

hook  java

主要通过反射和代理实现,应用与sdk开发环境中修改java代码。

hook native

应用与NDK 开发环境和系统开发修改Native 代码。

从实现的维度来看:  应用进程hook 和 全局hook 。

应用程序进程 hook 只是hook 当前应用程序进程。

如果对 zygote 进程(系统级别的进程孵化器)进行hook ,那就可以实现将所有应用程序进程进行修改,这就是全局hook。

hook技术的实现

1、找到hook点。

hook点必须满足以下条件:

  • 需要hook的方法 所属对象必须是静态的。(因为我们通过动态反射来获取对象,我们获取的系统对象,所以不能够new 一个对象 。因此只有静态才能保证和系统对象一致。)

2、将hook方法放到系统之外执行。

总结

hook的原理就是劫持函数的调用,改变目标函数的调用。原理不复杂,但实现有难度。

  • 如何注入代码(选择切入点)
  • 如何注入动态链接库 (让目标调用我们的动态链接库)

tip:  热更新tinker 、Robust 都是用hook原理,找到应用的特定的回调函数处理。 

React 的hooks 

React Hooks 是 React 16.8 引入的一项重要特性,它使函数组件能够拥有类组件的一些特性,例如状态管理和生命周期方法的使用。

通过 Hooks,可以更加简洁和灵活地编写 React 组件。

1. 什么是 React Hooks?

React Hooks 是一种函数式组件的增强机制,它允许你在不编写类组件的情况下使用 React 的特性。主要的 Hooks 包括 useStateuseEffectuseContextuseReduceruseCallbackuseMemouseRef, 和 useImperativeHandle 等。这些 Hooks 提供了访问 React 特性的方式,使得你可以更好地组织和重用你的代码。

2. 使用 React Hooks 的好处
  • 更简洁的组件逻辑:无需编写类组件,可以使用函数组件和 Hooks 来管理状态和生命周期。
  • 提高代码复用性:Hooks 可以帮助你将逻辑提取到可重用的函数中,减少重复代码。
  • 更好的性能优化:使用 useEffectuseCallbackuseMemo 等 Hooks 可以更精确地控制副作用和性能消耗。
3. 注意事项
  • 仅在顶层使用 Hooks:不要在循环、条件或嵌套函数中调用 Hook,确保 Hooks 在每次渲染时都以相同的顺序被调用。
  • 使用 ESLint 插件:React 官方提供了 eslint-plugin-react-hooks 插件来帮助你检查 Hook 的使用是否正确。

Hooks 也使得组件逻辑的测试变得更简单,因为你可以单独测试每个 hook 的逻辑,而不需要包装在一个组件中。

此外,Hooks 还支持自定义,你可以编写自己的 Hooks 来封装复杂的逻辑,然后在多个组件中重用。

结束。

=============================================

参考:

Android hook 原理

你可能感兴趣的:(react学习,开发语言)