news 2026/9/1 18:26:49

深度解析QtScrcpy:C++与Qt实现Android实时投屏与远程控制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深度解析QtScrcpy:C++与Qt实现Android实时投屏与远程控制

简介:这是一套面向C++/Qt开发者与Android投屏工具爱好者的开源实战项目源码,聚焦于无需Root权限的跨平台实时投屏解决方案,适用于移动开发调试、远程教学演示及企业级设备管控等场景。资源共126个文件,含15个核心C++源文件(如videoform.cpp、config.cpp)、16个头文件、9个Shell脚本(含build_for_win.bat、publish_for_win.bat等构建与发布脚本)、6个JSON/YAML配置文件、30张PNG与4张JPG界面资源图,以及TypeScript、Python、CSS等多语言协同模块,完整覆盖UI层、控制逻辑、设备通信与构建部署全流程;压缩包大小为36.03MB。已有416人学习下载。读者可直接复用其USB/TCP双模连接架构、Qt多线程视频渲染方案、ADB指令封装逻辑及跨平台构建脚本,快速掌握高性能投屏软件的工程组织方式与多语言协作实践。

1. 项目概述:这到底是什么,能拿来干什么

先给结论:QtScrcpy 是一个用 C++ 和 Qt 框架实现的 Android 实时投屏开源项目,底层数据链路沿用 scrcpy 的思路——通过 adb 协议与 Android 设备通信,把设备的屏幕内容以 H.264 编码流的形式送出来,再由 PC 端解码渲染。换句话说,它不是简单的“截屏工具”,而是一套完整的远程控制协议实现。

我第一次接触这个项目时,想到的并不是“投个屏有什么难的”,而是“在投屏之外,它能不能变成一套可扩展的 Android 设备控制基座”。如果你在测试部门待过,一定经历过那种场景:桌上十几台 Android 手机,每台都要装包、点按钮、看日志,人眼和手根本忙不过来。QtScrcpy 这类工具的价值,就是让你在 PC 上完成所有这些操作,还能录屏、反向传输文件、执行 shell 命令。它适合的人也很明确:Android 开发、测试工程师、自动化脚本编写者,以及想研究“C++ 怎么跟 Android 系统通信”底层原理的嵌入式或客户端开发者。

有一点需要提前说明:QtScrcpy 跟原版 scrcpy 有两个明显差异。第一,原版基于 SDL2,QtScrcpy 整个 UI 用 Qt Widgets 重写,看惯了原生 scrcpy 命令行的用户,会在这里得到一个完整的图形界面;第二,QtScrcpy 的代码模块更贴近“桌面应用工程化”,这意味着读它的源码,你能学到的不只是投屏,还有 Qt 线程模型、跨平台编译、协议解析这一类通用技能。

2. 整体设计与核心架构拆解

2.1 数据链路:Android 端把画面送出来的完整过程

很多人觉得投屏是“截屏 + 图片传输”,这是最大的误解。实时性要求下,逐帧传 PNG 或 JPEG 根本不可行。QtScrcpy 采用的是 video stream 方案:Android 端通过screenrecord命令配合SurfaceFlinger的虚拟显示节点,把屏幕内容交给硬件编码器,输出 H.264 格式的二进制流;PC 端接收这个流,再用 ffmpeg 或系统解码器还原成可显示的图像帧。

具体到 adb 侧,这条链路大致是:

  1. PC 端通过 adb push 把 server 文件(一个 jar 包)传到 Android 的/data/local/tmp
  2. adb shell 执行CLASSPATH=/data/local/tmp/server.jar app_process / com.genymobile.scrcpy.Server启动 Java 服务。
  3. Java 服务向 Android 的 SurfaceControl 申请一个虚拟 Display,把屏幕内容投到编码器。
  4. 编码器输出 H.264 流,经过本地 socket 回传。
  5. PC 端 client 读取这个 socket,解码后渲染到窗口。

这里有个值得新学者注意的点:adb 提供了adb forward转发机制,可以让 PC 端和 Android 端通过本地端口通信。QtScrcpy 启动时,会在 PC 端监听一个随机端口,同时把这个端口 forward 到 Android 设备的 tcp 端口,两条通道各自独立。控制指令(触摸、按键)和视频流走的都是这个 socket,但通过字节流前缀区分消息类型。

