☰
scrcpy 设备连接完全指南:设备选择、无线 TCP/IP 连接与源码实现剖析
2026/9/25 7:59:10 网站建设 项目流程

scrcpy 设备连接完全指南:设备选择、无线 TCP/IP 连接与源码实现剖析

【免费下载链接】scrcpyDisplay and control your Android device项目地址: https://gitcode.com/GitHub_Trending/sc/scrcpy

本文基于 scrcpy 官方文档 Connection 与客户端源码,系统讲解多设备环境下的设备选择机制(--serial/--select-usb/--select-tcpip/--tcpip)、ANDROID_SERIAL环境变量、无线 TCP/IP 连接的自动与手动两种模式,并结合 app/src/adb/adb.c 与 app/src/server.c 中的实际调用链,剖析这些选项在底层是如何解析adb devices -l输出、判定设备类型、自动完成 USB 到 TCP/IP 切换的。读完后你可以独立完成多设备指定、免数据线投屏,并能读懂 scrcpy 连接阶段的日志输出。

一、设备选择(Selection)

scrcpy 通过adb枚举设备。当adb devices恰好只列出一台设备时,scrcpy 会自动选中它,无需任何参数。

当连接了多台设备时,必须用以下 4 种方式之一指定目标设备:

1. 通过序列号(serial)选择

scrcpy --serial=0123456789abcdef scrcpy -s 0123456789abcdef # 短选项 # 通过 TCP/IP 连接时,serial 就是 ip:port(行为与 adb 一致) scrcpy --serial=192.168.1.1:5555

2. 指定 USB 设备(要求恰好只有一台)

scrcpy --select-usb scrcpy -d # 短选项

3. 指定 TCP/IP 设备(要求恰好只有一台)

scrcpy --select-tcpip scrcpy -e # 短选项

4. 直接连接一个已在监听 TCP/IP 的设备

scrcpy --tcpip=192.168.1.1:5555 scrcpy --tcpip=192.168.1.1 # 默认端口为 5555

此外,序列号也可以通过环境变量ANDROID_SERIAL提供(adb工具同样使用该变量),三种常见 Shell 下的写法:

# in bash export ANDROID_SERIAL=0123456789abcdef scrcpy
:: in cmd set ANDROID_SERIAL=0123456789abcdef scrcpy
# in PowerShell $env:ANDROID_SERIAL = '0123456789abcdef' scrcpy

二、源码剖析:scrcpy 是如何完成设备选择的

