Skip to content

armjukl/python_fake_adb_devices

Repository files navigation

fake-adb-device

fake-adb-device 是一个最小化的本地 ADB 设备服务端。它不依赖浏览器、MaaCore 或具体游戏,只把 ADB 的截图、点击和拖动请求转交给调用方提供的回调。

打个比方,fake-adb-devices 就像 “用遥控器操控电视时”,它假装成电视,接受遥控器的指令拿去自己用,并给遥控器希望得到的响应。

应用案例maaframework接入

实现原理

详情参考技术实现细节 先用真实adb.exe启动服务器 由这个真daemon 注册为一台网络设备。因此任意兼容 ADB 的客户端都能通过常规 adb connectadb shelladb exec-out 命令访问它。但因adb特性断连后注册就失效了,客户端将无法再次连接设备,所以我们还提供定时掉线检查,一旦掉线可自动再次注册,方便重新连接 D9mDKNOWvKbyuZU77Y8KSbF8yTWsehGj.webp NEHEK6sXub4G15eO3mpDj3O2ETfOnhCO.webp pI8sWfwi6GKVc9PCVzXXaVMdhnF6C5U0.webp 启动器会在终端输出所有客户端请求,包括成功的 shell/exec 命令、未知命令、未实现服务、格式错误的 input 命令与 Sync 文件操作。未知或错误请求会获得兼容的空响应或失败响应,不会令伪设备服务崩溃。

适用场景

  • 为自动化引擎提供伪装 Android 设备。
  • 将 ADB 输入桥接到浏览器、桌面程序、远程画面或测试夹具。
  • 在不启动 Android 模拟器的情况下测试 ADB 客户端的探测与输入流程。

快速启动

直接运行伪设备不需要安装任何 Python 包。Windows 下双击 启动伪设备.bat,或在项目目录执行:

python run.py

它会使用项目内的 platform-tools/adb.exe,启动真实 ADB daemon,并自动连接 127.0.0.1:5555。未指定截图时,screencap 返回内置的 1280 x 720 黑色 PNG,仅用于验证 ADB 协议和输入回调:

python run.py --screenshot .\screen.png

将实际 PNG 路径传入 --screenshot 后,每次截图请求都会读取该文件。输入命令会打印在启动窗口中;浏览器、桌面程序等宿主集成应使用下文的 Python API。

环境变量

以下环境变量均默认关闭:

环境变量 默认值 作用
FAKE_ADB_DEVICE_ALLOW_LAN 0 设为 1trueyeson 时,默认监听 0.0.0.0,允许局域网客户端连接。
FAKE_ADB_DEVICE_RECONNECT_INTERVAL 0 掉线检查间隔,单位秒。0 表示禁用;大于 0 时仅在设备从 adb devices 消失后重连。
FAKE_ADB_DEVICE_PORT 5555 伪设备监听端口。
FAKE_ADB_DEVICE_ADB_DAEMON_PORT 5037 本机 ADB daemon 端口,伪设备调用的 adb start-serverconnectdevices 均使用此端口。

PowerShell 示例:

$env:FAKE_ADB_DEVICE_ALLOW_LAN = "1"
$env:FAKE_ADB_DEVICE_RECONNECT_INTERVAL = "2"
$env:FAKE_ADB_DEVICE_PORT = "5555"
$env:FAKE_ADB_DEVICE_ADB_DAEMON_PORT = "5037"
python run.py

命令行参数优先于环境变量:--allow-lan / --no-allow-lan 覆盖局域网设置,--reconnect-interval 0 可明确禁用掉线检查,--port--adb-daemon-port 分别覆盖两个端口。局域网模式没有 ADB 身份认证,仅应在受信任网络中使用。

Linux 一键脚本

Linux 下先执行:

chmod +x 安装依赖.sh 启动伪设备.sh
./安装依赖.sh
./启动伪设备.sh

安装依赖.sh 支持 apt、dnf 和 pacman,会安装 python3adb启动伪设备.sh 顶部集中定义 ADB_PATH、设备端口、ADB daemon 端口、局域网开关和掉线检查间隔;直接编辑这些变量即可更改配置。命令行额外参数仍会传递给 run.py

设备端口

默认伪设备地址是 127.0.0.1:5555。端口被占用时可以指定另一个端口,启动器会自动使用该地址执行 adb connect

.\启动伪设备.bat --port 5556

之后所有 ADB 命令都应指定相同地址:

.\platform-tools\adb.exe -s 127.0.0.1:5556 shell wm size

传入 --port 0 会由系统分配空闲端口,启动窗口会打印实际地址。该端口是伪设备端口;真实 ADB daemon 默认监听本机 5037,可通过 FAKE_ADB_DEVICE_ADB_DAEMON_PORT--adb-daemon-port 修改。外部 ADB 客户端使用自定义 daemon 端口时,应添加 -P <端口>

让手机 ADB 客户端连接

默认只监听 127.0.0.1,手机无法访问。仅在受信任的同一局域网内测试时,使用:

.\启动伪设备.bat --host 0.0.0.0 --allow-lan --port 5555
ipconfig

ipconfig 找到电脑的 IPv4 地址,例如 192.168.1.10。手机上的 ADB 客户端应连接 192.168.1.10:5555,而不是 127.0.0.1:5555。本机 daemon 仍会自动通过 127.0.0.1:5555 注册该伪设备。

若手机连接超时,检查两台设备是否在同一 Wi-Fi,并允许 Windows 防火墙入站 TCP 5555。需要时在管理员 PowerShell 中添加临时规则:

New-NetFirewallRule -DisplayName "fake-adb-device test" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 5555

伪设备没有 ADB 认证;局域网内任何能访问该端口的设备都可发起截图和输入命令。测试结束后按 Ctrl+C 停止服务,并删除临时防火墙规则:

