autool/DroidBot/PLATFORM_GUIDE.md
2026-06-17 19:44:18 +08:00

227 lines
6.9 KiB
Markdown

# DroidBot 多平台适配指南
本文档介绍 DroidBot 的多平台架构设计和接口标准,帮助开发者扩展新平台支持。
## 架构概述
DroidBot 采用抽象工厂模式,将平台无关的核心逻辑与平台特定实现分离:
```
┌──────────────────────────────────────────────────────────┐
│ DroidBot Core │
│ (input_policy.py, input_manager.py, utg.py) │
└─────────────────────────┬────────────────────────────────┘
│ 调用抽象接口
┌─────────────────────────▼────────────────────────────────┐
│ core/ 抽象层 │
│ AbstractDevice, AbstractDeviceState, AbstractInputEvent │
│ PlatformFactory │
└─────────────────────────┬────────────────────────────────┘
│ 平台实现
┌─────────────────────────▼────────────────────────────────┐
│ platforms/ │
│ ├── android/ ← AndroidDevice, AndroidDeviceState │
│ ├── ios/ ← (预留) │
│ └── windows/ ← (预留) │
└──────────────────────────────────────────────────────────┘
```
## 核心接口
### 1. AbstractDevice
设备抽象基类,定义平台无关的设备操作接口。
```python
class AbstractDevice(ABC):
# === 必须实现的方法 ===
@abstractmethod
def set_up(self) -> None: ...
@abstractmethod
def connect(self) -> bool: ...
@abstractmethod
def disconnect(self) -> None: ...
@abstractmethod
def tear_down(self) -> None: ...
@abstractmethod
def check_connectivity(self) -> bool: ...
@abstractmethod
def get_current_state(self) -> 'AbstractDeviceState': ...
@abstractmethod
def get_display_info(self, refresh: bool = False) -> Dict[str, Any]: ...
@abstractmethod
def send_event(self, event: 'AbstractInputEvent') -> bool: ...
@abstractmethod
def take_screenshot(self, path: str) -> bool: ...
@abstractmethod
def unlock(self) -> None: ...
@abstractmethod
def is_foreground(self) -> bool: ...
@abstractmethod
def start_app(self) -> bool: ...
@abstractmethod
def pull_back_to_app(self) -> bool: ...
@property
@abstractmethod
def app_identifier(self) -> str: ...
@abstractmethod
def get_platform_name(self) -> str: ...
@abstractmethod
def get_device_info(self) -> Dict[str, Any]: ...
@abstractmethod
def create_event_from_dict(self, event_dict: Dict) -> 'AbstractInputEvent': ...
```
### 2. AbstractDeviceState
设备状态抽象基类,定义 UI 状态信息接口。
```python
class AbstractDeviceState(ABC):
# === 必须实现的属性 ===
@property
@abstractmethod
def views(self) -> List[Dict[str, Any]]: ...
@property
@abstractmethod
def state_str(self) -> str: ...
@property
@abstractmethod
def foreground_page(self) -> Optional[str]: ...
# === 必须实现的方法 ===
@abstractmethod
def get_possible_input(self) -> List['AbstractInputEvent']: ...
@abstractmethod
def to_dict(self) -> Dict[str, Any]: ...
@abstractmethod
def get_text_representation(self, merge_buttons: bool = False) -> tuple: ...
```
### 3. AbstractInputEvent
输入事件抽象基类。
```python
class AbstractInputEvent(ABC):
@abstractmethod
def send(self, device: 'AbstractDevice') -> bool: ...
@abstractmethod
def to_dict(self) -> Dict[str, Any]: ...
@abstractmethod
def get_event_str(self, state: Optional['AbstractDeviceState'] = None) -> str: ...
```
## 统一视图数据结构
各平台需将 UI 元素转换为统一格式:
```python
{
# 必需字段
"temp_id": int, # 临时 ID
"bounds": [[int, int], [int, int]], # 边界框 [[left,top], [right,bottom]]
"class": str, # 元素类型
# 文本相关
"text": Optional[str], # 显示文本
"content_description": Optional[str], # 无障碍描述
# 层级关系
"parent": Optional[int], # 父节点 ID
"children": List[int], # 子节点 ID 列表
# 交互属性
"enabled": bool,
"visible": bool,
"clickable": bool,
"scrollable": bool,
"editable": bool,
"checkable": bool,
"long_clickable": bool,
# 平台特有
"resource_id": Optional[str] # 平台元素标识
}
```
## 平台映射表
| 抽象接口 | Android | iOS | Windows |
|---------|---------|-----|---------|
| `foreground_page` | `package/activity` | `bundleId/viewController` | `exe_path/window_title` |
| `app_identifier` | package_name | bundleId | exe_path/window_class |
| `resource_id` | resource_id | accessibilityIdentifier | AutomationId |
## 添加新平台步骤
### 1. 创建平台目录
```bash
mkdir -p droidbot/platforms/ios
```
### 2. 实现核心类
```python
# platforms/ios/__init__.py
from .ios_device import IOSDevice
from .ios_device_state import IOSDeviceState
from .ios_input_event import IOSTouchEvent, IOSKeyEvent, ...
def register_ios_platform():
from ...core.platform_factory import PlatformFactory, Platform
event_classes = {
'touch': IOSTouchEvent,
'key': IOSKeyEvent,
# ...
}
PlatformFactory.register_platform(
Platform.IOS,
IOSDevice,
IOSDeviceState,
event_classes
)
# 模块导入时自动注册
register_ios_platform()
```
### 3. 添加平台枚举
```python
# core/platform_factory.py
class Platform(Enum):
ANDROID = "android"
IOS = "ios" # 新增
WINDOWS = "windows" # 新增
```
### 4. 在 platforms/__init__.py 导入
```python
from .ios import IOSDevice, IOSDeviceState
```
## 事件类型
所有平台必须支持的事件类型:
| 事件类型 | 说明 | 工厂键名 |
|---------|------|---------|
| Touch | 点击 | `touch` |
| LongTouch | 长按 | `long_touch` |
| Swipe | 滑动 | `swipe` |
| Scroll | 滚动 | `scroll` |
| SetText | 输入文本 | `set_text` |
| Key | 按键 | `key` |
| KillApp | 终止应用 | `kill_app` |