安卓开发板无线 ADB 调试与 UI 自动化测试指南

安卓开发板无线 ADB 调试与 UI 自动化测试指南

一、无线 ADB 连接

1.1 前提条件

  • 开发板与电脑连接同一 WiFi
  • 开发板已开启开发者选项和 USB 调试
  • 电脑上有 ADB 工具

1.2 开启无线调试

在开发板上操作:

设置 → 系统 → 开发者选项 → 无线调试 → 开启开关

点击 「配对码配对设备」,会显示 IP 地址、端口和 6 位配对码。

1.3 配对并连接

# 配对(配对码和端口从开发板获取)
adb pair 192.168.1.100:端口 配对码

# 连接(配对成功后显示的连接端口)
adb connect 192.168.1.100:34323

# 查看已连接的设备
adb devices

# 断开连接
adb disconnect 192.168.1.100:34323

注意:配对码有效期约 2-5 分钟,过期需重新生成。

1.4 常见问题

Q: 无法连接,端口 5555 被拒绝?

开发板可能没有默认监听 5555 端口。改用无线调试方式连接,或通过以下命令设置端口:

adb shell setprop service.adb.tcp.port 5556
adb shell stop adbd
adb shell start adbd

注意:setprop 设置的端口在重启后失效,需重新设置。

Q: adb pair 失败,提示 "Unable to start pairing client"?

检查 ADB 版本是否过旧,确保版本 >= 30.0.3:

adb version

二、scrcpy — 实时屏幕镜像与控制

2.1 简介

scrcpy 是一款开源的安卓屏幕镜像工具,支持实时画面显示和鼠标键盘控制,延迟极低。

2.2 安装

下载地址:https://github.com/Genymobile/scrcpy/releases

选择 scrcpy-win64-v4.0.zip,解压即可使用,无需安装。

2.3 使用

# 连接已通过 ADB 连接的设备
scrcpy

# 指定设备(多设备时)
scrcpy -s 192.168.1.100:34323

# 窗口模式(默认)
scrcpy

# 全屏模式
scrcpy --fullscreen

# 限定分辨率(省带宽)
scrcpy --max-size 1024

# 关闭屏幕(仅显示画面,设备屏幕熄灭)
scrcpy --turn-screen-off

2.4 常用快捷键

快捷键功能
鼠标左键点击
鼠标右键返回
鼠标中键Home
Ctrl+HHome
Ctrl+S截屏
Ctrl+O关闭屏幕
Ctrl+↑音量加
Ctrl+↓音量减

三、UI 控件定位 — 获取屏幕元素

3.1 使用 inspect_ui.py 工具

这是一个 Web 界面工具,点按钮即可获取当前屏幕的所有可点击控件信息。

启动

python inspect_ui.py

浏览器会自动打开 http://127.0.0.1:18889,点击 刷新 按钮即可获取当前界面的控件列表。

输出示例

坐标控件文字ID
[175,788][295,875]TextView"深度清洁"
[680,1024][760,1080]ImageViewsys_power
[45,852][165,939]TextView"启动"

3.2 坐标换算

控件 bounds 格式为 [left,top][right,bottom],点击时取中心坐标:

x = (left + right) / 2
y = (top + bottom) / 2

示例:[175,788][295,875]d.click(235, 831)

3.3 使用 uiautomator2 获取元素

import uiautomator2 as u2

d = u2.connect()

# 截图
d.screenshot("screen.png")

# 获取当前界面所有控件(XML 格式)
xml = d.dump_hierarchy()

# 获取当前前台应用
info = d.app_current()
print(info)

四、UI 自动化测试脚本

4.1 环境安装

pip install uiautomator2
python -m uiautomator2 init

init 命令会在开发板上安装 ATX 代理服务,后续所有操作都通过它执行。

4.2 基础用法

import uiautomator2 as u2
import time

d = u2.connect()

# 获取设备信息
print(d.info)

# 启动应用
d.app_start("com.android.settings")

# 点击文字
d(text="设置").click()