Remove-NetFirewallRule -DisplayName "fake-adb-device test"

嵌入其他 Python 程序时,才需要以可编辑模式安装:

pip install -e .

推荐用法

from pathlib import Path

from fake_adb_device import AdbDeviceSession, CallbackBackend


def get_screenshot() -> bytes:
    return Path("screen.png").read_bytes()


def handle_input(action):
    print(action)


backend = CallbackBackend(get_screenshot, handle_input)
with AdbDeviceSession(backend, adb_path="platform-tools/adb.exe") as device:
    print(f"伪设备已连接: {device.address}")
    input("按 Enter 断开设备\n")

AdbDeviceSession.start() 的顺序固定为:

启动 FakeAdbServer
    -> 等待端口开始监听
    -> adb start-server
    -> adb connect 127.0.0.1:5555

随后可从任意终端使用标准 ADB 命令:

.\platform-tools\adb.exe devices
.\platform-tools\adb.exe -s 127.0.0.1:5555 shell wm size
.\platform-tools\adb.exe -s 127.0.0.1:5555 shell input tap 640 360
.\platform-tools\adb.exe -s 127.0.0.1:5555 shell input swipe 640 600 640 200 500
cmd /c ".\platform-tools\adb.exe -s 127.0.0.1:5555 exec-out screencap -p > screen.png"
Start-Process .\screen.png

screencap -p 的标准输出是 PNG 二进制,不能直接在终端显示。Windows PowerShell 应通过上面的 cmd /c 重定向保存,避免二进制被文本编码破坏。伪设备启动窗口会显示每次截图返回的来源和字节数。

close() 仅对该地址执行 adb disconnect 并停止伪设备,不会关闭可能被其他设备共享的 adb daemon。

底层用法

只需要 ADB 协议服务端、且想自行管理 daemon 时,仍可直接使用 FakeAdbServer

server = FakeAdbServer(backend, host="127.0.0.1", port=5555)
server.serve_forever()

开发帮助

项目结构

fake-adb-device/
|-- run.py                         # 免安装启动器,提供黑图或静态 PNG 回调
|-- 启动伪设备.bat                   # Windows 启动入口
|-- platform-tools/                 # 精简的 adb.exe 运行时
|-- src/fake_adb_device/
|   |-- backend.py                  # 截图和输入回调接口
|   |-- server.py                   # 简化 adbd 协议与命令分发
|   `-- session.py                  # adb daemon、connect、disconnect 生命周期
`-- README.md

修改截图来源

无需修改代码时,启动器会在每次截图请求时读取 --screenshot 指定的文件;外部程序覆盖该 PNG 文件后,下一次 screencap 会返回新内容。

宿主程序集成时,修改或替换 CallbackBackend 的第一个回调即可。回调必须返回非空的 PNG bytes,并且图片尺寸应和 AdbDeviceSession(..., width=..., height=...) 一致:

def get_screenshot() -> bytes:
    return current_png_bytes

backend = CallbackBackend(get_screenshot, handle_input)

接入 Playwright、Qt 等线程敏感的界面框架时,ADB 服务线程不能直接调用页面或界面对象。应由界面所属线程定时刷新 current_png_bytes,截图回调只读取加锁后的缓存;输入回调则把 InputAction 放入队列,再由界面所属线程处理。

处理点击与滑动

input tap x yinput swipe x1 y1 x2 y2 duration 会分别转换为 InputAction("tap", ...)InputAction("swipe", ...),传入 CallbackBackend 的第二个回调:

def handle_input(action: InputAction) -> None:
    if action.kind == "tap":
        input_queue.put(action)
    elif action.kind == "swipe":
        input_queue.put(action)

坐标与 widthheight 所报告的设备尺寸属于同一坐标系。宿主画面尺寸不同时,应在消费队列时自行缩放坐标。

增加 ADB 命令

常见 shell 和 exec 请求由 FakeAdbServer.execute_command() 处理,输入命令由 _dispatch_input() 转换。新增设备探测响应或宿主能力时:

  1. execute_command() 识别新的命令字符串并返回正确的字节响应。
  2. 若需要向宿主请求数据,在 DeviceBackend 增加方法并同步实现 CallbackBackend
  3. 保持 shell:exec:exec-out: 三种 ADB 通道的输出均为原始字节。
  4. 使用 run.pyadb.exe -s <地址> shell <命令> 手工验证。

不要为了普通 ADB 命令修改 AdbDeviceSession;它只负责启动监听器、启动真实 daemon、连接设备和关闭时断开设备。

设计

ADB 客户端 -> adb daemon -> FakeAdbServer -> DeviceBackend -> 宿主程序回调
  • FakeAdbServer 解析简化的 ADB 传输协议,并模拟常见设备探测命令。
  • AdbDeviceSession 管理伪设备监听、adb start-serveradb connect 和定向断开。
  • DeviceBackend 是截图和输入的协议接口。
  • CallbackBackend 将接口适配为两个普通 Python 回调。
  • 输入回调接收 InputAction,由宿主程序决定在何处、以何种线程模型执行。

服务仅绑定本地地址时使用。它关闭 ADB 鉴权并只实现最小命令集,不应暴露到局域网或公网。

支持范围

支持 CNXNOPENWRTECLSE 以及 shell:exec:exec-out: 通道中的常见命令:设备属性、wm sizescreencapinput tapinput swipeinput keyeventinput textpm patham startmonkey -p。同时支持 MaaFramework 需要的持续 shell cat 监视连接,以及可安全失败的 sync: 文件操作。

它不是完整 adbd 实现,不提供安装 APK、文件同步、端口转发或认证服务。

About

一个模拟adb设备的python脚本,可接收adb相关命令并自行调用,并响应adb客户端希望接受的内容

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages