Android 手簿 ADB 无线调试全攻略:USB 转 WiFi 一键连接
面向现场测绘 / 硬件工程师的一篇实操向技术博客。解决「全站仪手簿、安卓主机等设备调试时被 USB 线束缚」的痛点,用
adb tcpip+ 自动读 IP + 重试,实现插一次 USB、之后全程 WiFi 无线调试。
目录
一、使用前提
开始之前,请逐条确认下面的前置条件。任何一条不满足,都会导致脚本卡在某个环节。
1. 硬件准备
| 项目 | 要求 |
|---|---|
| 目标设备 | Android 设备(手簿 / 全站仪主机),系统版本不限(本文方案兼容较老版本) |
| USB 数据线 | 支持数据传输(非纯充电线),且手簿已能通过 USB 被电脑识别 |
| 电脑 | Windows(本文脚本为 bat / ps1) |
| 网络 | 设备与电脑需处于同一局域网(同一 WiFi / 同一路由器下) |
2. 软件环境
- 电脑已安装 adb(Android SDK platform-tools)。
adb已加入系统PATH,在任意终端输入adb version能看到版本号。- 验证命令:
bat
adb version
如果提示「不是内部或外部命令」,需要把
platform-tools目录加到PATH,或修改脚本顶部的ADB变量为完整路径(如D:\platform-tools\adb.exe)。
3. 设备端配置
在手簿 / 主机上依次完成:
- 打开 设置 → 关于设备 ,连点「版本号」7 次,开启 开发者选项。
- 进入 开发者选项 ,打开 USB 调试(USB debugging)。
- 建议同时打开「USB 安装」「保持唤醒」,避免调试中途休眠断开。
4. 网络要求(最关键)
- 设备必须已连接 WiFi,且拿到了局域网 IP。
- 电脑与设备必须能互相 ping 通 。例如设备 IP 是
172.16.93.76,在电脑上:
bat
ping 172.16.93.76
- 常见网段:
172.16.x.x、192.168.x.x、10.x.x.x。如果 ping 不通,先解决网络,再谈无线调试。
5. 授权确认
- 第一次通过 USB 连接时,设备屏幕会弹出「是否允许 USB 调试 」,必须点允许(并勾选「一律允许」)。
- 如果之前点过「拒绝」,需要到开发者选项里「撤销 USB 调试授权」后重新插线确认。
二、原理解析
adb 本质上是一个 C/S 架构 :电脑端是 adb 客户端,设备端跑着 adbd 守护进程。连接方式有两种:
| 方式 | 传输层 | 设备标识 |
|---|---|---|
| USB 调试 | USB 线(transport-usb) | 序列号,如 ABCD1234 |
| 无线调试 | TCP(transport-tcp) | IP:端口,如 172.16.93.76:5555 |
整套方案的核心只有三步:
text
1. adb tcpip 5555
让设备端的 adbd 从「USB 模式」切换到「TCP 监听模式」,开始监听 5555 端口。
2. 读取设备 WiFi 的 IP
通过 USB 通道(此时 USB 还连着)执行 adb shell ip addr,取出 wlan0 的 IP。
3. adb connect <ip>:5555
电脑端主动向该 IP 的 5555 端口发起 TCP 连接,建立无线调试通道。
之后即可拔掉 USB 线,只要设备 IP 不变、网络不断,无线调试一直有效。
注意:
tcpip会重启设备端 adbd,所以重启后到端口真正可连之间有几秒的间隔,这也是脚本里需要加延时 / 重试的原因。
三、一键脚本
下面是两个完整版本,任选其一。脚本都已处理「多设备、重试、状态判定、编码」等踩坑点(详见第四节)。
版本一:批处理脚本 adb_wifi_connect.bat
保存为 .bat,双击或命令行运行。
bat
@echo off
setlocal enabledelayedexpansion
title ADB WiFi Connect
set "ADB=adb"
set "PORT=5555"
set "MAX_RETRY=3"
echo ==============================================
echo ADB WiFi Connect (retry up to %MAX_RETRY% times)
echo ==============================================
echo.
%ADB% version >nul 2>&1
if errorlevel 1 (
echo [ERROR] adb not found. Add it to PATH or set ADB to full path.
pause
exit /b 1
)
rem --- 0. Disconnect old WiFi connections to avoid "more than one device" ---
echo [0/4] Disconnecting old WiFi connections ...
%ADB% disconnect >nul 2>&1
rem --- detect USB device serial (the line without a colon) ---
set "USB_SERIAL="
set "USB_COUNT=0"
for /f "tokens=1" %%s in ('%ADB% devices ^| findstr /v "List of"') do (
echo %%s | findstr ":" >nul
if errorlevel 1 (
set /a USB_COUNT+=1
set "USB_SERIAL=%%s"
)
)
if "%USB_COUNT%"=="0" (
echo [ERROR] No USB device found. Plug in the device via USB.
pause
exit /b 1
)
if not "%USB_COUNT%"=="1" (
echo [ERROR] %USB_COUNT% USB devices found. Unplug the extras and retry.
pause
exit /b 1
)
echo USB device: %USB_SERIAL%
rem --- 1. tcpip on the specific USB device ---
echo [1/4] adb -s %USB_SERIAL% tcpip %PORT% ...
%ADB% -s %USB_SERIAL% tcpip %PORT%
if errorlevel 1 (
echo [ERROR] adb tcpip failed. Check USB connection and USB debugging.
pause
exit /b 1
)
ping -n 3 127.0.0.1 >nul
rem --- 2. read device IP ---
echo [2/4] Reading device IP ...
set "DEVICE_IP="
call :get_ip %USB_SERIAL% wlan0
if not defined DEVICE_IP call :get_ip %USB_SERIAL% eth0
if not defined DEVICE_IP call :get_ip %USB_SERIAL% ""
if not defined DEVICE_IP (
echo [ERROR] Cannot read device IP. Make sure device is on WiFi.
pause
exit /b 1
)
echo Device IP: %DEVICE_IP%
rem --- 3. connect with retry ---
echo [3/4] Connecting to %DEVICE_IP%:%PORT% ...
set /a TRY=0
:connect_loop
set /a TRY+=1
echo Attempt %TRY%/%MAX_RETRY% ...
%ADB% connect %DEVICE_IP%:%PORT%
set "STATE="
for /f "tokens=1,2" %%d in ('%ADB% devices ^| findstr /c:"%DEVICE_IP%:%PORT%"') do set "STATE=%%e"
echo State=[%STATE%]
if /i "%STATE%"=="device" goto :connected
if %TRY% LSS %MAX_RETRY% (
echo Not ready, retrying in 2s ...
ping -n 3 127.0.0.1 >nul
goto :connect_loop
)
echo.
echo [FAILED] Cannot connect after %MAX_RETRY% attempts.
echo Current adb devices:
%ADB% devices
pause
exit /b 1
:connected
echo Connected!
echo.
echo Current adb devices:
%ADB% devices
echo.
echo ==============================================
echo Done. Now you can unplug the USB cable.
echo Disconnect: %ADB% disconnect %DEVICE_IP%:%PORT%
echo ==============================================
pause
exit /b 0
rem ---------- sub: get IPv4 by interface ----------
:get_ip
set "SERIAL=%~1"
set "IFACE=%~2"
if "%IFACE%"=="" (
for /f "tokens=2 delims= " %%a in ('%ADB% -s %SERIAL% shell ip -4 addr 2^>nul ^| findstr "inet"') do (
call :pick_ip %%a
if defined DEVICE_IP goto :eof
)
) else (
for /f "tokens=2 delims= " %%a in ('%ADB% -s %SERIAL% shell ip -4 addr show %IFACE% 2^>nul ^| findstr "inet"') do (
call :pick_ip %%a
if defined DEVICE_IP goto :eof
)
)
goto :eof
rem ---------- sub: strip /mask, skip loopback ----------
:pick_ip
set "RAW=%~1"
for /f "tokens=1 delims=/" %%b in ("%RAW%") do set "IP=%%b"
if not "%IP%"=="127.0.0.1" set "DEVICE_IP=%IP%"
goto :eof
版本二:PowerShell 脚本 adb_wifi_connect.ps1
运行方式:powershell -ExecutionPolicy Bypass -File adb_wifi_connect.ps1
powershell
$ErrorActionPreference = "Stop"
$adb = "adb"
$port = 5555
$maxRetry = 3
Write-Host "=== ADB WiFi Connect (retry up to $maxRetry times) ===" -ForegroundColor Cyan
# 0. Disconnect old WiFi connections to avoid "more than one device"
Write-Host "[0/4] Disconnecting old WiFi connections ..."
& $adb disconnect | Out-Null
# detect USB devices (serial without a colon)
$usbDevices = @()
foreach ($line in (& $adb devices)) {
if ($line -and $line -notmatch 'List of devices') {
$parts = $line -split '\s+'
$serial = $parts[0]
if ($serial -notmatch ':') {
$usbDevices += $serial
}
}
}
if ($usbDevices.Count -eq 0) {
Write-Host "[ERROR] No USB device found. Plug in the device via USB." -ForegroundColor Red
exit 1
}
if ($usbDevices.Count -gt 1) {
Write-Host "[ERROR] $($usbDevices.Count) USB devices found. Unplug the extras and retry." -ForegroundColor Red
exit 1
}
$serial = $usbDevices[0]
Write-Host "USB device: $serial"
# 1. tcpip on the specific USB device
Write-Host "[1/4] adb -s $serial tcpip $port ..."
& $adb -s $serial tcpip $port
Start-Sleep -Seconds 2
# 2. read device IP
Write-Host "[2/4] Reading device IP ..."
$ip = $null
foreach ($iface in @("wlan0", "eth0")) {
$out = & $adb -s $serial shell ip -4 addr show $iface 2>$null
$line = $out | Where-Object { $_ -match 'inet\s+\d+\.\d+\.\d+\.\d+' } | Select-Object -First 1
if ($line -match 'inet\s+(\d+\.\d+\.\d+\.\d+)') {
$ip = $Matches[1]
break
}
}
if (-not $ip) {
$out = & $adb -s $serial shell ip -4 addr 2>$null
$line = $out | Where-Object { $_ -match 'inet\s+\d+\.\d+\.\d+\.\d+' -and $_ -notmatch '127\.0\.0\.1' } | Select-Object -First 1
if ($line -match 'inet\s+(\d+\.\d+\.\d+\.\d+)') {
$ip = $Matches[1]
}
}
if (-not $ip) {
Write-Host "[ERROR] Cannot read device IP. Make sure the device is connected to WiFi." -ForegroundColor Red
exit 1
}
Write-Host "Device IP: $ip"
# 3. connect with retry. Only 'device' state counts as success.
Write-Host "[3/4] Connecting to ${ip}:${port} ..."
$connected = $false
for ($i = 1; $i -le $maxRetry; $i++) {
Write-Host " Attempt $i/$maxRetry ..."
& $adb connect "${ip}:${port}" | Out-Host
$state = $null
foreach ($line in (& $adb devices)) {
if ($line -like "${ip}:${port}*") {
$parts = $line -split '\s+'
if ($parts.Count -ge 2) { $state = $parts[1] }
}
}
Write-Host " State: $state"
if ($state -eq 'device') {
$connected = $true
break
}
if ($i -lt $maxRetry) {
Write-Host " Not ready, retrying in 2s ..."
Start-Sleep -Seconds 2
}
}
Write-Host ""
Write-Host "Current adb devices:"
& $adb devices
if (-not $connected) {
Write-Host ""
Write-Host "[FAILED] Cannot connect after $maxRetry attempts." -ForegroundColor Red
exit 1
}
Write-Host ""
Write-Host "Done. Now you can unplug the USB cable." -ForegroundColor Green
Write-Host "Disconnect: adb disconnect ${ip}:${port}"
四、脚本关键点拆解
脚本不是简单地把三条命令串起来,下面这些点都是实测踩坑后的沉淀。
1. 多设备歧义:more than one device
如果之前跑过一次脚本,残留的 WiFi 连接(172.16.93.76:5555)还在 adb devices 列表里,此时再加 USB,就是两个设备。直接 adb tcpip 5555 会报:
text
error: more than one device/emulator
解决 :脚本开头先 adb disconnect 断开所有 TCP 连接(只留 USB),再从 adb devices 里解析出「不含冒号」的那行作为 USB 序列号,后续用 adb -s <serial> 锁定设备。
2. 成功判定:只认 device
adb connect 后,adb devices 里对应条目的状态有三种:
| 状态 | 含义 | 是否可用 |
|---|---|---|
device |
已授权、可调试 | ✅ |
unauthorized |
连上了但没授权 | ❌(需在设备上点允许) |
offline |
TCP 通了但 adbd 没响应 | ❌ |
早期版本把 unauthorized 也当成功,导致误报「已连接」。正确做法是只认 device,其余都重试。
3. 自动读 IP:接口优先级
不同设备网卡名不同,脚本按 wlan0 → eth0 → 遍历所有接口 的顺序尝试,最后统一排除回环地址 127.0.0.1。这样 WiFi 手簿、有线主机都能适配,且不硬编码 IP(DHCP 会漂移)。
4. 延时用 ping 而非 timeout
timeout /t 在非交互终端(IDE 终端、管道调用)会报错:
text
ERROR: Input redirection is not supported, exiting the process immediately.
导致脚本中断、看不到进度。改用 ping -n 3 127.0.0.1 >nul 做约 2 秒延时,不依赖 stdin,任何环境都能跑。
5. 提示用英文而非中文
Windows 自带 PowerShell 5.1 会把无 BOM 的 UTF-8 文件按 GBK 解码,中文提示在脚本加载阶段就变成乱码,且运行期改编码无效。因此脚本提示统一用英文,彻底规避编码问题。
五、使用步骤
- 确认前提:逐条核对「一、使用前提」。
- 插线:USB 数据线连接手簿与电脑。
- 跑脚本 :双击
adb_wifi_connect.bat,或执行 ps1。 - 观察输出 :确认
USB device、Device IP、State=device都正常。 - 拔线 :拔掉 USB,此时
adb devices里仍有172.16.93.76:5555 device即成功。 - 验证 :
adb shell能进入设备 shell,即无线调试生效。
六、常见问题排查
| 现象 | 原因 | 处理 |
|---|---|---|
error: more than one device/emulator |
残留 WiFi 连接 + USB 共 2 个设备 | 脚本已自动 adb disconnect;或手动执行 adb disconnect |
adb tcpip failed |
USB 未识别 / 未开 USB 调试 | 检查数据线、开发者选项、USB 调试授权 |
Cannot read device IP |
设备没连 WiFi / 没拿到 IP | 让设备连上 WiFi,确认 adb shell ip addr 有 inet |
State: unauthorized |
设备端没点「允许调试」 | 手簿屏幕上点允许;或撤销授权后重插 |
State: offline |
电脑与设备不在同一网段 / 网络不通 | ping 设备 IP,确保同网段、防火墙放行 |
| 昨天能连今天连不上 | 设备 DHCP 换 IP 了 | 重跑脚本(自动读新 IP);或给设备配静态 IP |
| ps1 输出乱码 | PowerShell 5.1 编码问题 | 改用英文版;或用 bat 版 |
| bat 看不到进度 | timeout 在非交互终端中断 |
已改用 ping 延时 |
七、总结
adb tcpip + 自动读 IP + adb connect 三招,就能把手簿从 USB 线里解放出来,实现全程 WiFi 无线调试。真正麻烦的不是命令本身,而是多设备歧义、状态误判、编码乱码、非交互延时这些细节------它们每一处都值得在脚本里提前处理好。
希望这篇博客能帮你少踩几个坑。