Metadata-Version: 2.4
Name: fengchao-sdk
Version: 1.2.3
Summary: 蜂巢云控 Python SDK - 手机自动化控制
Home-page: https://github.com/fendoushaonian/phone-control
Author: 蜂巢云控
Author-email: support@qunkong.com
Project-URL: Documentation, https://qk.lhy.lat/docs/sdk
Project-URL: Bug Reports, https://github.com/fendoushaonian/phone-control/issues
Project-URL: Source, https://github.com/fendoushaonian/phone-control
Keywords: android automation control phone fengchao qunkong accessibility hid adb
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.7
Description-Content-Type: text/markdown
Requires-Dist: websocket-client>=1.0.0
Requires-Dist: requests>=2.20.0
Provides-Extra: image
Requires-Dist: Pillow>=8.0.0; extra == "image"
Requires-Dist: opencv-python>=4.5.0; extra == "image"
Provides-Extra: ocr
Requires-Dist: rapidocr_onnxruntime>=1.0.0; extra == "ocr"
Provides-Extra: all
Requires-Dist: Pillow>=8.0.0; extra == "all"
Requires-Dist: opencv-python>=4.5.0; extra == "all"
Requires-Dist: rapidocr_onnxruntime>=1.0.0; extra == "all"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: project-url
Dynamic: provides-extra
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# 🐝 蜂巢云控 Python SDK

简单、强大的手机自动化控制SDK，支持 **无障碍服务**、**ADB USB**、**ADB WiFi**、**HID/OTG** 多种控制方式。

[![PyPI version](https://badge.fury.io/py/fengchao-sdk.svg)](https://badge.fury.io/py/fengchao-sdk)
[![Python](https://img.shields.io/pypi/pyversions/fengchao-sdk.svg)](https://pypi.org/project/fengchao-sdk/)

## ✨ 特性

- 🚀 **简单易用** - 几行代码即可控制手机
- 📶 **无障碍服务** - 无需ROOT，稳定可靠
- 🔄 **批量控制** - 同时控制50+台设备
- ⚡ **并行操作** - 多线程同时执行，效率翻倍
- 🔍 **OCR识别** - 屏幕文字识别与点击
- 🖼️ **图像识别** - 模板匹配查找图标
- 📱 **元素查找** - 按ID/类名/文本查找元素
- 🌐 **远程控制** - 通过中继服务器远程控制

## 📦 安装

```bash
pip install fengchao-sdk
```

安装全部功能：
```bash
pip install fengchao-sdk[all]  # 包含OCR和图像识别
```

---

# 📱 无障碍模式（推荐）

无障碍模式是**最推荐**的控制方式！无需ROOT、无需ADB、无需电脑连接，通过安卓无障碍服务实现稳定控制。

## 🔧 准备工作

1. **安装蜂巢云控APP** - 在手机上安装APP
2. **开启无障碍服务** - 设置 → 无障碍 → 蜂巢云控 → 开启
3. **授予截图权限** - 首次截图时会弹窗，点击允许
4. **获取连接信息**：
   - WiFi直连：获取手机IP地址（APP主界面显示）
   - 中继模式：获取设备ID和API密钥

## 1️⃣ WiFi直连模式

手机和电脑在同一局域网时使用：

```python
from fengchao import Device

# 连接设备（手机IP:端口）
device = Device('192.168.1.100', port=8888, mode='wifi')

# 基础操作
device.screenshot()           # 截图
device.click(500, 800)        # 点击
device.swipe(100, 800, 100, 200)  # 滑动
device.input_text('Hello')    # 输入文字

# 按键操作
device.press_home()           # Home键
device.press_back()           # 返回键
device.press_menu()           # 菜单键

# APP操作
device.start_app('com.android.settings')  # 启动APP
device.stop_app('com.android.settings')   # 停止APP
device.get_current_app()      # 获取当前APP
```

## 2️⃣ 中继服务器模式

通过中继服务器远程控制设备：

```python
from fengchao import Device

# 连接中继服务器
device = Device(
    device_id='设备ID',
    api_key='你的API密钥',
    relay_server='http://服务器地址:9999',
    mode='relay'
)

# 所有操作与WiFi直连一致
device.screenshot()
device.click(500, 800)
device.press_home()
```

## 3️⃣ 元素查找（无障碍核心功能）

通过无障碍服务可以精确查找和操作UI元素：

```python
# 按文本查找
elem = device.find_element(text='登录')
if elem:
    elem.click()  # 点击元素

# 按资源ID查找
elem = device.find_element(resource_id='com.example:id/btn_login')

# 按类名查找
elems = device.find_elements(class_name='android.widget.Button')
print(f'找到 {len(elems)} 个按钮')

# 按内容描述查找
elem = device.find_element(content_desc='返回')

# 组合查找
elem = device.find_element(
    class_name='android.widget.TextView',
    text='确定'
)

# 检查元素是否存在
if device.element_exists(text='登录成功'):
    print('登录成功！')

# 等待元素出现
elem = device.wait_element(text='加载完成', timeout=10)

# 直接点击元素
device.click_element(text='确定')
device.click_element(resource_id='com.example:id/btn')
```

### 元素属性

```python
elem = device.find_element(text='登录')
print(elem.text)           # 文本内容
print(elem.resource_id)    # 资源ID
print(elem.class_name)     # 类名
print(elem.content_desc)   # 内容描述
print(elem.bounds)         # 坐标范围
print(elem.clickable)      # 是否可点击
```

## 4️⃣ 图像识别

```python
# 截图并裁剪模板
img = device.screenshot()
template = img.crop((100, 100, 200, 200))
template.save('button.png')

# 查找图片
result = device.find_image('button.png', threshold=0.8)
if result:
    print(f"找到位置: {result['center']}")
    print(f"置信度: {result['confidence']}")

# 点击图片
device.click_image('button.png')

# 等待图片出现
device.wait_image('loading_done.png', timeout=10)

# 检查图片是否存在
if device.image_exists('success.png'):
    print('操作成功！')
```

## 5️⃣ OCR文字识别

需要安装：`pip install rapidocr-onnxruntime`

```python
# OCR识别屏幕文字
texts = device.ocr()
for t in texts:
    print(f"{t['text']} @ {t['center']}")

# 查找文字
result = device.find_text('登录')
if result:
    print(f"找到: {result['text']} @ {result['center']}")

# 点击文字
device.click_text('登录')
device.click_text('确定', timeout=5)

# 检查文字是否存在
if device.text_exists('登录成功'):
    print('成功！')

# 等待文字出现
device.wait_text('加载完成', timeout=10)
```

## 6️⃣ Device类完整API文档

`Device` 类是**无障碍模式**的核心类，通过无障碍服务控制手机。

### 连接方式

```python
from fengchao import Device

# 方式1: WiFi直连（同局域网）
device = Device('192.168.1.100', port=8888, mode='wifi')

# 方式2: 中继服务器（远程控制）
device = Device(
    device_id='设备ID',
    api_key='API密钥',
    relay_server='http://服务器:9999',
    mode='relay'
)
```

### 触摸操作

| 方法 | 参数 | 返回值 | 说明 |
|------|------|--------|------|
| `click(x, y)` | x, y: 坐标 | bool | 点击屏幕 |
| `double_click(x, y)` | x, y: 坐标 | bool | 双击屏幕 |
| `long_press(x, y, duration)` | duration: 毫秒，默认1000 | bool | 长按 |
| `swipe(x1, y1, x2, y2, duration)` | duration: 毫秒，默认300 | bool | 滑动 |
| `swipe_up()` | - | bool | 上滑 |
| `swipe_down()` | - | bool | 下滑 |
| `swipe_left()` | - | bool | 左滑 |
| `swipe_right()` | - | bool | 右滑 |
| `drag(x1, y1, x2, y2, duration)` | 起点终点坐标 | bool | 拖拽 |

```python
device.click(500, 800)
device.double_click(500, 800)
device.long_press(500, 800, 2000)  # 长按2秒
device.swipe(500, 1500, 500, 500, 300)  # 上滑
device.swipe_up()  # 快捷上滑
device.drag(100, 100, 500, 500, 1000)  # 拖拽
```

### 按键操作

| 方法 | 参数 | 返回值 | 说明 |
|------|------|--------|------|
| `press_home()` | - | bool | Home键 |
| `press_back()` | - | bool | 返回键 |
| `press_menu()` | - | bool | 菜单键 |
| `press_recent()` | - | bool | 最近任务键 |
| `press_key(keycode)` | keycode: 按键码 | bool | 发送任意按键 |

```python
device.press_home()
device.press_back()
device.press_menu()
device.press_key(24)  # 音量+
device.press_key(25)  # 音量-
device.press_key(26)  # 电源键
```

### 文本输入

| 方法 | 参数 | 返回值 | 说明 |
|------|------|--------|------|
| `input_text(text)` | text: 文字内容 | bool | 输入文字 |
| `clear_text(length)` | length: 删除字符数，默认50 | bool | 清空输入框 |

```python
device.input_text('Hello World')
device.clear_text()  # 清空
device.clear_text(10)  # 删除10个字符
```

### 截图操作

| 方法 | 参数 | 返回值 | 说明 |
|------|------|--------|------|
| `screenshot(save_path)` | save_path: 保存路径（可选） | PIL.Image | 截图 |
| `get_screen_size()` | - | (width, height) | 获取屏幕尺寸 |
| `save_screenshot_region(x1,y1,x2,y2,path)` | 区域坐标和路径 | bool | 保存截图区域 |

```python
img = device.screenshot()  # 返回PIL Image
device.screenshot('screen.png')  # 保存到文件
width, height = device.get_screen_size()
device.save_screenshot_region(100, 100, 200, 200, 'button.png')  # 保存模板
```

### APP操作

| 方法 | 参数 | 返回值 | 说明 |
|------|------|--------|------|
| `start_app(package)` | package: 包名 | bool | 启动APP |
| `stop_app(package)` | package: 包名 | bool | 停止APP |
| `get_current_app()` | - | dict | 获取当前APP信息 |
| `install_app(apk_path)` | apk_path: APK路径 | bool | 安装APP |
| `uninstall_app(package)` | package: 包名 | bool | 卸载APP |
| `clear_app_data(package)` | package: 包名 | bool | 清除APP数据 |
| `get_installed_apps()` | - | List[str] | 获取已安装APP列表 |

```python
device.start_app('com.android.settings')  # 启动设置
device.stop_app('com.android.settings')   # 停止设置
app = device.get_current_app()
print(app['package'], app['activity'])
device.clear_app_data('com.example.app')  # 清除数据
apps = device.get_installed_apps()  # 获取所有APP
```

### 设备信息

| 方法 | 参数 | 返回值 | 说明 |
|------|------|--------|------|
| `get_info()` | - | dict | 获取设备信息 |
| `get_battery()` | - | dict | 获取电池信息 |
| `is_screen_on()` | - | bool | 屏幕是否亮着 |
| `is_online()` | - | bool | 设备是否在线 |
| `wake_up()` | - | bool | 唤醒屏幕 |
| `lock_screen()` | - | bool | 锁屏 |

```python
info = device.get_info()
print(info)  # {'brand': 'Xiaomi', 'model': 'MI 8', ...}
battery = device.get_battery()
print(f"电量: {battery['level']}%")
if not device.is_screen_on():
    device.wake_up()
```

### 元素查找（无障碍核心功能）

| 方法 | 参数 | 返回值 | 说明 |
|------|------|--------|------|
| `find_element(text, resource_id, class_name, content_desc)` | 查找条件 | Element | 查找单个元素 |
| `find_elements(...)` | 同上 | List[Element] | 查找多个元素 |
| `click_element(...)` | 同上 | bool | 查找并点击 |
| `element_exists(...)` | 同上 | bool | 检查是否存在 |
| `wait_element(..., timeout)` | timeout: 超时秒数 | Element | 等待元素出现 |

```python
# 按文本查找
elem = device.find_element(text='登录')
if elem:
    print(f'文本: {elem.text}')
    print(f'坐标: {elem.bounds}')
    elem.click()  # 点击元素

# 按资源ID查找
elem = device.find_element(resource_id='com.example:id/btn_login')

# 按类名查找
buttons = device.find_elements(class_name='android.widget.Button')
print(f'找到 {len(buttons)} 个按钮')

# 按内容描述查找
elem = device.find_element(content_desc='返回')

# 组合查找
elem = device.find_element(
    class_name='android.widget.TextView',
    text='确定'
)

# 直接点击元素
device.click_element(text='确定')
device.click_element(resource_id='com.example:id/btn')

# 检查元素是否存在
if device.element_exists(text='登录成功'):
    print('登录成功！')

# 等待元素出现
elem = device.wait_element(text='加载完成', timeout=10)
```

### 图像识别

需要安装：`pip install fengchao-sdk[image]` 或 `pip install opencv-python Pillow`

| 方法 | 参数 | 返回值 | 说明 |
|------|------|--------|------|
| `find_image(template, threshold)` | template: 图片路径, threshold: 阈值0.8 | dict | 查找图片 |
| `find_all_images(template, threshold)` | 同上 | List[dict] | 查找所有匹配 |
| `click_image(template, threshold)` | 同上 | bool | 点击图片 |
| `image_exists(template, threshold)` | 同上 | bool | 检查图片是否存在 |
| `wait_for_image(template, timeout)` | timeout: 超时秒数 | dict | 等待图片出现 |

```python
# 先保存模板图片
device.save_screenshot_region(100, 100, 200, 200, 'button.png')

# 查找图片
result = device.find_image('button.png', threshold=0.8)
if result:
    print(f"位置: {result['center']}")
    print(f"置信度: {result['confidence']}")

# 点击图片
device.click_image('button.png')

# 等待图片出现
device.wait_for_image('loading_done.png', timeout=10)

# 检查图片是否存在
if device.image_exists('success.png'):
    print('操作成功！')
```

### OCR文字识别

需要安装：`pip install fengchao-sdk[ocr]` 或 `pip install rapidocr_onnxruntime`

| 方法 | 参数 | 返回值 | 说明 |
|------|------|--------|------|
| `ocr(region)` | region: 识别区域(x1,y1,x2,y2) | List[dict] | OCR识别 |
| `find_text(text)` | text: 要查找的文字 | dict | 查找文字位置 |
| `click_text(text, timeout)` | timeout: 超时秒数 | bool | 点击文字 |
| `text_exists(text)` | text: 要查找的文字 | bool | 检查文字是否存在 |
| `wait_text(text, timeout)` | timeout: 超时秒数 | dict | 等待文字出现 |

```python
# OCR识别全屏
texts = device.ocr()
for t in texts:
    print(f"{t['text']} @ {t['center']} 置信度:{t['confidence']}")

# OCR识别指定区域
texts = device.ocr(region=(100, 500, 300, 550))

# 查找文字
result = device.find_text('登录')
if result:
    print(f"找到: {result['text']} @ {result['center']}")

# 点击文字
device.click_text('登录')
device.click_text('确定', timeout=5)

# 检查文字是否存在
if device.text_exists('登录成功'):
    print('成功！')

# 等待文字出现
device.wait_text('加载完成', timeout=10)
```

### 连接管理

| 方法 | 说明 |
|------|------|
| `connect()` | 连接设备 |
| `disconnect()` | 断开连接 |
| `is_online()` | 检查是否在线 |

```python
device.connect()  # 手动连接
if device.is_online():
    print('设备在线')
device.disconnect()  # 断开连接
```

## 7️⃣ 常用按键码

| 按键 | Keycode | 说明 |
|------|---------|------|
| Home | 3 | 回到桌面 |
| Back | 4 | 返回 |
| Menu | 82 | 菜单键 |
| Power | 26 | 电源键 |
| Volume Up | 24 | 音量+ |
| Volume Down | 25 | 音量- |
| Enter | 66 | 确认键 |
| Delete | 67 | 删除键 |
| Tab | 61 | Tab键 |
| Space | 62 | 空格键 |

```python
device.press_key(3)   # Home
device.press_key(4)   # Back
device.press_key(24)  # Volume Up
device.press_key(25)  # Volume Down
device.press_key(26)  # Power
```

## 8️⃣ 无障碍模式实战示例

### 示例1：自动登录APP

```python
from fengchao import Device
import time

device = Device(
    device_id='你的设备ID',
    api_key='你的API密钥',
    relay_server='http://服务器:9999',
    mode='relay'
)

# 启动APP
device.start_app('com.example.app')
time.sleep(3)

# 等待登录按钮出现
if device.wait_element(text='登录', timeout=10):
    device.click_element(text='登录')
    time.sleep(1)
    
    # 输入账号
    device.click_element(resource_id='com.example.app:id/username')
    device.input_text('myusername')
    
    # 输入密码
    device.click_element(resource_id='com.example.app:id/password')
    device.input_text('mypassword')
    
    # 点击登录按钮
    device.click_element(text='登录')
    
    # 检查是否登录成功
    if device.wait_element(text='首页', timeout=10):
        print('登录成功！')
```

### 示例2：刷短视频

```python
from fengchao import Device
import time

device = Device(
    device_id='设备ID',
    api_key='API密钥',
    relay_server='http://服务器:9999',
    mode='relay'
)

# 打开抖音
device.start_app('com.ss.android.ugc.aweme')
time.sleep(5)

# 关闭可能的弹窗
for text in ['我知道了', '关闭', '跳过', '以后再说']:
    if device.text_exists(text):
        device.click_text(text)
        time.sleep(0.5)

# 刷视频
for i in range(100):
    print(f'观看第 {i+1} 个视频')
    time.sleep(8)  # 观看8秒
    device.swipe(540, 1500, 540, 500, 300)  # 上滑
```

### 示例3：OCR识别验证码

```python
from fengchao import Device

device = Device('192.168.1.100', port=8888, mode='wifi')

# 截图
img = device.screenshot()

# OCR识别指定区域（验证码区域）
texts = device.ocr(region=(100, 500, 300, 550))
if texts:
    code = texts[0]['text']
    print(f'识别到验证码: {code}')
    
    # 输入验证码
    device.click(400, 600)  # 点击输入框
    device.input_text(code)
```

### 示例4：图像识别点击

```python
from fengchao import Device

device = Device('192.168.1.100', port=8888, mode='wifi')

# 等待某个图标出现并点击
if device.wait_image('like_button.png', timeout=10):
    device.click_image('like_button.png')
    print('点击成功')

# 检查是否存在某个状态图标
if device.image_exists('success_icon.png'):
    print('操作成功')
else:
    print('操作失败')
```

### 示例5：批量控制多台设备

```python
from fengchao import Device
from concurrent.futures import ThreadPoolExecutor
import time

# 设备列表
DEVICES = [
    {'device_id': 'device1', 'api_key': 'key1'},
    {'device_id': 'device2', 'api_key': 'key2'},
    {'device_id': 'device3', 'api_key': 'key3'},
]

RELAY_SERVER = 'http://服务器:9999'

def run_script(config):
    """单台设备的脚本"""
    device = Device(
        device_id=config['device_id'],
        api_key=config['api_key'],
        relay_server=RELAY_SERVER,
        mode='relay'
    )
    
    device.press_home()
    device.start_app('com.smile.gifmaker')
    time.sleep(3)
    
    for i in range(10):
        time.sleep(5)
        device.swipe(540, 1500, 540, 500, 300)
    
    print(f"设备 {config['device_id']} 完成")

# 并行执行
with ThreadPoolExecutor(max_workers=len(DEVICES)) as pool:
    pool.map(run_script, DEVICES)

print('全部完成！')
```

---

# 🔌 ADB 连接方式

## 1️⃣ USB 连接（最简单）

```python
from fengchao import ADBDevice

# 自动连接第一台USB设备
device = ADBDevice()

# 或指定设备序列号
device = ADBDevice(serial="A9GVVB2B30026001")

# 开始操作
device.click(500, 800)
device.swipe_up()
```

## 2️⃣ WiFi 连接（无需USB线）

### 方式A：USB转WiFi（推荐首次使用）

```python
from fengchao import ADBDevice

# 1. 先用USB连接
device = ADBDevice()

# 2. 开启WiFi调试模式
device.enable_tcpip(5555)

# 3. 获取手机IP
ip = device.get_ip_address()
print(f"手机IP: {ip}")

# 4. 现在可以拔掉USB线了！

# 5. 通过WiFi连接
wifi_device = ADBDevice.connect_wifi(ip, 5555)

# 6. WiFi控制手机
wifi_device.click(500, 800)
wifi_device.swipe_up()
```

### 方式B：直接WiFi连接（手机已开启tcpip）

```python
from fengchao import ADBDevice

# 直接用IP连接（手机需要已开启 adb tcpip 5555）
device = ADBDevice.connect_wifi("192.168.1.100", 5555)

# 操作手机
device.start_app("com.smile.gifmaker")
device.swipe_up()
```

### WiFi连接数量

| 限制因素 | 推荐数量 |
|---------|---------|
| 单台电脑 | **20-50台** |
| 极限测试 | 100台+ |

> 主要受限于：电脑性能、网络带宽

---

# 🔄 批量操作（重点！）

## 串行批量（简单但慢）

```python
from fengchao import ADBDevice

# 获取所有设备
serials = ADBDevice.list_devices()
devices = [ADBDevice(s) for s in serials]

# 逐个操作（一台一台来）
for d in devices:
    d.swipe_up()
```

## ⚡ 并行批量（同时操作，超快！）

```python
from fengchao import ADBDevice
from concurrent.futures import ThreadPoolExecutor

# 连接所有设备
serials = ADBDevice.list_devices()
devices = [ADBDevice(s) for s in serials]

# 🚀 同时操作所有设备（不是for循环！）
with ThreadPoolExecutor(max_workers=50) as pool:
    # 所有设备同时上滑
    list(pool.map(lambda d: d.swipe_up(), devices))
    
    # 所有设备同时打开快手
    list(pool.map(lambda d: d.start_app("com.smile.gifmaker"), devices))
```

## 🎯 封装成一行代码

```python
from fengchao import ADBDevice
from concurrent.futures import ThreadPoolExecutor

# 连接所有设备
devices = [ADBDevice(s) for s in ADBDevice.list_devices()]

def batch(func):
    """批量并行执行"""
    with ThreadPoolExecutor(max_workers=50) as pool:
        return list(pool.map(func, devices))

# 使用示例 - 一行代码控制所有设备！
batch(lambda d: d.swipe_up())                              # 全部上滑
batch(lambda d: d.press_home())                            # 全部回桌面
batch(lambda d: d.click(500, 800))                         # 全部点击
batch(lambda d: d.start_app("com.smile.gifmaker"))         # 全部打开快手
batch(lambda d: d.screenshot(f"screen_{d.serial}.png"))    # 全部截图
```

## 📊 批量获取信息

```python
# 获取所有设备电量
results = batch(lambda d: {"serial": d.serial, "battery": d.get_battery_level()})
for r in results:
    print(f"{r['serial']}: {r['battery']}%")

# 获取所有设备信息
infos = batch(lambda d: d.get_device_info())
for info in infos:
    print(f"{info['brand']} {info['model']} - Android {info['android_version']}")
```

---

# 📚 ADBDevice 完整API文档

以下是 `ADBDevice` 类（ADB模式）的完整API。

## ADB设备连接

| 方法 | 说明 | 示例 |
|------|------|------|
| `ADBDevice()` | 自动连接第一台USB设备 | `device = ADBDevice()` |
| `ADBDevice(serial)` | 连接指定序列号设备 | `device = ADBDevice("ABC123")` |
| `ADBDevice.connect_wifi(ip, port)` | WiFi连接设备 | `device = ADBDevice.connect_wifi("192.168.1.100", 5555)` |
| `ADBDevice.list_devices()` | 列出所有已连接设备 | `serials = ADBDevice.list_devices()` |
| `enable_tcpip(port)` | 开启WiFi调试模式 | `device.enable_tcpip(5555)` |
| `disconnect()` | 断开WiFi连接 | `device.disconnect()` |

## ADB触摸操作

| 方法 | 参数 | 说明 |
|------|------|------|
| `click(x, y)` | x, y: 坐标 | 点击屏幕 |
| `double_click(x, y)` | x, y: 坐标 | 双击屏幕 |
| `long_press(x, y, duration)` | duration: 毫秒，默认1000 | 长按屏幕 |
| `swipe(x1, y1, x2, y2, duration)` | duration: 毫秒，默认300 | 滑动 |
| `swipe_up()` | - | 上滑（刷视频） |
| `swipe_down()` | - | 下滑 |
| `swipe_left()` | - | 左滑 |
| `swipe_right()` | - | 右滑 |

## ADB按键操作

| 方法 | 说明 |
|------|------|
| `press_back()` | 返回键 |
| `press_home()` | Home键 |
| `press_menu()` | 菜单键 |
| `press_recent()` | 最近任务键 |
| `press_key(keycode)` | 发送任意按键码 |

## ADB文本输入

| 方法 | 参数 | 说明 |
|------|------|------|
| `input_text(text)` | text: 要输入的文字 | 输入文字 |
| `clear_text(length)` | length: 删除字符数 | 清空输入框 |
| `set_clipboard(text)` | text: 文字内容 | 设置剪贴板 |
| `input_from_clipboard()` | - | 粘贴剪贴板内容 |

## ADB屏幕操作

| 方法 | 说明 |
|------|------|
| `screenshot(path)` | 截图并保存 |
| `get_screen_size()` | 获取屏幕尺寸 |
| `wake_up()` | 唤醒屏幕 |
| `lock_screen()` | 锁屏 |
| `is_screen_on()` | 屏幕是否亮着 |
| `is_screen_locked()` | 屏幕是否锁定 |

## ADB APP管理

| 方法 | 说明 |
|------|------|
| `start_app(package)` | 启动APP |
| `stop_app(package)` | 停止APP |
| `get_current_app()` | 获取当前APP |
| `is_app_installed(package)` | 检查是否安装 |
| `install_app(apk_path)` | 安装APP |
| `uninstall_app(package)` | 卸载APP |
| `list_packages()` | 列出所有已安装包 |
| `clear_app_data(package)` | 清除APP数据 |

## ADB设备信息

| 方法 | 说明 |
|------|------|
| `get_device_info()` | 设备完整信息 |
| `get_battery_level()` | 电量百分比 |
| `get_ip_address()` | 设备IP地址 |
| `get_mac_address()` | MAC地址 |
| `get_brightness()` | 屏幕亮度 |
| `get_cpu_usage()` | CPU使用率 |
| `get_memory_info()` | 内存信息 |

## ADB文件操作

| 方法 | 说明 |
|------|------|
| `push(local, remote)` | 推送文件到手机 |
| `pull(remote, local)` | 从手机拉取文件 |
| `list_files(path)` | 列出目录文件 |
| `file_exists(path)` | 检查文件是否存在 |
| `delete_file(path)` | 删除文件 |
| `mkdir(path)` | 创建目录 |

## ADB系统设置

| 方法 | 说明 |
|------|------|
| `set_brightness(level)` | 设置亮度 |
| `enable_wifi()` / `disable_wifi()` | WiFi开关 |
| `enable_airplane_mode()` / `disable_airplane_mode()` | 飞行模式 |
| `reboot()` | 重启设备 |
| `shell(cmd)` | 执行Shell命令 |

## ADB OCR/UI分析

| 方法 | 说明 |
|------|------|
| `init_ocr(engine)` | 初始化OCR引擎 |
| `ocr_screen()` | 识别屏幕文字 |
| `click_text(text)` | 找到文字并点击 |
| `dump_ui()` | 获取UI XML |
| `find_element_by_text(text)` | 通过文字查找元素 |
| `find_element_by_id(id)` | 通过ID查找元素 |
| `click_by_text(text)` | 点击文字元素 |

```python
from fengchao import ADBDevice

# ADB模式示例
device = ADBDevice()
device.start_app("com.smile.gifmaker")
device.swipe_up()
device.click_text("关注")
device.screenshot("screen.png")
device.push("local.txt", "/sdcard/test.txt")
info = device.get_device_info()
print(info)

# 识别屏幕所有文字
results = device.ocr_screen()
for r in results:
    print(f"{r['text']} @ {r['position']}")

# 查找并点击文字
device.click_text("登录")
device.click_text("确定")
device.click_text("关闭")

# 检查文字是否存在
if device.text_exists("登录成功"):
    print("登录成功！")

# 等待文字出现
device.wait_for_text("加载完成", timeout=10)
```

---

# 🎬 ADB实战示例

## 批量刷快手视频

```python
from fengchao import ADBDevice
from concurrent.futures import ThreadPoolExecutor
import time

def kuaishou_script(device):
    """快手刷视频脚本"""
    print(f"[{device.serial}] 开始")
    
    # 打开快手
    device.start_app("com.smile.gifmaker")
    time.sleep(3)
    
    # 关闭弹窗
    for text in ["关闭", "跳过", "我知道了"]:
        try:
            device.click_text(text)
            time.sleep(0.5)
        except:
            pass
    
    # 刷10个视频
    for i in range(10):
        time.sleep(5)  # 看5秒
        device.swipe_up()  # 下一个
        print(f"[{device.serial}] 视频 {i+1}/10")
    
    print(f"[{device.serial}] 完成")

# 连接所有设备
devices = [ADBDevice(s) for s in ADBDevice.list_devices()]
print(f"共 {len(devices)} 台设备")

# 并行执行
with ThreadPoolExecutor(max_workers=len(devices)) as pool:
    pool.map(kuaishou_script, devices)

print("全部完成！")
```

## WiFi批量控制

```python
from fengchao import ADBDevice
from concurrent.futures import ThreadPoolExecutor

# WiFi设备IP列表
DEVICE_IPS = [
    "192.168.1.101",
    "192.168.1.102",
    "192.168.1.103",
    "192.168.1.104",
    "192.168.1.105",
]

# 连接所有WiFi设备
devices = []
for ip in DEVICE_IPS:
    try:
        d = ADBDevice.connect_wifi(ip, 5555)
        devices.append(d)
        print(f"✅ 连接成功: {ip}")
    except:
        print(f"❌ 连接失败: {ip}")

print(f"共连接 {len(devices)} 台设备")

# 批量操作
def batch(func):
    with ThreadPoolExecutor(max_workers=50) as pool:
        return list(pool.map(func, devices))

# 全部回桌面
batch(lambda d: d.press_home())

# 全部打开快手
batch(lambda d: d.start_app("com.smile.gifmaker"))

# 全部刷视频
for i in range(10):
    print(f"第 {i+1} 次上滑")
    batch(lambda d: d.swipe_up())
    time.sleep(5)
```

---

# 📋 常用APP包名

| APP | 包名 |
|-----|------|
| 快手 | `com.smile.gifmaker` |
| 抖音 | `com.ss.android.ugc.aweme` |
| 微信 | `com.tencent.mm` |
| 淘宝 | `com.taobao.taobao` |
| 拼多多 | `com.xunmeng.pinduoduo` |
| 京东 | `com.jingdong.app.mall` |
| 支付宝 | `com.eg.android.AlipayGphone` |
| QQ | `com.tencent.mobileqq` |
| 微博 | `com.sina.weibo` |
| 小红书 | `com.xingin.xhs` |
| B站 | `tv.danmaku.bili` |
| 设置 | `com.android.settings` |

---

# 🔧 常见问题

## Q: WiFi连接失败？
```bash
# 1. 确保手机和电脑在同一WiFi
# 2. 先用USB连接，执行：
adb tcpip 5555
# 3. 获取手机IP后连接
```

## Q: OCR识别慢？
```python
# 预加载OCR引擎
device.init_ocr(engine="rapidocr")
# 后续识别会很快
```

## Q: 如何查看设备序列号？
```bash
adb devices
```

## Q: 批量操作有数量限制吗？
- 推荐：20-50台/电脑
- 极限：100台+
- 取决于电脑性能和网络

---

# 📄 许可证

MIT License
