Adb 方法
Adb 在 Android 11+ 上通过本机无线调试操作手机。先完成 开启与配对,再调用下面的方法。
手机上可打开 示例 → 接口 → Adb 无线调试 实测自动配对。请优先看 开启与配对;连不上再看 手动配对。
完整方法列表在脚本里执行下面一句即可(会按行打到控制台;不要再包一层 console.log,否则摘要可能被挤成一行):
Adb.help();多数方法返回对象,至少包含:
| 字段 | 含义 |
|---|---|
ok | 是否成功 |
error | 失败原因(失败时) |
code | shell 类命令的退出码;失败时常为 -1 |
result / all | 标准输出或合并输出 |
最小可运行示例
第一次要配对,再连接。 默认只填 6 位码:Adb.pairWithCode,见 开启与配对。自动连不上再 手动配对。
使用前请先:打开 Wi‑Fi → 打开「无线调试」,见 开启与配对。
推荐:日常先 connectSaved,首次才 pairWithCode
两条都会自动扫描端口,不用手填。connectSaved 会先用上次成功的端口,扫不到再找当前连接端口。只有从未配对、撤销授权或清数据后,才用通知栏回复 6 位码;pairWithCode 会自己找配对端口和连接端口。自动扫描仍失败时,再看 手动配对(那里才手填端口)。
if (!Adb.isSupported()) {
throw new Error("需要 Android 11+");
}
// 已连接 / 历史端口 / 自动扫描连接端口
let c = Adb.connectSaved();
if (!c.ok) {
// 只填 6 位码,配对端口和连接端口都自动扫描
let code = App.notifyInput(
"无线调试配对",
"点「输入」回复 6 位配对码。不要回到本应用。",
"6 位配对码",
function () {
Adb.openWirelessDebuggingSettings();
}
);
if (!code) {
throw new Error(c.error || "连接失败;自动扫描不到时可改试手动配对");
}
c = Adb.pairWithCode(String(code), 120000);
}
if (!c.ok) {
throw new Error(c.error || "连接失败;可改试手动配对");
}
console.log(Adb.shell("id"));
Adb.home();
Adb.tap(500, 800);
Adb.swipe(500, 1400, 500, 400, 300);首次从未配对过时,直接 Adb.pairWithCode(六位码),见 开启与配对。自动扫描仍失败时,再看 手动配对。日常封装可抄 开启与配对 · 已经配对过之后 的 ensureAdb()。
相近方法怎么选
| 你想做的事 | 用这个 | 说明 |
|---|---|---|
| 第一次信任本 App(推荐) | pairWithCode(code) | 只填 6 位码;自动发现本机端口 |
| 第一次信任本 App(手动) | pair | 配对端口 + 6 位码 |
| 日常连上 adbd | connect / connectSaved | 不要每次都 pair |
| 执行任意命令 | shell(cmd) | 最常用的通用入口 |
| 打开底层 ADB 服务 | service(destination) | 如 tcp:8080、exec:... |
| 点一下 / 滑动 | tap / swipe | 底层是 input |
| 亮屏 | power() / wake() | 点亮已经息屏的屏幕 |
| 息屏 | sleep() | 关掉屏幕 |
| 输入文字 | text | ASCII 走 input text;中文等走剪贴板再粘贴 |
| 截图到文件 | screenshot(path) | 也可用 screenshotBytes |
| 授权运行时权限 | grant(pkg, permission) | shell 身份下多数可授 |
| 未封装的能力 | shell 或 service | 不要等专用 API |
下面每个方法单独写用途。别名跟在主方法后面,不再把不同用途的方法挤在同一段。
状态与设置页
isSupported()
用途: 判断这台设备能不能用无线调试。Android 11 以下为 false。
返回: {boolean}
status()
用途: 一次看完连接和开关状态,排查「为什么连不上」时先调它。
返回: {object},含 supported、connected、host、port、adbEnabled、wirelessDebuggingEnabled、developerOptionsEnabled、sdk、timeouts
isConnected()
用途: 看当前这条到 adbd 的连接还在不在。别名 getConnectState。
返回: {boolean}
isAdbEnabled()
用途: 看系统「USB 调试」开关是否打开。无线调试通常要先开这个。
返回: {boolean}
isWirelessDebuggingEnabled()
用途: 看系统「无线调试」开关是否打开。
返回: {boolean}
isDeveloperOptionsEnabled()
用途: 看开发者选项是否已经打开。
返回: {boolean}
openWirelessDebuggingSettings()
用途: 跳到系统「无线调试」页,方便用户打开开关或点「使用配对码配对设备」。打不开专用页时会落到开发者选项。别名 openWirelessDebugging。
返回: {boolean} 是否成功拉起页面
openDeveloperOptions()
用途: 跳到系统「开发者选项」页。
返回: {boolean} 是否成功拉起页面
配对与连接
pairWithCode(code) / pairWithCode(code, timeoutMs) / pairWithCode(options)
用途: 首次配对。只填 6 位配对码,配对端口和连接端口都自动扫描,扫到后完成配对并连上。别名 pairCode、easyPair。
mDNS 只接受当前手机自己的地址,忽略局域网其它设备;真正连的时候优先局域网 IP,127.0.0.1 只作兜底。
参数:
code {string}6 位配对码timeoutMs {number}可选,整段扫描+配对+连接的总超时,默认60000(60 秒)。华为等机型发现慢时,可改成120000或更大;超时后会停止扫描并返回错误,不会一直扫下去。options {object}可选:{ code }/{ pairingCode }/{ code, timeoutMs }/{ timeout }
返回: {object} 成功时 ok === true,并带 pairPort / connectPort / host(多为局域网 IP,例如 192.168.x.x)/ timeoutMs
调用前请先打开「使用配对码配对设备」,并用 通知栏回复 6 位码(App.notifyInput)。不要切回本应用,否则配对弹窗常被关掉。别名:pairCode、easyPair。自动发现失败再 手动配对。
Adb.pairWithCode("643102"); // 默认等 60 秒
Adb.pairWithCode("643102", 120000); // 自定义:最多扫描 120 秒
Adb.pairWithCode({ code: "643102", timeoutMs: 120000 });pair(port, code) / pair(host, port, code) / pair(options)
用途: 手动配对。自己已经抄到配对端口和 6 位码时用。只交换密钥,不会接着连接,成功后还要 connect。自动扫描失败时才用。
参数:
port {number}配对端口(配对码页面上的端口)code {string}6 位配对码host {string}可选;不填则按本机局域网 IP →127.0.0.1轮询options {object}可选:{ host, port, code }或{ host, port, pairingCode }
返回: {object} ok 为 true 表示配对成功
Adb.pair(37123, "643102"); // 自动试本机局域网 IP
Adb.pair("192.168.1.8", 37123, "643102"); // 与设置页 IP 一致
Adb.pair({ host: "192.168.1.8", port: 37123, code: "643102" });connect() / connect(port) / connect(host, port) / connect("ip:port") / connect(options)
用途: 按指定地址连上 adbd。无参时等同 connectSaved()。本机地址会优先试局域网 IP。连上后会执行 echo 探测,探测失败不算连上。
参数:
- 无参:等同
connectSaved(),用上次成功的 host/port port {number}连接端口host {string}可选"ip:port" {string}例如"127.0.0.1:5555"options {object}{ host, port }
返回: {object} 成功时 ok === true,并带 host / port
Adb.connect(5555); // 自动优先局域网 IP
Adb.connect("192.168.1.8", 5555); // 与设置页 IP 一致
Adb.connect("192.168.1.8:5555");connectSaved()
用途: 日常重连。已经连着就直接成功;否则用上次成功的端口,还不行就自动扫描当前连接端口。日常启动用这个,不用手填端口。
返回: {object} 成功时 ok === true,并带 host / port。已连着时 message 为 already_connected
let c = Adb.connectSaved();connectByDiscovery(timeoutMs)
用途: 忽略历史端口,只扫描当前连接端口并连上。已经配对过、但保存的端口失效时,connectSaved 内部会走这一步。
参数: timeoutMs {number} 可选,默认 8000
返回: {object}
tryConnect(...)
用途: 和 connect 相同的参数,失败时把异常收成 { ok: false, error },方便脚本分支判断。
返回: {object}
reconnect()
用途: 先断开,再按上次保存的 host 和 port 重连一次。
返回: {object}
disconnect()
用途: 关掉当前到 adbd 的套接字。配对密钥还在,下次 connectSaved() 不用再填 6 位码。
返回: {boolean}
resetConnection()
用途: 断开后立刻 connectSaved(),用来清掉一条已经失效的连接。
返回: {boolean} 重连是否成功
waitConnected(timeoutMs, intervalMs)
用途: 在一段时间内反复 connectSaved(),直到连上或超时。脚本启动后要等调试通道就绪时用。
参数:
timeoutMs {number}最长等待,默认15000intervalMs {number}轮询间隔,默认500
返回: {object} 连上则 ok === true
setHost(host)
用途: 写下一次连接要用的主机地址。connect / pair 成功后也会自动保存。
返回: {boolean}
setPort(port)
用途: 写下一次连接要用的端口。范围 1 到 65535。
返回: {boolean}
getHost()
用途: 读取当前保存的主机地址。
返回: {string}
getPort()
用途: 读取当前保存的连接端口。还没成功连过时可能是 0。
返回: {number}
setTimeouts(connectTimeout, socketTimeout)
用途: 设置连接超时。第二个参数目前和连接超时一起保存。
参数:
connectTimeout {number}连接超时毫秒socketTimeout {number}预留,当前与连接超时一并保存
返回: {object} 当前超时配置
getTimeouts()
用途: 读取当前连接超时配置。
返回: {object} 含 connectTimeout、socketTimeout
发现
日常配对和 connectSaved 会自己扫描,一般不用直接调这组方法。要自己看扫到了哪些端口时再用。
startDiscovery()
用途: 开始扫描本机无线调试的配对端口和连接端口。别名 discover。
返回: {boolean} 是否已开始
stopDiscovery()
用途: 停止端口扫描。
返回: {boolean}
discoveryState()
用途: 查看当前扫描结果。
返回: {object},含 pairDevices、connectDevices。每一项有 host、port、serviceType
waitDiscovery(wantPair, timeoutMs, pollMs)
用途: 等到扫描列表里出现配对端口或连接端口。wantPair 为 true 时等配对端口。
返回: {object}
waitPairingEndpoint(timeoutMs, pollMs)
用途: 等到出现配对端口。默认最多等 15 秒。
返回: {object}
waitConnectEndpoint(timeoutMs, pollMs)
用途: 等到出现连接端口。默认最多等 15 秒。自动扫描失败时,再用 手动配对 手填端口。
返回: {object}
通用执行
下面几个没有对应按钮或系统动作时再用。命令在 adbd 里执行,身份是 shell,读不了本 App 的私有目录。
shell(cmd)
用途: 执行一条 shell 命令,拿回它的输出。别名 exec、execute。
ok === true 表示命令已经执行完。命令自己打印的报错在 result / all 里,末尾通常带一个换行。
参数: cmd {string}
返回: {object} ok、code、result、error、all
let r = Adb.shell("pm list packages | grep deeke");
console.log(r.all);service(destination, writeUtf8, maxBytes)
用途: 打开一个原始 ADB 服务并读写。shell 不够用时用它,例如 tcp:、自定义 exec:。
参数:
destination {string}服务名,例如exec:cmd package list packages、tcp:8080writeUtf8 {string}可选,先写入再读maxBytes {number}最多读取字节,默认约 8MB
返回: {object},文本在 result
serviceBytes(destination, maxBytes)
用途: 和 service 一样打开服务,但返回原始字节。截图、二进制输出用这个。
参数:
destination {string}maxBytes {number}可选
返回: {object},字节在 data,长度在 bytes
open(destination)
用途: service 的简写,只打开服务并读取,不先写入。
返回: {object}
supportsFeature(feature)
用途: 粗略判断当前连接能不能执行 shell。它不是系统 feature 列表查询。
返回: {boolean}
文件与安装
shell 只能读写它有权限的路径,例如 /data/local/tmp 和 /sdcard 下的公共目录。本 App 私有目录用 Files,不要用 Adb.shell 去 cat。
push(localPath, remotePath)
用途: 把 App 能读到的本地文件推到设备路径。
参数: localPath {string}、remotePath {string}
返回: {object} 成功时带 size
pull(remotePath, localPath)
用途: 把设备上的文件拉到本地路径。别名 pullAndSave。
参数: remotePath {string}、localPath {string}
返回: {object} 成功时带 size
install(apkPath, ...options)
用途: 安装一个 apk。先推到 /data/local/tmp,再 pm install,装完删掉临时文件。别名 pushAndInstall。
参数:
apkPath {string}options {string}传给pm install的参数。常见的是"-r"覆盖安装、"-d"允许降级、"-g"安装时授权。其余参数以设备上pm install -h的输出为准,说明见 adb pm
返回: {object}
Adb.install("/sdcard/Download/app.apk", "-r");installMultiple(apkPaths)
用途: 按顺序安装多个 apk。其中一个失败就停。
参数: apkPaths {string[]}
返回: {object} 成功时带 count
uninstall(packageName)
用途: 卸载指定包名的应用。
参数: packageName {string}
返回: {object} 成功时 result 里通常是 Success 加一个换行
输入与按键
坐标原点在屏幕左上角,单位是像素。下面这些方法都是往系统注入一次输入。
tap(x, y)
用途: 点击屏幕上的一个点。
参数: x {number}、y {number}
返回: {object}
swipe(x1, y1, x2, y2, durationMs)
用途: 从一点直线滑到另一点。
参数: 起点、终点,durationMs 默认 300
返回: {object}
longPress(x, y, durationMs)
用途: 在一个点上按住不放。别名 press。
参数: durationMs 默认 800
返回: {object}
drag(x1, y1, x2, y2, durationMs)
用途: 按住并拖到另一点。默认时长 500 毫秒。
返回: {object}
keyEvent(codeOrName)
用途: 发送一个按键。别名 key。
参数:
亮屏、息屏、桌面、返回已经有 power()、wake()、sleep()、home()、back()。
返回: {object}
Adb.keyEvent("HOME");
Adb.keyEvent(4);text(value)
用途: 向当前焦点输入一段文字。别名 type。空字符串直接成功,不发命令。
可打印 ASCII(码点 32–126,含英文、数字和常见符号)走 input text,空格转成 %s。中文以及其它非该范围字符:先 clipPut 写入剪贴板,再执行 input keycombination 113 50(CTRL+V)。这条失败时再发按键码 279(KEYCODE_PASTE)。成功时返回对象可能带 via:clip+ctrlv 或 clip+paste。只想写剪贴板、自己决定何时粘贴时,用 clipPut。
参数: value {string}
返回: {object}
Adb.text("hello"); // input text
Adb.text("你好"); // ClipboardManager + CTRL+V,不行再 KEYCODE_PASTEclipPut(text)
用途: 把文字写入系统剪贴板,供随后粘贴。优先用本应用 ClipboardManager(返回里 via 为 ClipboardManager);失败再尝试把内容写到 /data/local/tmp 后执行 cmd clipboard set-text。
参数: text {string}
返回: {object}
power()
用途: 亮屏。点亮已经息屏的屏幕。
返回: {object}
Adb.power();wake()
用途: 亮屏。和 power() 一样,把屏幕点亮。
返回: {object}
sleep()
用途: 息屏。关掉屏幕。
返回: {object}
Adb.sleep();home()
用途: 按下 Home,回到桌面。
返回: {object}
back()
用途: 按下返回键,回到上一层。
返回: {object}
recents()
用途: 打开最近任务。
返回: {object}
volumeUp()
用途: 音量加。
返回: {object}
volumeDown()
用途: 音量减。
返回: {object}
mute()
用途: 静音。
返回: {object}
enter()
用途: 按下回车。
返回: {object}
del()
用途: 按下退格,删除光标前一个字符。
返回: {object}
menu()
用途: 按下菜单键。
返回: {object}
应用与系统
startApp(packageName, activity)
用途: 启动一个应用。
参数:
packageName {string}包名activity {string}可选。不填时用启动器入口拉起;填写时按组件名am start
返回: {object}
Adb.startApp("com.example.app");
Adb.startApp("com.example.app", ".MainActivity");forceStop(packageName)
用途: 强行停止一个应用。
参数: packageName {string}
返回: {object}
clearApp(packageName)
用途: 清空一个应用的数据,相当于设置里的「清除数据」。
参数: packageName {string}
返回: {object}
grant(packageName, permission)
用途: 授予一个运行时权限。
参数: 包名,以及权限名。运行时权限的完整名单见 Manifest.permission
返回: {object}
Adb.grant("com.example.app", "android.permission.CAMERA");revoke(packageName, permission)
用途: 撤销一个运行时权限。
参数: 包名、权限名。名单与 grant 相同,见 Manifest.permission
返回: {object}
listPackages(filter)
用途: 列出已安装包名。
参数: filter {string} 可选,原样传给 pm list packages。过滤项以设备上 pm list packages -h 为准,说明见 adb pm
返回: {object} 包名列表在 result
getProp(name)
用途: 读取一项系统属性。
参数: name {string}。这台设备上有哪些属性,用 Adb.shell("getprop") 列出来。
返回: {object} 值在 result
setProp(name, value)
用途: 写入一项系统属性。shell 身份写不了的属性会失败,看 result。
参数: name {string}、value {string}
返回: {object}
wmSize()
用途: 读取当前屏幕分辨率。
返回: {object} 文本在 result,例如 Physical size: 1080x2400
wmDensity()
用途: 读取当前屏幕密度。
返回: {object}
settingsGet(namespace, key)
用途: 读取一项系统设置。
参数: namespace 只有这三种:system、secure、global。key 分别查 Settings.System、Settings.Secure、Settings.Global
返回: {object} 值在 result
Adb.settingsGet("system", "screen_off_timeout");settingsPut(namespace, key, value)
用途: 写入一项系统设置。
参数: 命名空间、键、值。命名空间和键的范围与 settingsGet 相同。
返回: {object}
Adb.settingsPut("system", "screen_off_timeout", "300000");settingsDelete(namespace, key)
用途: 删除一项系统设置,让它回到默认值。
参数: 命名空间、键。范围与 settingsGet 相同。
返回: {object}
dumpsys(service)
用途: 导出一项系统服务的调试信息。
参数: service {string}。这台设备上有哪些服务,用 Adb.shell("dumpsys -l") 列出。
返回: {object} 文本在 result
activityTop()
用途: 查看当前回到前台的 Activity,用来判断现在停在哪个界面。
返回: {object}
currentFocus()
用途: 查看当前焦点窗口。
返回: {object}
broadcast(action, extras)
用途: 发送一条广播。
参数:
action {string}广播动作。系统自带动作见 Intentextras {string}可选,原样接在am broadcast -a后面
返回: {object}
reboot(mode)
用途: 重启设备。确认后再调用。
参数: mode 省略或 "normal" 是正常重启;"recovery" 进恢复模式;"bootloader" 或 "fastboot" 进 bootloader。其它字符串会原样接在 reboot 后面。
返回: {object}
screenshot(path)
用途: 截取当前屏幕,保存成 PNG 文件。别名 screencap。文件由本 App 写入,用 App 自己的目录即可,例如 Files.getFilesPath()。
参数: path {string} 保存路径
返回: {object} 成功时 ok === true,并带 path、size(字节数)
if (!Adb.isConnected()) {
Adb.connectSaved();
}
let path = Files.getFilesPath() + "/screen.png";
let shot = Adb.screenshot(path);
if (!shot.ok) {
console.log(shot.error);
} else {
console.log(shot.path, shot.size);
}screenshotBytes()
用途: 截取当前屏幕,直接返回 PNG 字节,不落文件。要自己决定存哪里时用它。
返回: {object} 成功时字节在 data,长度在 bytes
let shot = Adb.screenshotBytes();
if (shot.ok) {
let path = Files.getFilesPath() + "/screen.png";
Files.writeBytes(path, shot.data);
console.log(path, shot.bytes);
}waitForShell(command, expectContains, timeoutMs, intervalMs)
用途: 反复执行一条命令,直到输出里出现期望文字,或超时。用来等某个界面或状态出现。
参数:
command {string}expectContains {string}输出里要包含的文字timeoutMs {number}默认15000intervalMs {number}默认500
返回: {object} 等到时 matched === true
Adb.waitForShell("dumpsys window | grep mCurrentFocus", "com.example.app", 15000);root()
用途: 请求 adbd 以 root 重新运行。普通零售机通常会失败。调用后当前连接会断开,需要再 connectSaved()。
返回: {object}
unroot()
用途: 请求 adbd 退回非 root。调用后当前连接会断开。
返回: {object}
tcpForward(hostPort, targetPort)
用途: 预留的端口转发入口。当前只返回提示,设备侧要读某个 TCP 端口时用 service("tcp:端口")。
返回: {object}
Adb.service("tcp:8080");身份密钥
配对时用的 RSA 密钥存在 App 私有目录。清掉之后要重新配对。
ensureIdentity()
用途: 保证本机配对密钥和证书已经生成。
返回: {object} 含 fingerprintSha256、privateKeyPath、certificatePath
rotateIdentity()
用途: 换成一对新密钥,并断开当前连接。之后要重新 pairWithCode。
返回: {object}
clearIdentity()
用途: 删掉现有密钥并立刻重新生成一对,同时断开连接。之后要重新配对。
返回: {boolean}
keyFilePath()
用途: 读取私钥文件的路径。这个路径在 App 私有目录里,Adb.shell 读不到。
返回: {string}
localIpAddresses()
用途: 列出本机 IPv4。前面是局域网地址,最后一项是 127.0.0.1。连接时优先用局域网地址。
返回: {string[]}
help()
用途: 把方法列表逐行打到控制台。别名 methods。直接调用,不要再包一层 console.log。
返回: {string}
完整业务示例
首次引导 + 日常重连 + 自动化:
function ensureAdbConnected() {
if (!Adb.isSupported()) {
throw new Error("需要 Android 11+");
}
if (Adb.isConnected()) {
return;
}
let saved = Adb.connectSaved();
if (saved.ok) {
return;
}
let pairCode = App.notifyInput(
"无线调试配对",
"点「使用配对码配对设备」,再点通知「输入」回复 6 位码。不要回到本应用。",
"6 位配对码",
function () {
Adb.openWirelessDebuggingSettings();
}
);
if (!pairCode) {
throw new Error(saved.error || "已取消配对;自动扫描不到时可改试手动配对");
}
let c = Adb.pairWithCode(String(pairCode));
if (!c.ok) {
throw new Error(c.error || "配对失败");
}
}
ensureAdbConnected();
Adb.startApp("com.example.app");
System.sleep(2000);
Adb.tap(540, 1600);
Adb.text("hello");
Adb.enter();
let focus = Adb.currentFocus();
console.log(focus.all);与无障碍混用:节点查找仍用 UiSelector,Adb 只负责授权或兜底点击。
ensureAdbConnected();
Adb.grant(App.currentPackageName(), "android.permission.READ_EXTERNAL_STORAGE");
let btn = UiSelector().text("同意").findOne();
if (btn) {
btn.click();
} else {
Adb.tap(540, 1800);
}