2.2 Client 端怎么“接住”并渲染

QtScrcpy 的客户端不是单纯地开一个线程去recv()数据,它拆了三层:

  • 网络层:负责连接与字节收发,用 Qt 的QTcpSocket,支持读写缓冲区管理。
  • 解码层:把 H.264 裸流交给QVideoStreamReader做 AVCodec 解码,产出QAbstractVideoBufferQVideoFrame
  • 渲染层:通过QVideoWidget显示,同时处理窗口缩放、封面模式、黑边去除。

这三层分离的直接好处是:你可以替换掉任意一层。比如解码层直接硬件解码,渲染层改成 OpenGL 纹理,网络层支持 UDP 局域网直连,扩展性极强。

音频部分,QtScrcpy 新版也做了接收处理。Android 端把 PCM 音频封装成数据块,通过控制 socket 的另一个子通道发送,PC 端用QAudioOutput播放。因为 C++ 侧跟 Java 侧的数据格式约定必须完全一致,这里对字节序、采样位深、声道数这些细节要求非常高,是移植时最容易踩坑的地方之一。

2.3 为什么用 C++ 和 Qt,而不是 Electron 或 Java

这个问题我聊过很多次,QtScrcpy 选择 C++/Qt 并非偶然,而是由性能要求和开发效率共同决定的。

  • 视频解码后是一个相对高频的帧回调流程,Electron 的 Node 层和浏览器渲染层之间有额外拷贝,延迟会高 20~50ms 甚至更多。C++ 处理视频帧可以直接用内存指针引用,避免了多次 memcpy。
  • Qt 的QThread、信号槽在跨线程传递帧数据时非常方便,不必自己写复杂锁。
  • Qt 本身就是跨平台的,Windows/macOS/Linux 下行为一致,这对投屏这种强依赖设备生态的工具几乎是必需属性。
  • 底层解码库(ffmpeg)本身就是 C 库,C++ 直接调用,节省了跨语言绑定的成本。

如果用 Electron,开发 GUI 确实快,但你会发现解码帧要先把 C++ 侧的数据转成 JS 侧能访问的 ArrayBuffer,再传给 canvas,每一步都在复制内存。你用 Qt 直接操作QVideoFramebits()指针,性能差距非常直观。

3. 环境准备、源码结构与编译流程

3.1 工具链选型:从零搭一套可编译环境

先说你最需要准备的东西:

  • 操作系统:Windows 10/11 或 Ubuntu 20.04+
  • 编译器:MSVC 2019/2022(Windows)或 GCC 9+(Linux)
  • Qt 版本:5.15 或更高(6.x 理论可行,但部分控件 API 需要调整)
  • Android SDK 与 Platform Tools:adb 是核心依赖
  • 构建工具:CMake 3.16+,Ninja 或 make

我自己在 Windows 上的推荐组合是 Visual Studio 2022 + Qt 5.15.2(msvc2019_64)+ CMake。有一个容易忽略的坑:Qt 的 msvc 和 MinGW 版本不能混用,如果你下载的是 MinGW 版 Qt,编译器必须用 MinGW 的 g++,否则链接阶段会报一堆“无法解析的外部符号”。

3.2 源码目录与模块划分

QtScrcpy 的源码组织方式非常清晰,值得在头脑里建立一个地图:

  • main目录:客户端主程序,Qt Widgets 界面入口。
  • core目录:核心网络、连接池、控制逻辑。
  • dialog目录:设置对话框。
  • device目录:设备管理与 adb 交互。
  • decoder目录:视频解码封装。
  • server目录:Android 端 Java 服务源码,最终打包成 jar。

读代码时,我的建议顺序是:先看core里的connectionserverServer.java,把两端的通信协议理解清楚,再看decoderdevice的连接初始化流程。一开始就扎进窗口布局,容易迷失。

3.3 编译流程:两条路径,选适合自己的

路径一:直接用 Qt Creator 构建

用 Qt Creator 打开CMakeLists.txt,选择 kit 为Desktop Qt 5.15.2 MSVC2019 64bit,直接构建就行。这种方式最直观,适合想快速跑起来的读者。