# 点击坐标
d.click(235, 831)

# 输入文字
d.send_keys("hello")

# 滑动
d.swipe(500, 1000, 500, 200)

# 截图
d.screenshot("screen.png")

# 等待元素出现
d(text="确定").wait(timeout=5)
d(text="确定").click()

# 获取控件是否存在
if d(text="确定").exists:
    d(text="确定").click()

4.3 完整示例

import uiautomator2 as u2
import time

d = u2.connect()

# 等待界面加载
time.sleep(2)

# 点击"深度清洁"
d(text="深度清洁").click()
time.sleep(1)

# 点击"启动"
d(text="启动").click()
time.sleep(3)

# 截图验证
d.screenshot("result.png")

4.4 定位方式优先级

  1. text — 文字匹配(最直观)
  2. resourceId — 控件 ID(最稳定)
  3. className — 控件类型
  4. 坐标 — 最后的手段
d(text="登录").click()                    # 按文字
d(resourceId="com.xx:id/btn_login").click()  # 按 ID
d(className="android.widget.Button").click()  # 按类型

五、工具链总结

工具用途运行方式
adb设备连接、文件传输、shell命令行
scrcpy实时画面、鼠标控制单窗口
inspect_ui.py获取控件坐标/文字/IDWeb 页面
uiautomator2自动化脚本Python 脚本

工作流程

1. adb connect → 连接设备
2. scrcpy → 实时看屏幕操作
3. inspect_ui.py → 点击"刷新"获取控件信息
4. 写 Python 脚本 → 用 uiautomator2 自动化

六、注意事项

  1. 无线 ADB 在设备重启后需重新连接setprop 设置的端口不会持久化
  2. 配对码会过期(约 2-5 分钟),过期后需重新生成
  3. d.dump_hierarchy() 每次耗时约 400ms,不需要追求太高的刷新频率
  4. scrcpy 和 inspect_ui 不冲突,一个看画面,一个看控件信息
  5. 首次使用需执行 python -m uiautomator2 init 安装 ATX 代理服务

七、AI skill


title: 安卓开发板无线调试与UI自动化完全指南 date: 2026-05-23 tags: [Android, ADB, scrcpy, uiautomator2, 自动化测试] name: android-remote-debug description: Use when the user asks about Android remote debugging, ADB over WiFi, scrcpy screen mirroring, UI automation testing with uiautomator2, or getting UI element coordinates/bounds. Covers wireless ADB connection, pairing, scrcpy usage, UI inspection, and uiautomator2 scripting.

Android Remote Debugging & UI Automation

Wireless ADB Connection

Prerequisites

  • Device and PC on same WiFi
  • Developer options & USB debugging enabled on device
  • ADB installed on PC

Pair & Connect

# Pair (code & port from device: Settings → Developer options → Wireless debugging → Pair with pairing code)
adb pair 192.168.1.100:PORT PAIRING_CODE

# Connect (use port shown after pairing)
adb connect 192.168.1.100:34323

# Verify
adb devices

# Disconnect
adb disconnect 192.168.1.100:34323

Pairing code expires in ~2-5 minutes. Regenerate by re-entering the pairing screen.

Alternative: Manual TCP Port

adb shell setprop service.adb.tcp.port 5556
adb shell stop adbd
adb shell start adbd

Note: setprop resets on reboot.

Common Issues

  • Port 5555 refused → Device not listening, use Wireless debugging pairing method
  • adb pair fails "Unable to start pairing client" → Check ADB version >= 30.0.3
  • Fiddler intercepts local connections → Use 127.0.0.1 instead of localhost, or close Fiddler

scrcpy — Real-time Screen Mirroring

Install

Download from: https://github.com/Genymobile/scrcpy/releases

Usage

scrcpy                            # Auto-connect to ADB device
scrcpy -s 192.168.1.100:34323     # Specific device
scrcpy --turn-screen-off          # Device screen off, PC only
scrcpy --max-size 1024            # Limit resolution
scrcpy --fullscreen               # Fullscreen mode

