227 lines
6.9 KiB
Markdown
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` |
|