路径二:命令行 + CMake
mkdir build && cd build cmake .. -DCMAKE_PREFIX_PATH=C:/Qt/5.15.2/msvc2019_64 cmake --build . --config Release

这里CMAKE_PREFIX_PATH必须指向 Qt 的编译器对应目录。如果你装了多个 Qt 版本,这个路径写错会直接导致找不到 Qt6Core.dll 之类的错误。

编译完成后,还需要单独处理 server 端。因为 Android 端跑的是 Java,需要 JDK 环境和 Android SDK 提供的dxd8工具来把 class 文件打包进 jar。QtScrcpy 的CMakeLists.txt里已经写好了相关步骤,只要你的环境变量里配了ANDROID_HOMEJAVA_HOME,构建过程会自动生成server.jar

4. 核心功能实现细节与实操要点

4.1 adb 设备接入的底层实现

设备接入不是简单地调一次adb devices就结束。QtScrcpy 里维护了一个设备列表,实时监听设备的插拔事件。这里有一个比较隐蔽的技术点:adb 的 server 本身就是一个常驻进程,PC 端工具启动时会尝试启动它,然后通过 5037 端口跟 adb server 通信。

如果你的设备没有开启 USB 调试,投屏请求就会返回unauthorized状态。QtScrcpy 的处理是弹出提示,并将设备标记为不可用。实操中我建议把adb keys目录下的公钥复制到所有测试机上,这样可以避免每台新设备都去点“允许调试”弹窗。

有一个高频操作是adb forward命令。QtScrcpy 在一次连接中可以同时 forward 多个端口,每个都对应不同的服务类型。查看端口转发状态可以用:

adb forward --list

如果发现端口被占用,可以先:

adb forward --remove-all

再重新连接。这个“先清空再分配”的思路,在多设备同时接入时能避免很多端口冲突的诡异问题。

4.2 视频解码与渲染:延迟控制的关键

很多人问“为什么我的投屏延迟总是 200ms 以上”,其实问题往往不在网络,而在解码线程和渲染线程的帧滞留策略。QtScrcpy 的解码线程会尽量只保留最新帧,丢弃积压的旧帧。但如果你把它改成“所有帧都渲染”,立刻就能感受到严重卡顿。

渲染时容易遇到的一个坑是纹理格式不匹配。Android 端输出的往往是H.264裸流,解码后的像素格式可能是YUV420P,而 Qt 的QVideoWidget默认期望的是RGB32ARGB32。这里需要做一次颜色空间转换。QtScrcpy 用了libyuv做转换,你也可以用 ffmpeg 的sws_scale。相比逐像素手动转换,这两个库的速度差了一个数量级。

帧率控制上,QtScrcpy 默认会从流信息里读帧率。如果你的设备原生支持 60fps,而 PC 端因为屏幕刷新率是 144Hz,那么解码器会多出不少空闲间隔。这个没有问题,真正要关注的是maxFps的设置。降低帧率可以节省大量 USB 带宽和 CPU 占用,尤其是在无线投屏时非常实用。

4.3 反向控制:触摸、按键和文本输入怎么实现

投屏的意义不只在于“看”,更在于“操作”。QtScrcpy 把鼠标事件、键盘事件、剪贴板事件都封装成控制消息,通过 socket 发给 Android 端的 server,再由 server 调用 InputManager 注入事件。

触摸注入的核心是坐标系转换。PC 窗口的坐标是相对窗口左上角的,但 Android 设备的坐标是相对屏幕左上角的像素值,两者需要根据实际窗口大小和设备分辨率做缩放。QtScrcpy 里有一个MotionEvent类专门处理这个映射。这里有一个细节:如果窗口保持 16:9 比例,但设备是 18:9,屏幕两侧会出现黑边。QtScrcpy 提供“裁剪”模式和“填充”模式,二选一都会影响坐标换算,代码里是按 width/height 比来动态修正的,并没有一刀切。

文字输入这块,QtScrcpy 用的是 Android 的adb shell input text方式,但遇到特殊字符时非常容易踩坑。空格需要转义成%s,中文需要用ADBKeyboard.apk这类 IME 支持。如果你做的是自动化测试框架,建议仔细看下这段逻辑,否则脚本里输入带@#的密码时会莫名失败。

4.4 Server 端注入:Java 与 C++ 的配合方式

