React Native inspector 技术详解

39 阅读5分钟

背景

Mobile 日常维护遇到大部分页面组件无法快速定位到准确位置,经常需要花 1~2 分钟识别页面关键字,全局搜索定位组件,这样的方式实在是太原始了,急需一个 click-to-component 的工具提升效率

调研

研发现市面上并没有可参考的资料,只有闭源的 Radon-ide 提供了 click-to-component 功能

Radon-ide 的实现方案

  1. 手动替换 Dev 下的 react 编译器版本,让其回到留有 Fiber debug source 的版本,其管理的范围在 react 18 之后的版本

  1. 实现方法:

    1. 创建自定义的 react babel transform,将可用版本的 babel_transform.js 拷贝到本地

    2. 将自定义的 react babel transform 在开发模式下转为用指定版本的 babel_transform.js

    3. 优点:

      1. 可直接使用现成的 Fiber debug source 去获得组件跳转所需的数据
    4. 缺点:

      1. 开发与生产两个版本的 transform 可能会引发未知问题

      2. Transform 版本与 react-native 版本不一致埋下隐患

系统设计

mermaid-1102026 12254 PM.png

  • 数据端

    • 自定义 Inspector babel 插件

      • 核心能力:遍历 JSXElement 节点,自动注入源码定位属性

      • 关键逻辑:

        • 跳过 Fragment 元素(不支持自定义属性)
        • 避免重复注入 __inspectorSource 属性
        • 提取元素名、文件路径(保留 src/ 路径)、行号、列号
        • 组装属性值为包含 file/line/column/element 的对象
  • 应用端

    • 封装 Inspector 核心组件

      • InspectorWrapper 组件(核心容器)

        • 仅在 DEV 环境生效,生产环境直接返回子组件
        • 添加「Toggle Inspector」开发菜单,控制调试开关
        • 包裹业务组件,绑定手势响应器(PanResponder)
        • 渲染高亮层(InspectorHighlight)和弹窗层(InspectorPopover)
      • useInspector 核心 Hook

        • 手势处理:监听点击/触摸事件,定位点击位置的组件

        • 组件信息获取:

          • 调用 RN 底层 API 获取组件帧信息、props、style
          • 提取 __inspectorSource 源码定位信息
          • 收集最多 5 层祖先组件的源码信息
        • 编辑器跳转:

          • 判断组件是否在屏蔽列表(blockComponents)
          • 向服务端发送 __open-in-editor 请求
          • 屏蔽组件则尝试跳转祖先组件源码
        • 辅助函数:

          • getSourceFromNodeClosestFiber:从 Fiber 节点提取源码信息
          • isBlockedComponent:判断组件是否需要屏蔽
      • 辅助组件/工具

        • InspectorHighlight:渲染组件选中高亮框
        • InspectorPopover:展示组件尺寸、props、style、源码信息
        • stringifyPropsForDisplay:格式化 props/style 用于展示
  • 服务端

    • Metro 中间件服务

      • 开启 Inspector 中间件,监听 /__open-in-editor 请求

      • 接收应用端传递的 source 数据(file:line:column 格式)

      • 执行指定 Editor 指令(可支持本地配置不同的 Edit ),跳转到对应代码位置

踩坑问题

  1. 应用端编写过程中,无法准确获取鼠标点击时挂载在组件上的数据

    1. 跑在模拟器上的代码并不是 React 代码,实际是 RN 转换过后的 Native 代码
    2. RN 提供的 API 无法获取点击元素的组件信息

解决方法:

  1. 通过 RN PanResponder 绑定点击获取元素的坐标
  2. 通过 RN 提供的 Inspector 方法 getInspectorDataForViewAtPoint 获取到 Node 节点
  3. 通过获取到该 Node 节点最近的 Fiber 实例来获取到挂载的 Props 数据
  1. 点击后跳转的可能是 node_modules 或者 MoeText 等基础组件

解决办法:

  1. 注入数据时,将父组件向上获取 5 层并一同注入

  2. 点击组件后处理,如果被点击识别到的是“干扰”组件则替换为使用父组件中寻找首个最近的“有效”组件进行跳转,大大提高了跳转到期望组件的概率

核心难点总结

  1. 缺少可参考实现,方案需要从零探索验证

业界几乎没有“可直接套用”的完整链路(源码注入 → 端侧命中 → 信息展示 → 打开编辑器),只能通过阅读零散资料与不断试错逐步拼出可行方案

心得:遇到无从下手的大问题,先拆成若干可验证的小问题;每一步做最小闭环验证,最终自然收敛为完整方案

  1. 端侧如何“命中”被点击的组件,并获取与可视化有效信息

难点不只是拿到点击坐标,而是把坐标映射到具体组件区域,并进一步提取到该组件携带的源码定位、props/style、尺寸位置等信息,最后以高亮框与信息面板形式呈现

心得:先定义目标体验(点哪、亮哪、显示什么),再围绕体验拆解链路,做一组递进 Demo 验证关键环节,逐步组合成稳定方案

  1. 精准跳转到“目标业务组件”,避免落到无效组件

实际点击往往会命中大量包装层/容器层/框架组件(例如 View、Text、Touchable 等),即便拿到 Fiber 也可能定位到“不可读、不可改、无意义”的源码位置

需要设计屏蔽策略与回溯策略(如 blockComponents + 祖先向上查找),确保最终跳转落在最有价值的业务组件上

  1. 服务端承接跳转请求,并驱动本地编辑器准确定位

应用端发起打开请求后,服务端需要正确解析 source(file/line/column),兼容不同编辑器的打开方式与参数差异,并保证在本地环境可用、稳定、可配置