Key Bindings

InputAction
Left mouseTap
Right mouseBack
Middle mouseHome
Ctrl+HHome
Ctrl+SScreenshot
Ctrl+OTurn off screen

UI Element Inspection

Web Inspector Tool (inspect_ui.py)

A self-contained Python web server with a refresh button.

import uiautomator2 as u2
import xml.etree.ElementTree as ET
import json
from http.server import HTTPServer, BaseHTTPRequestHandler
import webbrowser

d = u2.connect()

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == "/":
            self.send_response(200)
            self.send_header("Content-Type", "text/html;charset=utf-8")
            self.end_headers()
            with open(__file__.replace('.py', '.html')) as f:
                self.wfile.write(f.read().encode())
        elif self.path == "/refresh":
            xml = d.dump_hierarchy()
            root = ET.fromstring(xml)
            cur = d.app_current()
            pkg = cur.get('package') or cur.get('currentPackageName', '')
            items = []
            for node in root.iter("node"):
                if node.get("clickable") == "true":
                    text = node.get("text", "") or ""
                    rid = node.get("resource-id", "") or ""
                    bounds = node.get("bounds", "")
                    cls = node.get("class", "").split(".")[-1]
                    if text or rid:
                        items.append({"text": text, "id": rid.split("/")[-1], "bounds": bounds, "class": cls})
            data = {"pkg": pkg, "items": items, "count": len(list(root.iter()))}
            self.send_response(200)
            self.send_header("Content-Type", "application/json;charset=utf-8")
            self.end_headers()
            self.wfile.write(json.dumps(data, ensure_ascii=False).encode())

httpd = HTTPServer(("127.0.0.1", 18889), Handler)
webbrowser.open("http://127.0.0.1:18889")
httpd.serve_forever()

Run: python inspect_ui.py → browser opens at http://127.0.0.1:18889 → click Refresh

Coordinate Calculation

Bounds format: [left,top][right,bottom]

x = (left + right) / 2
y = (top + bottom) / 2

Example: [175,788][295,875]d.click(235, 831)

uiautomator2 Automation

Setup

pip install uiautomator2
python -m uiautomator2 init    # Installs ATX agent on device

Element Locators

d(text="登录").click()                            # By text
d(resourceId="com.xx:id/btn").click()            # By resource ID
d(className="android.widget.Button").click()      # By class
d.click(235, 831)                                  # By coordinate

Common Operations

import uiautomator2 as u2
import time

d = u2.connect()

d.app_start("com.android.settings")   # Launch app
d.send_keys("hello")                   # Input text
d.swipe(500, 1000, 500, 200)          # Swipe
d(text="确认").wait(timeout=5)        # Wait for element
d(text="确认").click()                 # Click after wait
d.screenshot("screen.png")            # Screenshot

Full Example

import uiautomator2 as u2
import time

d = u2.connect()
time.sleep(2)
d(text="深度清洁").click()
time.sleep(1)
d(text="启动").click()
time.sleep(3)
d.screenshot("result.png")

Workflow

Terminal 1: adb connect 192.168.1.100:34323
Terminal 2: scrcpy -s 192.168.1.100:34323
Terminal 3: python inspect_ui.py  →  http://127.0.0.1:18889
Terminal 4: Write & run automation script
  • scrcpy: Real-time view + manual control
  • inspect_ui: Refresh button → get all clickable elements
  • uiautomator2 script: Automated test flow

Notes

  • Reboot resets wireless ADB; reconnect after reboot
  • d.dump_hierarchy() takes ~400ms per call; don't set too fast refresh
  • Run python -m uiautomator2 init once before first use
  • Fiddler or similar proxies block local web servers; close or use 127.0.0.1

Installation

opencode

Place in .opencode/skills/android-remote-debug/SKILL.md or add the path to skills.paths in opencode.json:

{
  "skills": {
    "paths": [".opencode/skills"]
  }
}

Manual

Place anywhere and load as a reference file when working on Android automation.

学习
知识