很多人读 QtScrcpy 源码时最看不懂的就是 server 端——它是一段写好的 Java 代码,但运行方式不是常规的Class.forNameActivity,而是通过app_process启动。app_process是 Android 系统启动 zygote 时使用的进程入口,可以直接在非 Activity 环境下运行 Java 类,这让投屏服务具备了“无界面后台运行”的能力。

Server 启动后的工作流程可以这样理解:

  1. 解析命令行参数,拿到视频位宽、码率、帧率、连接端口。
  2. 创建一个虚拟 Display,与设备的真实屏幕同步刷新。
  3. 启动MediaCodec编码器,把虚拟 Display 的内容编码成 H.264。
  4. 与 PC 端的 socket 建立连接,开始双向读写。

这里有个常见误区:MediaCodec编码出来的流是带 SPS/PPS 的 AVCC 格式,而 PC 端的 ffmpeg 解码时如果是 Annex-B 格式的配置,两者不能直接互通。QtScrcpy 里对csd-0csd-1的处理就是专门解决这个问题的。如果你自己写了一个新的投屏协议,但画面一直黑屏、只有音频,先查 SPS/PPS 的封装格式,大概率就是这个问题。

5. 实操记录:从源码编译到首次投屏

5.1 编译所踩的坑与应对

我第一次在 Windows 上编译 QtScrcpy,整体流程还算顺利,但有几个环节很有代表性,值得写下来。

  • CMake找不到 Qt:这是最常见的失败原因。经验是先在 CMake 的CMAKE_PREFIX_PATH里填路径时,不要指到C:/Qt/5.15.2这种总目录,而要指到具体编译器架构的目录,比如msvc2019_64。因为 Qt 提供的.cmake文件都在该子目录下。
  • 链接时缺少winmm.lib:这是 Qt 5.15 在 Windows 上经常出现的情况,通常跟音频模块有关。解决方法是加一条target_link_libraries(... winmm),或者在 Qt Creator 的 pro 文件里加LIBS += -lwinmm
  • 缺少platforms/qwindows.dll:编译过了但运行报错,本质是 Qt 插件路径没配置。将编译完的 dll 放在正确目录下通常能解决,如果不行就在代码里强制QApplication::addLibraryPath()

5.2 首次连接与高清画质调试

编译成功后,我直接插上一台 Android 测试机,打开 QtScrcpy,设备列表里立刻显示序列号。点击“开始投屏”,大约 1~2 秒后窗口出来画面,默认是 720p 的标准模式。

如果你想投 2K 或 4K,必须在点击“开始投屏”前设置分辨率。注意一点:分辨率不是越低越流畅,也不是越高越清晰。它跟设备实际屏幕大小、PC 端窗口大小、USB 带宽三者都有关系。实测下来,电脑窗口只有 800x600 时,投 4K 纯属浪费带宽;反之如果用 4K 大屏全屏显示,只投 720p 会明显模糊。

码率这块,我用-b 8M起步,无线场景下降到4M仍然能保持不错的清晰度。如果你要投屏录屏做教程,建议直接开-b 20M,细节保留程度会好很多,但延迟也会略微上升。

5.3 无线模式:让手机离开 USB 线

QtScrcpy 是支持无线投屏的,原理是先通过 USB 建立连接,然后执行:

adb tcpip 5555 adb connect <设备IP>:5555

一旦连接成功,拔掉 USB 线,重新在 QtScrcpy 里连接设备就行。我实测的延迟大约比 USB 多 30~60ms,这取决于你的路由器。如果是 5G Wi-Fi 局域网,基本感受不到差别;如果是 2.4G Wi-Fi 又离得远,延迟会明显增加,画面也会产生马赛克。

网络环境差时,最有效的优化是把投屏分辨率降到 1080p、码率降到 4M 以下。这样画质会有一定损失,但操作响应速度比什么都重要。

6. 常见问题与排查技巧实录

6.1 设备连接与权限类

Q:adb devices 能看到设备,但 QtScrcpy 一直提示未授权。

原因通常是 PC 端的 RSA 指纹跟设备端不匹配。手机上撤销 USB 调试授权,重新插拔,并在设备上点“允许”。如果有多台设备,建议把~/.android/adbkey.pub内容追加到每台设备的/data/misc/adb/adb_keys,但需要 root 权限。没有 root 的测试机,最好还是手动在每台设备上授权一次。

