更新记录

1.0.0(2026-07-10)

初版自用


平台兼容性

uni-app(5.0)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
- - - - - - 5.0 - -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - - -

uni-app x(5.0)

Chrome Safari Android iOS 鸿蒙 微信小程序
- - 5.0 - - -

其他

多语言 暗黑模式 宽屏模式
×

jiedead-adb

ADB 助手 UTS 插件 —— 让 uni-app (Vue3) 写的 App 成为"控制端",通过 ADB 控制另一台 Android 设备。

⚠️ 本插件只支持 App-Android 端(HBuilderX 3.6+ 编译为 Kotlin 运行)。Web / 小程序 / iOS 调用会直接 reject。


1. 功能一览

方法 用途
getDevices() 列出已连接设备(adb devices -l)
parseTcpTarget(serial) 解析 "ip:port" 形式 serial
connectDevice(host, port) adb connect
pairDevice(host, port, code) adb pair(Android 11+ 无线调试)
disconnectDevice(host, port) adb disconnect
exec(args, opts) 执行任意 adb 命令(args 数组形式)
shell(command, opts) 执行 device 端 shell 命令(自动 sh -c
installApp(apkPath, opts) adb install
uninstallApp(pkg, opts) adb uninstall
pushFile(local, remote, opts) adb push
pullFile(remote, local, opts) adb pull
startActivity(opts) adb shell am start
stopApp(pkg, opts) adb shell am force-stop
listPackages(thirdPartyOnly?, opts) adb shell pm list packages
getDeviceInfo(serial) 聚合 getprop + wm size/density
isAdbAvailable() 探测 adb 可执行文件是否存在
getAdbVersion() adb version

2. 目录结构

jiedead-adb/                          ← 独立项目(也可作为集成目标)
├─ manifest.json
├─ pages.json
├─ App.vue
├─ main.js
├─ index.html
├─ uni.scss
├─ pages/
│  └─ adb-shell/
│     └─ adb-shell.vue                 ← 示例页面
└─ uni_modules/
   └─ jiedead-adb/                    ← 插件本体
      ├─ package.json
      └─ utssdk/
         ├─ interface.uts               ← 对外 API 类型声明
         ├─ unierror.uts                ← 错误码
         ├─ index.uts                   ← 跨平台入口
         ├─ app-android/
         │  ├─ config.json
         │  ├─ AndroidManifest.xml
         │  └─ index.uts                ← Android 实现
         ├─ app-ios/
         │  └─ index.uts                ← iOS 占位
         └─ web/
            ├─ package.json
            └─ index.uts                ← Web 占位

3. 重要现实约束:adb 在哪?

adb 二进制不能从 npm 装,必须由你提供。两条路径:

方案 A:把 adb 打包到 App assets(推荐)

  1. 找一台装了 Android Studio / Platform Tools 的电脑,从以下位置复制 adb:
    • macOS: ~/Library/Android/sdk/platform-tools/adb
    • Linux: ~/Android/Sdk/platform-tools/adb
    • Windows: %LOCALAPPDATA%\Android\Sdk\platform-tools\adb.exe
  2. 在 HBuilderX 中右键 jiedead-adb/uni_modules/jiedead-adb/utssdk/app-android/ → 新建 assets/adb/<abi>/ 目录,把 adb 放进去。
  3. 至少为以下 ABI 放一个:arm64-v8a(必)、armeabi-v7a(选)、x86_64(模拟器)。

目录最终长这样:

utssdk/app-android/assets/adb/arm64-v8a/adb
utssdk/app-android/assets/adb/armeabi-v7a/adb   (可选)
utssdk/app-android/assets/adb/x86_64/adb        (可选)

插件会在首次调用时把 assets 里的 adb 解压到 filesDir/jiedead_adb/adb-<abi>/adb 并 chmod 755。

方案 B:依赖系统 PATH(仅模拟器/root 设备)

不打包 adb,依赖设备本身 adb(极少普通 App 能这么做,主要用于开发自测)。

调用方

import { adbCmd, installAdbFromAssets } from '@/uni_modules/jiedead-adb/utssdk/app-android/index.uts'

// App 启动时执行一次(建议放在 App.vue onLaunch)
const ok = installAdbFromAssets()
console.log('adb installed:', ok)

// 探测可用性
const version = await adbCmd.getAdbVersion()

4. 使用示例

import { adbCmd } from '@/uni_modules/jiedead-adb/utssdk/app-android/index.uts'

// 列出设备
const devs = await adbCmd.getDevices()
// [{ serial: '192.168.1.10:5555', state: 'device', model: 'Pixel 6', ... }]

// 无线配对
await adbCmd.pairDevice('192.168.1.10', 37123, '123456')
// 连接
await adbCmd.connectDevice('192.168.1.10', 5555)

// 执行任意 adb 命令
const r = await adbCmd.exec(['shell', 'getprop', 'ro.build.version.sdk'], {
  serial: '192.168.1.10:5555'
})
console.log(r.exitCode, r.stdout)
// 1, 33

// 执行 shell 命令(自动 sh -c 包装,支持空格/管道)
const r2 = await adbCmd.shell('pm list packages -3 | grep example', {
  serial: '192.168.1.10:5555'
})

// 安装 APK
await adbCmd.installApp('/data/user/0/com.your.app/files/app.apk', {
  serial: '192.168.1.10:5555',
  replace: true,
  grantPermissions: true
})

// 启动 Activity
await adbCmd.startActivity({
  serial: '192.168.1.10:5555',
  component: 'com.example.app/.MainActivity',
  action: 'android.intent.action.VIEW',
  data: 'myapp://route/page?id=1',
  extras: { from: 'adb-shell' },
  wait: true
})

// 设备信息
const info = await adbCmd.getDeviceInfo('192.168.1.10:5555')
// { serial, state, model, manufacturer, brand, androidRelease, sdk, abi, screenSize, density }

5. 错误码

code 含义
1000 未知错误
1001 adb 可执行文件未找到
1002 adb 进程启动失败
1003 adb 命令超时
1004 adb 命令被中断(保留位)
1005 参数非法(含白名单外的字符)
1006 设备 offline / unauthorized(语义保留)
1007 文件 IO 错误
1008 APK 路径不可读
1009 shell 命令解析失败
1010 用户拒绝授权

AdbError 实例带 code 字段和 cause 字段:

try {
  await adbCmd.installApp('/bad path.apk')
} catch (e) {
  console.log(e.code)    // 1005
  console.log(e.message) // 'apkPath 含非法字符...'
}

6. 限制与安全提示

⚠️ 重要 —— 本插件仅用于受控环境(自研运维工具/测试平台)。

  • serial / 文件路径只接受 [A-Za-z0-9._:\-\/],白名单外字符会被拒绝(防 shell 注入)。
  • 大文件 install / push 仍可能受 OS 管道 buffer 影响,已用后台 drainer 线程缓解但不能完全消除。
  • adb shellsh -c 包装,前端传入的命令会原样下发给 device 端 shell。
  • adb 本身是 Android 工具,不能跨平台控制 iOS
  • App 本身也是 Android 设备adb devices 列出的是"另一台"的 serial,不包括自己。

7. 集成到现有项目

uni_modules/jiedead-adb/ 整个目录复制到目标项目的 uni_modules/ 下即可:

cp -r /Users/mac/work/dev/jiedead-adb/uni_modules/jiedead-adb \
      /Users/mac/work/dev/dev_uniapp/uni_modules/

然后在需要使用的页面:

import { adbCmd } from '@/uni_modules/jiedead-adb/utssdk/app-android/index.uts'

HBuilderX 会自动识别并把插件代码编入 App 包。第一次编译必须使用「自定义基座」(manifest.json 改了权限 / uts 插件需要自定义基座才能生效),菜单:运行 → 运行到手机或模拟器 → 制作自定义调试基座

8. 调试

  • 编译期:HBuilderX 控制台会显示 UTS 编译错误。常见的:
    • uts.sdk.modules.jiedeadAdb 包名与 package.jsonid 驼峰不一致 → 改 id 后重置基座。
    • 找不到 BufferedReader → 检查 import java.io.BufferedReader 是否有。
  • 运行期:把日志打出来
    const r = await adbCmd.shell('getprop ro.build.version.sdk', { serial: 'xxx' })
    console.log('cmd:', r.command, 'exit:', r.exitCode, 'stdout:', r.stdout, 'stderr:', r.stderr)
  • adb 卡住:八成是 OS 管道 buffer 满 / 目标 device offline / USB 断开。先确认 adb -s <serial> shell echo ok 在控制端 PC 上能跑通。

9. 版本

  • 0.1.0 初始版本:支持 adb devices / connect / pair / shell / install / uninstall / push / pull / am start / pm list / getprop

隐私、权限声明

1. 本插件需要申请的系统权限列表:

"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>", "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>", "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>", "<uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>", "<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。