yyds-auto 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- yyds_auto-1.0.0/.gitignore +88 -0
- yyds_auto-1.0.0/LICENSE +21 -0
- yyds_auto-1.0.0/PKG-INFO +493 -0
- yyds_auto-1.0.0/README.md +449 -0
- yyds_auto-1.0.0/pyproject.toml +55 -0
- yyds_auto-1.0.0/yyds_auto/__init__.py +162 -0
- yyds_auto-1.0.0/yyds_auto/__main__.py +184 -0
- yyds_auto-1.0.0/yyds_auto/adb.py +211 -0
- yyds_auto-1.0.0/yyds_auto/assets/.gitkeep +1 -0
- yyds_auto-1.0.0/yyds_auto/client.py +138 -0
- yyds_auto-1.0.0/yyds_auto/device.py +159 -0
- yyds_auto-1.0.0/yyds_auto/discover.py +220 -0
- yyds_auto-1.0.0/yyds_auto/exceptions.py +60 -0
- yyds_auto-1.0.0/yyds_auto/mixins/__init__.py +1 -0
- yyds_auto-1.0.0/yyds_auto/mixins/app.py +114 -0
- yyds_auto-1.0.0/yyds_auto/mixins/device_info.py +129 -0
- yyds_auto-1.0.0/yyds_auto/mixins/file.py +122 -0
- yyds_auto-1.0.0/yyds_auto/mixins/input.py +99 -0
- yyds_auto-1.0.0/yyds_auto/mixins/ocr.py +225 -0
- yyds_auto-1.0.0/yyds_auto/mixins/project.py +59 -0
- yyds_auto-1.0.0/yyds_auto/mixins/screen.py +181 -0
- yyds_auto-1.0.0/yyds_auto/mixins/shell.py +48 -0
- yyds_auto-1.0.0/yyds_auto/mixins/touch.py +142 -0
- yyds_auto-1.0.0/yyds_auto/selector.py +260 -0
- yyds_auto-1.0.0/yyds_auto/setup.py +148 -0
- yyds_auto-1.0.0/yyds_auto/types.py +109 -0
- yyds_auto-1.0.0/yyds_auto/version.py +1 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# =========================
|
|
2
|
+
# IDEs and Editors
|
|
3
|
+
# =========================
|
|
4
|
+
.idea/
|
|
5
|
+
.vscode/
|
|
6
|
+
*.iml
|
|
7
|
+
*.swp
|
|
8
|
+
|
|
9
|
+
# =========================
|
|
10
|
+
# Node.js / TypeScript Projects
|
|
11
|
+
# =========================
|
|
12
|
+
node_modules/
|
|
13
|
+
dist/
|
|
14
|
+
out/
|
|
15
|
+
*.vsix
|
|
16
|
+
npm-debug.log*
|
|
17
|
+
yarn-debug.log*
|
|
18
|
+
yarn-error.log*
|
|
19
|
+
package-lock.json
|
|
20
|
+
yarn.lock
|
|
21
|
+
|
|
22
|
+
# =========================
|
|
23
|
+
# Android / Gradle
|
|
24
|
+
# =========================
|
|
25
|
+
.gradle/
|
|
26
|
+
local.properties
|
|
27
|
+
/yyds-android/app/build/
|
|
28
|
+
/yyds-android/build/
|
|
29
|
+
.cxx/
|
|
30
|
+
captures/
|
|
31
|
+
*.apk
|
|
32
|
+
*.ap_
|
|
33
|
+
|
|
34
|
+
# =========================
|
|
35
|
+
# Python
|
|
36
|
+
# =========================
|
|
37
|
+
__pycache__/
|
|
38
|
+
*.py[cod]
|
|
39
|
+
*$py.class
|
|
40
|
+
*.so
|
|
41
|
+
build/
|
|
42
|
+
develop-eggs/
|
|
43
|
+
dist/
|
|
44
|
+
downloads/
|
|
45
|
+
eggs/
|
|
46
|
+
.eggs/
|
|
47
|
+
lib/
|
|
48
|
+
lib64/
|
|
49
|
+
parts/
|
|
50
|
+
sdist/
|
|
51
|
+
var/
|
|
52
|
+
wheels/
|
|
53
|
+
*.egg-info/
|
|
54
|
+
.installed.cfg
|
|
55
|
+
*.egg
|
|
56
|
+
.pytest_cache/
|
|
57
|
+
.coverage
|
|
58
|
+
htmlcov/
|
|
59
|
+
.tox/
|
|
60
|
+
.nox/
|
|
61
|
+
.venv/
|
|
62
|
+
venv/
|
|
63
|
+
ENV/
|
|
64
|
+
env.bak/
|
|
65
|
+
venv.bak/
|
|
66
|
+
|
|
67
|
+
# =========================
|
|
68
|
+
# Rust
|
|
69
|
+
# =========================
|
|
70
|
+
target/
|
|
71
|
+
**/*.rs.bk
|
|
72
|
+
|
|
73
|
+
# =========================
|
|
74
|
+
# OS generated files
|
|
75
|
+
# =========================
|
|
76
|
+
.DS_Store
|
|
77
|
+
.DS_Store?
|
|
78
|
+
._*
|
|
79
|
+
.Spotlight-V100
|
|
80
|
+
.Trashes
|
|
81
|
+
ehthumbs.db
|
|
82
|
+
Thumbs.db
|
|
83
|
+
|
|
84
|
+
# Publish Script (Private)
|
|
85
|
+
build_and_release.py
|
|
86
|
+
|
|
87
|
+
# Internal / Private
|
|
88
|
+
yyds-con/
|
yyds_auto-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Yyds Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
yyds_auto-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: yyds-auto
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Android RPA automation library — control your Android phone from Python, like uiautomator2
|
|
5
|
+
Project-URL: Homepage, https://yydsxx.com
|
|
6
|
+
Project-URL: Documentation, https://yydsxx.com/docs
|
|
7
|
+
Project-URL: Repository, https://github.com/ChenAnZong/AndroidRPA
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/ChenAnZong/AndroidRPA/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/ChenAnZong/AndroidRPA/releases
|
|
10
|
+
Author-email: Yyds Team <support@yydsxx.com>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: adb,android,appium,automation,mobile,rpa,uiautomator
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
26
|
+
Classifier: Topic :: Software Development :: Testing
|
|
27
|
+
Classifier: Topic :: System :: Monitoring
|
|
28
|
+
Requires-Python: >=3.8
|
|
29
|
+
Requires-Dist: requests>=2.28
|
|
30
|
+
Provides-Extra: adb
|
|
31
|
+
Requires-Dist: adbutils>=2.0; extra == 'adb'
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: build; extra == 'dev'
|
|
34
|
+
Requires-Dist: mypy; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
36
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
37
|
+
Requires-Dist: twine; extra == 'dev'
|
|
38
|
+
Provides-Extra: full
|
|
39
|
+
Requires-Dist: adbutils>=2.0; extra == 'full'
|
|
40
|
+
Requires-Dist: pillow>=9.0; extra == 'full'
|
|
41
|
+
Provides-Extra: pillow
|
|
42
|
+
Requires-Dist: pillow>=9.0; extra == 'pillow'
|
|
43
|
+
Description-Content-Type: text/markdown
|
|
44
|
+
|
|
45
|
+
# yyds-auto
|
|
46
|
+
|
|
47
|
+
[](https://pypi.org/project/yyds-auto/)
|
|
48
|
+
[](https://pypi.org/project/yyds-auto/)
|
|
49
|
+
[](https://opensource.org/licenses/MIT)
|
|
50
|
+
|
|
51
|
+
Android RPA 自动化库 — 从 PC 端 Python 控制 Android 设备。
|
|
52
|
+
|
|
53
|
+
类似 [uiautomator2](https://github.com/openatx/uiautomator2),但集成了 OCR、图像识别、脚本项目管理等更多能力。
|
|
54
|
+
|
|
55
|
+
## 特性
|
|
56
|
+
|
|
57
|
+
- **多种连接方式** — USB 自动连接 / 指定序列号 / WiFi IP 直连 / 局域网自动扫描
|
|
58
|
+
- **uiautomator2 风格 API** — `d.click()`, `d(text="X").click()`, `d.screenshot()` 零学习成本
|
|
59
|
+
- **元素选择器** — 支持 text / resourceId / className / description 等多种定位方式
|
|
60
|
+
- **OCR 识别** — 内置 OCR 能力,`d.ocr_click("确认")` 一行搞定文字点击
|
|
61
|
+
- **图像识别** — 模板匹配、像素取色
|
|
62
|
+
- **Shell 命令** — ROOT/SHELL 权限执行,`d.shell("ls /sdcard")`
|
|
63
|
+
- **文件管理** — push / pull / 读写 / 列目录 / 删除
|
|
64
|
+
- **应用管理** — 启动 / 停止 / 安装 / 卸载 / 列表
|
|
65
|
+
- **脚本项目** — 远程管理设备上的 Python 脚本项目
|
|
66
|
+
- **CLI 工具** — 命令行快速操作:截图、Shell、设备扫描、环境诊断
|
|
67
|
+
- **自动初始化** — 自动检测 APK 安装状态,自动启动引擎
|
|
68
|
+
|
|
69
|
+
## 安装
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pip install yyds-auto
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 前置条件
|
|
76
|
+
|
|
77
|
+
1. Android 设备已开启 USB 调试(或 WiFi 调试)
|
|
78
|
+
2. 设备已安装 yyds.auto App
|
|
79
|
+
3. PC 已安装 [ADB](https://developer.android.com/tools/releases/platform-tools)(USB 连接时需要)
|
|
80
|
+
|
|
81
|
+
> WiFi 直连模式下只需设备已启动 yyds.auto 引擎,无需 ADB。
|
|
82
|
+
|
|
83
|
+
## 快速开始
|
|
84
|
+
|
|
85
|
+
### 连接设备
|
|
86
|
+
|
|
87
|
+
由于 \`yyds-auto\` 支持在 **PC 端调试** 以及 **直接在 Android 设备端运行**,推荐使用以下区分逻辑来初始化设备连接:
|
|
88
|
+
|
|
89
|
+
\`\`\`python
|
|
90
|
+
import os
|
|
91
|
+
import yyds_auto
|
|
92
|
+
|
|
93
|
+
# 区分两套运行方式
|
|
94
|
+
if os.path.exists("/sdcard"):
|
|
95
|
+
# Android 端运行: 直连本地引擎
|
|
96
|
+
d = yyds_auto.connect("127.0.0.1:61140")
|
|
97
|
+
else:
|
|
98
|
+
# PC 端运行: 自动连接手机
|
|
99
|
+
# 可直接使用 yyds_auto.connect() 自动查找 USB 或默认设备
|
|
100
|
+
d = yyds_auto.connect()
|
|
101
|
+
|
|
102
|
+
# 或者指定连接:
|
|
103
|
+
# d = yyds_auto.connect("HJR5T19A28007194") # 指定 USB 序列号
|
|
104
|
+
# d = yyds_auto.connect("192.168.1.5") # WiFi IP 直连
|
|
105
|
+
# d = yyds_auto.connect("192.168.1.5:61140") # WiFi IP + 自定义端口
|
|
106
|
+
#
|
|
107
|
+
# 也可以使用局域网自动发现:
|
|
108
|
+
# devices = yyds_auto.discover()
|
|
109
|
+
# d = devices[0].connect()
|
|
110
|
+
\`\`\`
|
|
111
|
+
|
|
112
|
+
### 设备信息
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
# 基础信息
|
|
116
|
+
print(d.info)
|
|
117
|
+
|
|
118
|
+
# 详细硬件信息
|
|
119
|
+
info = d.device_info
|
|
120
|
+
print(f"型号: {info.model}")
|
|
121
|
+
print(f"品牌: {info.brand}")
|
|
122
|
+
print(f"Android: {info.android_version}")
|
|
123
|
+
print(f"分辨率: {info.display_width}x{info.display_height}")
|
|
124
|
+
print(f"IP: {info.wlan_ip}")
|
|
125
|
+
|
|
126
|
+
# 屏幕尺寸
|
|
127
|
+
w, h = d.window_size()
|
|
128
|
+
|
|
129
|
+
# 连接状态
|
|
130
|
+
print(d.alive())
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### 截图
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
# 截图并保存
|
|
137
|
+
d.screenshot("screen.png")
|
|
138
|
+
|
|
139
|
+
# 获取 PIL Image 对象
|
|
140
|
+
img = d.screenshot()
|
|
141
|
+
img.show()
|
|
142
|
+
|
|
143
|
+
# 指定质量
|
|
144
|
+
img = d.screenshot(quality=50)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 触控操作
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
# 点击
|
|
151
|
+
d.click(500, 800)
|
|
152
|
+
|
|
153
|
+
# 双击
|
|
154
|
+
d.double_click(500, 800)
|
|
155
|
+
|
|
156
|
+
# 长按
|
|
157
|
+
d.long_click(500, 800, duration=1.0)
|
|
158
|
+
|
|
159
|
+
# 滑动
|
|
160
|
+
d.swipe(500, 1500, 500, 500, duration=0.5)
|
|
161
|
+
|
|
162
|
+
# 方向滑动
|
|
163
|
+
d.swipe_ext("up") # 上滑
|
|
164
|
+
d.swipe_ext("down") # 下滑
|
|
165
|
+
d.swipe_ext("left") # 左滑
|
|
166
|
+
d.swipe_ext("right") # 右滑
|
|
167
|
+
|
|
168
|
+
# 拖拽
|
|
169
|
+
d.drag(100, 200, 300, 400)
|
|
170
|
+
|
|
171
|
+
# 底层触控链
|
|
172
|
+
d.touch.down(500, 500).sleep(0.5).move(500, 300).up()
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### 按键与输入
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
# 按键
|
|
179
|
+
d.press("home")
|
|
180
|
+
d.press("back")
|
|
181
|
+
d.press("enter")
|
|
182
|
+
d.press("volume_up")
|
|
183
|
+
d.press("power")
|
|
184
|
+
d.press("recent") # 最近任务
|
|
185
|
+
|
|
186
|
+
# 文本输入
|
|
187
|
+
d.send_keys("hello world")
|
|
188
|
+
|
|
189
|
+
# 清空后输入
|
|
190
|
+
d.send_keys("new text", clear=True)
|
|
191
|
+
|
|
192
|
+
# 剪贴板
|
|
193
|
+
d.set_clipboard("copied text")
|
|
194
|
+
print(d.clipboard)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### 屏幕控制
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
# 亮屏 / 熄屏
|
|
201
|
+
d.screen_on()
|
|
202
|
+
d.screen_off()
|
|
203
|
+
|
|
204
|
+
# 屏幕方向
|
|
205
|
+
print(d.orientation) # 0=竖屏, 1=横屏左, 2=倒屏, 3=横屏右
|
|
206
|
+
|
|
207
|
+
# 冻结旋转
|
|
208
|
+
d.freeze_rotation(True)
|
|
209
|
+
d.freeze_rotation(False)
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### 元素选择器
|
|
213
|
+
|
|
214
|
+
yyds-auto 支持类似 uiautomator2 的元素选择器语法:
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
# 通过文本查找
|
|
218
|
+
d(text="Settings").click()
|
|
219
|
+
|
|
220
|
+
# 通过 resourceId
|
|
221
|
+
d(resourceId="com.example:id/btn").click()
|
|
222
|
+
|
|
223
|
+
# 通过 className
|
|
224
|
+
d(className="android.widget.EditText").set_text("hello")
|
|
225
|
+
|
|
226
|
+
# 组合条件
|
|
227
|
+
d(text="OK", clickable=True).click()
|
|
228
|
+
|
|
229
|
+
# 等待元素出现
|
|
230
|
+
d(text="Loading").wait_gone(timeout=15)
|
|
231
|
+
d(text="Done").wait(timeout=10)
|
|
232
|
+
|
|
233
|
+
# 检查元素是否存在
|
|
234
|
+
if d(text="Error").exists:
|
|
235
|
+
print("出错了")
|
|
236
|
+
|
|
237
|
+
# 获取元素信息
|
|
238
|
+
elem = d(resourceId="com.example:id/title")
|
|
239
|
+
print(elem.text)
|
|
240
|
+
print(elem.bounds) # (left, top, right, bottom)
|
|
241
|
+
print(elem.center) # (x, y)
|
|
242
|
+
|
|
243
|
+
# 文本操作
|
|
244
|
+
d(className="android.widget.EditText").set_text("hello")
|
|
245
|
+
d(className="android.widget.EditText").clear_text()
|
|
246
|
+
|
|
247
|
+
# 滚动查找
|
|
248
|
+
d(scrollable=True).scroll_to(text="Target Item")
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
支持的选择器属性:
|
|
252
|
+
|
|
253
|
+
| 属性 | 说明 | 示例 |
|
|
254
|
+
|------|------|------|
|
|
255
|
+
| `text` | 精确文本 | `d(text="OK")` |
|
|
256
|
+
| `textContains` | 包含文本 | `d(textContains="设置")` |
|
|
257
|
+
| `textStartsWith` | 文本前缀 | `d(textStartsWith="第")` |
|
|
258
|
+
| `textMatches` | 正则匹配 | `d(textMatches="\\d+")` |
|
|
259
|
+
| `resourceId` | 资源 ID | `d(resourceId="com.example:id/btn")` |
|
|
260
|
+
| `className` | 类名 | `d(className="android.widget.Button")` |
|
|
261
|
+
| `description` | 描述文本 | `d(description="返回")` |
|
|
262
|
+
| `clickable` | 可点击 | `d(clickable=True)` |
|
|
263
|
+
| `scrollable` | 可滚动 | `d(scrollable=True)` |
|
|
264
|
+
| `enabled` | 已启用 | `d(enabled=True)` |
|
|
265
|
+
| `checked` | 已选中 | `d(checked=True)` |
|
|
266
|
+
| `selected` | 已选择 | `d(selected=True)` |
|
|
267
|
+
| `packageName` | 包名 | `d(packageName="com.example")` |
|
|
268
|
+
|
|
269
|
+
### OCR 文字识别
|
|
270
|
+
|
|
271
|
+
```python
|
|
272
|
+
# 全屏 OCR
|
|
273
|
+
results = d.ocr()
|
|
274
|
+
for r in results:
|
|
275
|
+
print(f"{r.text} (置信度: {r.confidence:.2f}, 位置: {r.bounds})")
|
|
276
|
+
|
|
277
|
+
# 区域 OCR
|
|
278
|
+
results = d.ocr(region=(0, 0, 500, 500))
|
|
279
|
+
|
|
280
|
+
# 查找文字
|
|
281
|
+
result = d.ocr_find("确认")
|
|
282
|
+
if result:
|
|
283
|
+
print(f"找到: {result.text} at {result.center}")
|
|
284
|
+
|
|
285
|
+
# 查找并点击
|
|
286
|
+
d.ocr_click("确认", timeout=10)
|
|
287
|
+
|
|
288
|
+
# 等待文字出现
|
|
289
|
+
d.ocr_wait("加载完成", timeout=15)
|
|
290
|
+
|
|
291
|
+
# 像素取色
|
|
292
|
+
color = d.pixel_color(500, 800)
|
|
293
|
+
print(color) # "#FF0000"
|
|
294
|
+
|
|
295
|
+
# 模板匹配
|
|
296
|
+
pos = d.find_image("/sdcard/template.png", threshold=0.8)
|
|
297
|
+
if pos:
|
|
298
|
+
d.click(*pos)
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Shell 命令
|
|
302
|
+
|
|
303
|
+
```python
|
|
304
|
+
# 执行命令(通过引擎,ROOT/SHELL 权限)
|
|
305
|
+
result = d.shell("ls /sdcard")
|
|
306
|
+
print(result.output)
|
|
307
|
+
print(result.exit_code)
|
|
308
|
+
|
|
309
|
+
# 作为布尔值使用
|
|
310
|
+
if d.shell("test -f /sdcard/test.txt"):
|
|
311
|
+
print("文件存在")
|
|
312
|
+
|
|
313
|
+
# 通过 ADB 执行(仅 USB 模式)
|
|
314
|
+
result = d.adb_shell("getprop ro.build.version.release")
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### 应用管理
|
|
318
|
+
|
|
319
|
+
```python
|
|
320
|
+
# 启动应用
|
|
321
|
+
d.app_start("com.example.app")
|
|
322
|
+
|
|
323
|
+
# 先停止再启动
|
|
324
|
+
d.app_start("com.example.app", stop=True)
|
|
325
|
+
|
|
326
|
+
# 停止应用
|
|
327
|
+
d.app_stop("com.example.app")
|
|
328
|
+
|
|
329
|
+
# 当前前台应用
|
|
330
|
+
current = d.app_current()
|
|
331
|
+
print(f"包名: {current['package']}")
|
|
332
|
+
|
|
333
|
+
# 等待应用出现在前台
|
|
334
|
+
d.app_wait("com.example.app", timeout=10)
|
|
335
|
+
|
|
336
|
+
# 已安装应用列表
|
|
337
|
+
apps = d.app_list()
|
|
338
|
+
apps = d.app_list(filter="example") # 过滤
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### 文件操作
|
|
342
|
+
|
|
343
|
+
```python
|
|
344
|
+
# 推送文件到设备
|
|
345
|
+
d.push("local_file.txt", "/sdcard/remote_file.txt")
|
|
346
|
+
|
|
347
|
+
# 从设备拉取文件
|
|
348
|
+
d.pull("/sdcard/remote_file.txt", "local_file.txt")
|
|
349
|
+
|
|
350
|
+
# 列出目录
|
|
351
|
+
files = d.list_files("/sdcard")
|
|
352
|
+
for f in files:
|
|
353
|
+
print(f"{f.name} {'[DIR]' if f.is_dir else f.size}")
|
|
354
|
+
|
|
355
|
+
# 读写文本文件
|
|
356
|
+
content = d.read_file("/sdcard/test.txt")
|
|
357
|
+
d.write_file("/sdcard/test.txt", "hello world")
|
|
358
|
+
|
|
359
|
+
# 文件操作
|
|
360
|
+
d.file_exists("/sdcard/test.txt") # 检查存在
|
|
361
|
+
d.mkdir("/sdcard/new_folder") # 创建目录
|
|
362
|
+
d.remove("/sdcard/test.txt") # 删除
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### 脚本项目管理
|
|
366
|
+
|
|
367
|
+
```python
|
|
368
|
+
# 列出设备上的脚本项目
|
|
369
|
+
projects = d.list_projects()
|
|
370
|
+
for p in projects:
|
|
371
|
+
print(f"{p.name} {'[运行中]' if p.running else ''}")
|
|
372
|
+
|
|
373
|
+
# 启动 / 停止项目
|
|
374
|
+
d.start_project("my_script")
|
|
375
|
+
d.stop_project()
|
|
376
|
+
|
|
377
|
+
# 查看运行状态
|
|
378
|
+
status = d.project_status()
|
|
379
|
+
|
|
380
|
+
# 远程执行代码片段
|
|
381
|
+
output = d.run_code("print('hello from device')")
|
|
382
|
+
print(output)
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## 局域网设备发现
|
|
386
|
+
|
|
387
|
+
自动扫描局域网中运行 yyds.auto 引擎的设备:
|
|
388
|
+
|
|
389
|
+
```python
|
|
390
|
+
import yyds_auto
|
|
391
|
+
|
|
392
|
+
# 自动检测本机网段并扫描
|
|
393
|
+
devices = yyds_auto.discover()
|
|
394
|
+
for dev in devices:
|
|
395
|
+
print(f"{dev.ip} - {dev.model} (Android {dev.android_version})")
|
|
396
|
+
|
|
397
|
+
# 指定子网
|
|
398
|
+
devices = yyds_auto.discover(subnet="192.168.1.0/24")
|
|
399
|
+
|
|
400
|
+
# 扫描多个子网
|
|
401
|
+
devices = yyds_auto.discover(subnet=["192.168.1.0/24", "10.0.0.0/24"])
|
|
402
|
+
|
|
403
|
+
# 调整扫描参数
|
|
404
|
+
devices = yyds_auto.discover(
|
|
405
|
+
timeout=0.5, # 单 IP 探测超时(秒)
|
|
406
|
+
max_workers=256, # 并发线程数
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
# 连接发现的设备
|
|
410
|
+
d = devices[0].connect()
|
|
411
|
+
d.screenshot("screen.png")
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
## CLI 命令行工具
|
|
415
|
+
|
|
416
|
+
安装后可通过 `yyds-auto` 或 `python -m yyds_auto` 使用:
|
|
417
|
+
|
|
418
|
+
```bash
|
|
419
|
+
# 环境诊断(检查 ADB、设备、引擎状态)
|
|
420
|
+
yyds-auto doctor
|
|
421
|
+
|
|
422
|
+
# 列出 ADB 设备
|
|
423
|
+
yyds-auto devices
|
|
424
|
+
|
|
425
|
+
# 扫描局域网设备
|
|
426
|
+
yyds-auto discover
|
|
427
|
+
yyds-auto discover --subnet 192.168.1.0/24
|
|
428
|
+
|
|
429
|
+
# 初始化设备(安装 APK + 启动引擎)
|
|
430
|
+
yyds-auto init
|
|
431
|
+
yyds-auto init -s SERIAL --apk path/to/yyds-auto.apk
|
|
432
|
+
|
|
433
|
+
# 截图
|
|
434
|
+
yyds-auto screenshot
|
|
435
|
+
yyds-auto screenshot -o screen.png -s SERIAL
|
|
436
|
+
|
|
437
|
+
# 执行 Shell 命令
|
|
438
|
+
yyds-auto shell "ls /sdcard"
|
|
439
|
+
yyds-auto shell -s SERIAL "whoami"
|
|
440
|
+
|
|
441
|
+
# 查看版本
|
|
442
|
+
yyds-auto version
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
## 架构说明
|
|
446
|
+
|
|
447
|
+
```
|
|
448
|
+
PC (Python) Android 设备
|
|
449
|
+
┌──────────────┐ ┌──────────────────┐
|
|
450
|
+
│ yyds-auto │ │ yyds.auto App │
|
|
451
|
+
│ │ USB/ADB Forward │ │
|
|
452
|
+
│ Device ─────┼──── HTTP REST ────►│ yyds.py :61140 │
|
|
453
|
+
│ │ or WiFi Direct │ │ │
|
|
454
|
+
│ discover() │ │ ▼ │
|
|
455
|
+
│ connect() │ │ yyds.auto :61100│
|
|
456
|
+
│ │ │ (自动化引擎) │
|
|
457
|
+
└──────────────┘ └──────────────────┘
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
- **USB 模式**: 通过 ADB 端口转发 `localhost:61140 → device:61140`
|
|
461
|
+
- **WiFi 模式**: 直接连接设备 IP `http://<device-ip>:61140`
|
|
462
|
+
- **引擎自启动**: 连接时自动检测引擎状态,未运行则尝试三级启动策略
|
|
463
|
+
|
|
464
|
+
## 与 uiautomator2 的对比
|
|
465
|
+
|
|
466
|
+
| 功能 | yyds-auto | uiautomator2 |
|
|
467
|
+
|------|-----------|--------------|
|
|
468
|
+
| USB 连接 | ✅ | ✅ |
|
|
469
|
+
| WiFi 连接 | ✅ | ✅ |
|
|
470
|
+
| 局域网扫描 | ✅ | ❌ |
|
|
471
|
+
| 元素选择器 | ✅ | ✅ |
|
|
472
|
+
| 截图 | ✅ | ✅ |
|
|
473
|
+
| OCR 识别 | ✅ 内置 | ❌ 需第三方 |
|
|
474
|
+
| 图像匹配 | ✅ 内置 | ❌ 需第三方 |
|
|
475
|
+
| ROOT Shell | ✅ | ❌ |
|
|
476
|
+
| 文件管理 | ✅ | ❌ |
|
|
477
|
+
| 脚本项目管理 | ✅ | ❌ |
|
|
478
|
+
| 远程执行代码 | ✅ | ❌ |
|
|
479
|
+
|
|
480
|
+
## 依赖
|
|
481
|
+
|
|
482
|
+
- Python >= 3.8
|
|
483
|
+
- [requests](https://pypi.org/project/requests/) >= 2.28
|
|
484
|
+
- [Pillow](https://pypi.org/project/Pillow/) >= 9.0
|
|
485
|
+
- [adbutils](https://pypi.org/project/adbutils/) >= 2.0
|
|
486
|
+
|
|
487
|
+
## License
|
|
488
|
+
|
|
489
|
+
[MIT](LICENSE)
|
|
490
|
+
|
|
491
|
+
# 发布
|
|
492
|
+
pip install twine
|
|
493
|
+
twine upload dist/*
|