Q:启动时提示 adb server 版本过旧。

Android SDK 的 platform-tools 更新频率很高,老版本 adb 无法解析新设备的协议。直接下载最新 platform-tools 并替换系统 PATH 里的 adb 文件即可。注意 64 位系统千万不要用 32 位 adb,否则会提示 Exec format error。

6.2 画面与性能类

Q:投屏成功,但画面是黑屏,只有声音或完全不显示。

先查 H.264 流是否正常输出。如果设备接口正常、编码器正常,黑屏大概率是解码或渲染环节的问题。可以试着用 ffprobe 看一下流信息:

adb shell screenrecord --time-limit 5 /sdcard/test.mp4 adb pull /sdcard/test.mp4

如果录出的 mp4 在本地播放正常,说明编码侧没问题,问题出在 PC 端解码器。推荐换用硬件解码,或者更新显卡驱动。

Q:投屏延迟很高,触摸明显跟不上。

先把分辨率降下来,再把码率降下来。如果仍然卡顿,检查是否有后台进程占用 CPU。QtScrcpy 的解码在最坏情况下是单线程满负荷的,音频解码又会跟视频解码抢 CPU 时间,可以在设置里关闭声音,看延迟是否明显降低。

Q:窗口缩放后画面发虚。

Qt 的QVideoWidget默认按设备像素比渲染,窗口缩小到一定程度后,像素堆积明显。可以在渲染前把目标窗口大小设置为固定的 2x 或 3x 缩放倍率,避免花式差值造成画面发虚。更高清的体验,是用 OpenGL 纹理渲染,再做双线性过滤。

6.3 音频与录屏类

Q:画面正常,但没有声音。

先确认工具已开启音频转发。其次检查 PC 端默认播放设备是否为“扬声器/耳机”。如果你用的是虚拟声卡或蓝牙音箱,Android 的声音数据可能被系统吞掉。另一个容易忽略的因素是 QtScrcpy 不支持所有音频格式,部分设备的采样率如果比较特殊,可以在设置里手动指定 44100 或 48000。

Q:录屏文件打开后没有声音。

录屏文件通常将视频和音频混流成 mp4。如果文件能打开但声音缺失,说明混流时的音频解析有问题。建议先检查录屏期间 QtScrcpy 的日志里有没有“audio decode error”。这类问题,多半是 PCM 采样格式不匹配,需要查看音频子通道的参数是否与 PC 端期望一致。

7. 从“跑通”到“好用”的扩展方向

如果你只是把 QtScrcpy 跑起来,那收获有限。真正有价值的是把它当成一个可二次开发的投屏基座。我根据自己的实践,列几个有代表性的扩展方向,希望对你的项目设计有启发。

7.1 多设备并发管理:从“单投屏”到“设备墙”

QtScrcpy 天然支持多开,只要每个实例连接不同设备。你可以做一个简单的主控程序,一次性拉起 N 个子进程,每个子进程对应一台设备。这样测试一个 App 在不同机型上的兼容性时,可以同时观察所有屏幕的操作反馈,效率直接翻倍。

实现时的一个关键点是:每个实例的 adb forward 端口不能冲突。启动前先检查端口占用,或者让每个实例动态请求一个空闲端口。否则第二台设备启动时会报 bind 失败。

7.2 自定义按键协议:接入自动化框架

原版 QtScrcpy 的按键事件是写死的。你可以扩展控制消息协议,比如在鼠标事件结构体里追加一个“宏指令”字段,告诉 Android 端执行一次滑动、长按或多点触控。这样测试脚本就不需要再走一遍 UI 自动化框架,直接把精确的触摸坐标发过去就行。

这种改法要注意消息头的对齐。C++ 端使用#pragma pack(push, 1)来紧凑定义结构体,Java 端同样按字节读取。否则两端对结构体大小的理解不一致,会读到错误的数据。

7.3 高清投屏优化与低延迟改造

如果你对延迟有极致要求,可以跳过 Qt 的QVideoWidget默认绘制路径,改用QOpenGLWidget直接接收QVideoFrame,通过 OpenGL 纹理上传并渲染。这样绕开了 Qt 内部的一次绘图拷贝,实测可以降低约 5~10ms 延迟。

