screencap, touch, remote control for android devices via adb
Project description
说明
用于android设备远程实时控制的工具整合包。
- 封装了minicap 、 minicap_sdk32、 minitouch 、ADBKeyboard 的预编译包
- 支持多线程(threading)中资源自动分配,但应避免在多进程(multiprocessing)中使用
- 支持多设备连接
- 支持安卓设备的实时截图(延迟约30~40ms)
- 支持修改分辨率
- 支持监听屏幕旋转
- 支持监听输入框弹出
- 内置触控点坐标变换
- 支持中文输入
- 包含一个远程控制demo
- 支持安卓系统版本android<=12, sdk<=32
适用场景
- 有一定实时性要求的安卓游戏自动控制项目
- 需要从不同线程控制、获取屏幕内容的多线程项目
安装
pip install anhelper
Demo
运行demo需要确保已经通过adb连接安卓设备
anhelper-demo
已知问题
- 实体机上可能存在输入设备写入权限问题,导致minitouch无法运行。需要adb获取root权限。
- 部分机器需要手动在设置中开启ADBKeyboard并且手动切换输入法才可用。
用于安卓控制的同类开源项目推荐
在python项目中使用
Device
from anhelper import device
device.listDevices()
{'127.0.0.1:16416': ['device',
'product:SDY-AN00',
'model:SDY_AN00',
'device:SDY-AN00',
'transport_id:24'],
'127.0.0.1:21513': ['device',
'product:SM-S9010',
'model:SM_S9010',
'device:SM-S9010',
'transport_id:23']}
# 通过网络连接设备
device.connectDevice('127.0.0.1', port=16416)
True
device.listDevices()
{'127.0.0.1:16416': ['device',
'product:SDY-AN00',
'model:SDY_AN00',
'device:SDY-AN00',
'transport_id:24'],
'127.0.0.1:21513': ['device',
'product:SM-S9010',
'model:SM_S9010',
'device:SM-S9010',
'transport_id:23']}
# 获取adb连接的第一个设备
# getDevice已对多线程进行了优化,不同线程中调用不会重复构建实例
dev = device.getDevice()
# 检查是否处于输入法输入状态
dev.getIMEInputActive()
False
# 获取屏幕显示参数
dev.getWM()
{'width': 1280, 'height': 720, 'density': 240}
%%time
# 获取屏幕方向(顺时针旋转)
dev.getOrientation()
CPU times: total: 0 ns
Wall time: 86.9 ms
0
# 修改分辨率
dev.setWM(720, 1280, fit_orientation = True)
dev.getWM()
{'width': 1280, 'height': 720, 'density': 240}
dev.setWM(**device.CONST.TABLET_720P, fit_orientation = True)
dev.getWM()
{'width': 1280, 'height': 720, 'density': 240}
ime
from anhelper import ime
# 获取默认设备的ADBKeyboard输入法对象
mime = ime.getIME()
# 检查ADBKeyboard是否是默认输入法
mime.getSelected()
False
%%time
# 等待输入完成
mime.inputSafe('你好')
正在安装ADBkeyboard。。。ok
CPU times: total: 15.6 ms
Wall time: 540 ms
'Broadcasting: Intent { act=ADB_INPUT_B64 flg=0x400000 (has extras) }\r\nBroadcast completed: result=0'
%%time
# 输入且不等待完成
mime.input('你好')
CPU times: total: 15.6 ms
Wall time: 3.91 ms
<Popen: returncode: None args: 'adb -s 127.0.0.1:16416 shell "am broadcast -...>
## 多设备
mime2 = ime.getIME(list(device.listDevices().keys())[1])
mime2.input('再见')
<Popen: returncode: None args: 'adb -s 127.0.0.1:21513 shell "am broadcast -...>
Minicap
from anhelper import minicap
from anhelper.utils.visualizehelper import *
# 获取默认设备的minicap输入法对象
mcap = minicap.getMinicap()
# 截图默认返回cv2格式BGR矩阵
# sync=True 获取当前时间之后的第一帧
imat = mcap.cap(sync = True)
imshow(imat)
%%time
# 对于静态画面minicap不会发送新的帧,所以同步截图设置了1秒超时
imat = mcap.cap(sync=True)
CPU times: total: 15.6 ms
Wall time: 37.1 ms
%%time
# sync=False 跳过等待直接从缓存中取帧
imat = mcap.cap(sync=False)
CPU times: total: 15.6 ms
Wall time: 15.6 ms
# 用完记得关
mcap.close()
Minitouch
from anhelper import minitouch
import time
# 获取默认设备的minicap输入法对象
touch = minitouch.getMinitouch()
%%time
# 由于触控设备通常支持多个触控点,使用useContact()自动分配触控点,以避免冲突
# 所有的触控操作推荐使用比例坐标而非绝对坐标
# 比例坐标:x = 绝对坐标x/屏幕宽度, y=绝对坐标y/屏幕高度, 0 <= x,y <= 1
with touch.useContact() as c:
c.swipe(0.5,0.2, 0.5, 0.4, duration_ms=3000)
print(c.id)
with touch.useContact() as c:
print(c.id)
c.tap(1000, 500)
c.tap(0.5, 0.5)
正在部署minitouch。。。ok
9
8
CPU times: total: 78.1 ms
Wall time: 1.94 s
%%time
# 同一个触控点的操作会覆盖掉上一个操作未完成的部分
with touch.useContact() as c:
c.swipe(0.5,0.2, 0.5, 0.4, duration_ms=3000)
time.sleep(2)
print(c.inuse)
c.swipe(0.5,0.2, 0.5, 0.4, duration_ms=3000)
True
CPU times: total: 78.1 ms
Wall time: 2.01 s
%%time
with touch.useContact() as c:
c.swipe(0.5, 0.4, 0.5, 0.6, duration_ms=3000)
CPU times: total: 46.9 ms
Wall time: 53.7 ms
%%time
with touch.useContact() as c:
c.tap(0.9, 0.7)
CPU times: total: 0 ns
Wall time: 976 µs
# 绝对坐标也可以使用但不推荐,坐标原点为旋转后的屏幕左上角,与截图坐标一致
with touch.useContact() as c:
c.tap(700, 500)
# 用完记得关
touch.close()
WebUI(Demo)
from anhelper import webui
from IPython.display import IFrame
# 创建一个webui,绑定默认设备(连接的第一个),可以使用不同的device_id来绑定不同设备
# webui可以在网页中同步显示设备屏幕的内容
# divice_id 可以通过 device.listDevices()获取
ui = webui.WebUI(device_id=None)
ui.start()
# 检查webui是否正在运行
ui.is_alive()
True
IFrame( ui.url, width='100%',height='400px')
127.0.0.1 - - [29/Jul/2023 23:56:15] "GET / HTTP/1.1" 200 -
正在部署minicap。。。ok
127.0.0.1 - - [29/Jul/2023 23:56:16] "GET /video_feed HTTP/1.1" 200 -
ui2 = webui.WebUI(device_id=None, port=5001)
ui2.start()
ui2.is_alive()
True
IFrame( ui2.url, width='100%',height='400px')
127.0.0.1 - - [29/Jul/2023 23:56:20] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [29/Jul/2023 23:56:20] "GET /video_feed HTTP/1.1" 200 -
# 关闭webui
# 多个webui可以指向同一个设备,可以分别创建和关闭
ui2.stop()
ui.stop()
包含开源项目许可声明
None
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
anhelper-0.1.6.tar.gz
(6.3 MB
view details)
Built Distribution
File details
Details for the file anhelper-0.1.6.tar.gz
.
File metadata
- Download URL: anhelper-0.1.6.tar.gz
- Upload date:
- Size: 6.3 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.10.13
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | c72b4c3815e69215af678b7b318e9d78dcb451e6b17162028698e6d6c201df54 |
|
MD5 | d187d68ee21b4f113e423fddccb28160 |
|
BLAKE2b-256 | bbed7f47e69844ddca147eaac7829827cef91783f416ca812cfbf4f0e69dd6c4 |
File details
Details for the file anhelper-0.1.6-py3-none-any.whl
.
File metadata
- Download URL: anhelper-0.1.6-py3-none-any.whl
- Upload date:
- Size: 7.0 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.10.13
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | f1ec0381c8c2cc40bd9b44fc5c9dd640832cf75b5219d4e549919e9f981e68b4 |
|
MD5 | 8bba89f47404c708f334005fc1c0a572 |
|
BLAKE2b-256 | e23c2b5afe224b20be1768a995b8d9617ace31c6d0dc8dd282546dc769042477 |