上面 4 种选择方式在源码中统一收敛为「选择器(selector)」机制,核心实现在 sc_adb_select_device():

  1. 枚举设备:sc_adb_list_devices() 执行adb devices -l,将输出解析为设备列表(serial、state、model)。解析逻辑由 app/src/adb/adb_parser.c 实现,并有对应的单元测试 test_adb_parser.c 覆盖。
  2. 按选择器过滤:每种命令行选项对应 sc_adb_device_selector 的一个类型——SC_ADB_DEVICE_SELECT_ALL(无参数)、SC_ADB_DEVICE_SELECT_SERIAL(-s)、SC_ADB_DEVICE_SELECT_USB(-d)、SC_ADB_DEVICE_SELECT_TCPIP(-e),过滤规则见 sc_adb_accept_device()。
  3. 设备类型判定:sc_adb_device_get_type() 的规则非常简洁——serial 以emulator-开头判为模拟器;serial 中含:判为 TCP/IP 设备(因为ip:port与真实 USB serial 可以靠冒号区分);其余判为 USB 设备。因此-e实际会同时选中「TCP/IP 设备和模拟器」,这与 adb 的-e语义一致(源码注释中亦有说明)。
  4. 数量校验与状态检查:匹配到 0 台或多台都会报错并打印全部设备列表(日志中带-->标记的即候选设备);匹配到 1 台后还会检查其状态(sc_adb_device_check_state(),adb.c#L584-L604)——只有device状态可用,unauthorized会提示在设备上确认授权弹窗。

两个值得注意的匹配细节(adb.c#L513-L534):

  • IP 前缀匹配:如果设备 serial 是192.168.1.1:5555,而你用--serial=192.168.1.1(不带端口)匹配,scrcpy 会截取 IP 部分做前缀比较——因此--serial=IP可匹配该 IP 的任意 adb 端口,这也是--tcpip=192.168.1.1能自动补默认端口的基础。
  • ANDROID_SERIAL的读取时机:在 run_server() 中,当未显式给出-s/-d/-e时,scrcpy 会调用getenv("ANDROID_SERIAL");若设置了该变量,则隐式按 serial 选择器过滤,等价于scrcpy -s $ANDROID_SERIAL。

命令行选项的定义见 app/src/cli.c(-d/--select-usb)与 app/src/cli.c(-e/--select-tcpip),--tcpip选项在 app/src/cli.c#L904-L906。注意三者的互斥关系:在需要「先选设备」的路径上,req_serial、select_usb、select_tcpip三者至多只能设置一个(见 server.c#L967-L971 的断言)。

三、TCP/IP(无线)连接

scrcpy 依赖adb与设备通信,而adb本身支持通过 TCP/IP 连接设备。前提是设备与电脑处于同一网络。

3.1 自动模式(--tcpip)

--tcpip有两个用法:

用法 A:不带参数(设备上 adb TCP/IP 模式未开启,或不知道 IP)——先用 USB 连上设备,然后:

scrcpy --tcpip # 不带参数

scrcpy 会自动:探测设备 IP 和 adb 端口 → 必要时开启 TCP/IP 模式 → 连接设备 → 再启动投屏。

用法 B:带地址(设备已在监听 adb 端口,通常是 5555):

scrcpy --tcpip=192.168.1.1 # 默认端口为 5555 scrcpy --tcpip=192.168.1.1:5555

强制重连:在地址前加+前缀,会先断开旧连接再连接:

scrcpy --tcpip=+192.168.1.1

3.2 自动模式背后的调用链

整个流程集中在 app/src/server.c 的run_server()中,按是否带地址分两条路径:

路径一:--tcpip(无地址)→ sc_server_configure_tcpip_unknown_address()

  1. 先用 USB 选出一台设备(第二节的 selector 机制);若该设备已经是 TCP/IP 类型则直接复用。
  2. sc_server_switch_to_tcpip() 完成「USB → TCP/IP」切换:
    • sc_adb_get_device_ip() 执行adb -s <serial> shell ip route并解析出设备 IP;
    • get_adb_tcp_port() 读取设备属性service.adb.tcp.port判断 TCP/IP 模式是否已开启;
    • 若未开启,调用 sc_adb_tcpip()(即adb tcpip 5555,5555定义在 server.c#L23 的SC_ADB_PORT_DEFAULT),然后由 wait_tcpip_mode_enabled()轮询等待:每 250ms 重读一次service.adb.tcp.port,最多 40 次(约 10 秒),直到属性值等于 5555——这一步解释了「adb tcpip执行后 adbd 需要重启、存在短暂延迟」这一现象。

路径二:--tcpip=ip[:port](已知地址)→ sc_server_configure_tcpip_known_address()

  • 地址中无端口时自动补上默认端口 5555;
  • +前缀会被 run_server() 检测出来,先执行一次adb disconnect(静默模式,连接不存在时不报错)再连接;
  • 随后调用 sc_server_connect_to_tcpip() 执行adb connect ip:port。

一个容易踩坑的底层细节:adb connect无论成败退出码都是 0,所以 sc_adb_connect() 不得不读取其 stdout,只有输出以connected或already connected开头才判定成功;否则把 adb 的报错回显到 stderr。这就是连接失败时你会在终端看到类似failed to connect to '192.168.1.1:5555'输出的原因。

3.3 手动模式

也可以不借助--tcpip,直接用adb手动完成:

  1. 用 USB 把设备连到电脑;

  2. 让设备与电脑连入同一个 Wi-Fi网络;

  3. 获取设备 IP:在「设置 → 关于手机 → 状态信息」中查看,或执行:

    adb shell ip route | awk '{print $9}'
  4. 在设备上启用 adb TCP/IP 模式:adb tcpip 5555;

  5. 拔掉 USB 线;

  6. 连接设备:adb connect DEVICE_IP:5555(DEVICE_IP换成上一步查到的 IP);

  7. 像平常一样运行scrcpy;

  8. 用完后执行adb disconnect。

自 Android 11 起,系统还内置了「无线调试」功能,可以完全跳过物理 USB 连接这一步,直接通过配对码完成无线 adb 连接(参见 ADB 官方文档中 wireless debugging 一节)。

四、自动启动(Autostart)

scrcpy 作者维护了一个小工具AutoAdb,可以在检测到新 Android 设备连接的瞬间自动执行任意命令。用它实现「设备一插上就启动 scrcpy」:

autoadb scrcpy -s '{}'

其中{}是 AutoAdb 提供的占位符,会被替换为新连接设备的 serial,等价于scrcpy -s <新设备serial>,天然适配多设备环境。

五、常见问题速查

现象原因与处理
Multiple (N) ADB devices报错多台设备时未指定选择器;用-s/-d/-e指定,或设置ANDROID_SERIAL
Device is unauthorized设备端未确认调试授权弹窗,在设备上点击允许即可(报错信息会引导查看 FAQ.md)
Could not find any ADB device over USB/TCP/IP-d/-e要求「恰好一台」,当前一台都没有;确认adb devices输出
adb tcpip后一段时间才能连上adbd 重启需要时间;自动模式内置了最多约 10 秒的轮询等待(40 次 × 250ms),手动模式建议稍等数秒再adb connect
换了 Wi-Fi 后连接失败设备与电脑必须同网段;重新查 IP 并adb connect

适用范围说明:以上行为均基于当前仓库源码验证——默认端口 5555 由 SC_ADB_PORT_DEFAULT 决定;--tcpip=+ip的强制重连、ANDROID_SERIAL兜底等细节均与文档 doc/connection.md 描述一致。若你使用 portable 版 scrcpy,adb 二进制随包附带,其查找逻辑见 sc_adb_init()。

【免费下载链接】scrcpyDisplay and control your Android device项目地址: https://gitcode.com/GitHub_Trending/sc/scrcpy

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询