同时,在 Android 端把编码器的预期帧率设置为 60fps,并把i-frame-interval调小,这样远程操作时画面不会长时间卡在旧帧上。另一个技巧是把编码器bitrate-mode设为 CQ(Constant Quality),码率会自动在复杂画面和静止画面间调整,比恒定码率更节约带宽。

7.4 跨平台 UI 的细节打磨

QtScrcpy 在 Linux 和 macOS 上同样可以编译运行,但有几个平台差异需要注意:

  • macOS 上需要开启APP_SANDBOX权限描述,否则无法使用 local network。
  • Linux 上如果使用 Wayland,部分鼠标事件坐标会异常,需要改用 X11。
  • 字体渲染在不同平台差异明显,如果 UI 上要显示设备型号和状态信息,建议用系统默认字体替代自定义字体。

这些坑都不会在 Windows 上遇到,真正做跨平台发布时才能体会到“写一次代码,到处调试”的含义。

写在最后的一点心得

研究 QtScrcpy 源码这件事,让我真正理解了一个现代桌面应用应该如何设计:网络层、解码层、渲染层、控制层,每一层都独立、稳定、可替换,而不是所有代码混在一个类里。如果你最近在看 C++ 项目,我的建议是把 QtScrcpy 的core模块拆出来,一行行读通,再对照server里的 Java 代码理解后端服务。两端的协议定义基本就是一套字节流封装的约定,吃透之后,你自己写一个局域网无线投屏工具也只是时间问题。

另外想提醒一点:Android 手机开启 USB 调试会存在一定的安全风险,尽量只在可信的设备和测试环境中使用。投屏软件的边界是工具本身,怎么用它,完全取决于你的目标场景。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/1 18:25:31

海尔小红花472L十字门母婴冰箱:超薄嵌入与精准控温全解析

最近装修群里讨论最多的问题&#xff0c;不是瓷砖颜色&#xff0c;也不是全屋定制板材&#xff0c;而是冰箱到底怎么选。很多人在定制橱柜时预留了标准的 600mm 深度&#xff0c;结果看中的冰箱厚度普遍在 650mm 以上&#xff0c;柜子做好了&#xff0c;冰箱却凸出来一大截&…

作者头像 李华
网站建设 2026/9/1 18:17:30

配置文件修改全流程:从定位备份到验证回滚

配置文件改来改去&#xff0c;最怕的不是改错某一个参数&#xff0c;而是不知道文件在哪里、改完没生效、出了问题找不到回滚版本。很多人学了一大堆具体软件和框架的配置写法&#xff0c;换一个项目、换一台机器还是卡住&#xff0c;原因在于配置文件不只是一个“改法”问题&a…

作者头像 李华
网站建设 2026/9/1 18:15:02

网约车视觉识别:从特征拆解到工程落地

一眼认出“这台车是网约车”&#xff0c;几乎是每个都市人的本能。一辆白色紧凑型轿车从中间车道减速靠边&#xff0c;双闪打开&#xff0c;车身贴着一张半透明的平台二维码&#xff0c;即使没有顶灯&#xff0c;你也知道它不是普通私家车。这个判断时间不超过一秒钟&#xff0…

作者头像 李华
网站建设 2026/9/1 18:14:36

ESP8266与Proteus联合仿真:从电路搭建到固件调试的完整指南

简介&#xff1a;一套基于ESP8266与51单片机的Protues仿真工程&#xff0c;面向物联网和嵌入式方向的初学者、课程设计者&#xff0c;可在缺乏实物硬件的情况下完成联调验证。项目中包含1602液晶显示、电机控制&#xff0c;并可通过按键触发ESP8266向电脑端上位机上报数据&…

作者头像 李华
网站建设 2026/9/1 18:06:56

XR Operator:用AI智能体重塑VR游戏自动化测试

在 Quest 头显上调试 VR 游戏时&#xff0c;最消耗耐心的往往不是写玩法逻辑&#xff0c;而是“戴头显、操作手柄、摘头显、记录结果”这个循环。尤其当你要验证的是一条重要的新手引导流程&#xff0c;每次版本点击一遍&#xff0c;一天下来腰酸脖子酸&#xff0c;得到的结论还…

作者头像 李华