125 lines
3.4 KiB
Python
125 lines
3.4 KiB
Python
"""
|
|
工作手机SDK v3.0 - 技能基类
|
|
所有APP脚本的父类
|
|
"""
|
|
|
|
from abc import ABC, abstractmethod
|
|
from typing import Dict, Any, Optional
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class BaseSkill(ABC):
|
|
"""技能基类"""
|
|
|
|
# 子类必须定义
|
|
PACKAGE: str = "" # APP包名
|
|
NAME: str = "" # APP中文名
|
|
|
|
def __init__(self, device):
|
|
"""
|
|
初始化技能
|
|
|
|
Args:
|
|
device: uiautomator2设备对象
|
|
"""
|
|
self.d = device
|
|
self.d.implicitly_wait(10.0)
|
|
|
|
# ========== 抽象方法 ==========
|
|
|
|
@abstractmethod
|
|
async def send_message(self, to_id: str, content: str, msg_type: str = "text") -> Dict[str, Any]:
|
|
"""发送消息"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def get_messages(self, limit: int = 20) -> Dict[str, Any]:
|
|
"""获取消息列表"""
|
|
pass
|
|
|
|
# ========== 通用方法 ==========
|
|
|
|
def launch(self) -> bool:
|
|
"""启动APP"""
|
|
try:
|
|
self.d.app_start(self.PACKAGE)
|
|
self.d.sleep(2)
|
|
return True
|
|
except Exception as e:
|
|
logger.error(f"启动{self.NAME}失败: {e}")
|
|
return False
|
|
|
|
def close(self):
|
|
"""关闭APP"""
|
|
self.d.app_stop(self.PACKAGE)
|
|
|
|
def is_running(self) -> bool:
|
|
"""检查APP是否运行"""
|
|
return self.d.app_current()['package'] == self.PACKAGE
|
|
|
|
# ========== UI操作 ==========
|
|
|
|
def click(self, x: int, y: int):
|
|
"""点击坐标"""
|
|
self.d.click(x, y)
|
|
|
|
def click_text(self, text: str, timeout: float = 10) -> bool:
|
|
"""点击文字"""
|
|
try:
|
|
element = self.d(text=text)
|
|
if element.wait(timeout=timeout):
|
|
element.click()
|
|
return True
|
|
return False
|
|
except Exception as e:
|
|
logger.error(f"点击文字失败: {e}")
|
|
return False
|
|
|
|
def click_resource_id(self, resource_id: str) -> bool:
|
|
"""点击资源ID"""
|
|
try:
|
|
self.d(resourceId=resource_id).click()
|
|
return True
|
|
except Exception:
|
|
return False
|
|
|
|
def input_text(self, text: str, clear: bool = True):
|
|
"""输入文字"""
|
|
if clear:
|
|
self.d.clear_text()
|
|
self.d.send_keys(text)
|
|
|
|
def swipe(self, direction: str, scale: float = 0.8):
|
|
"""滑动"""
|
|
self.d.swipe_ext(direction, scale=scale)
|
|
|
|
def exists(self, text: str = None, resource_id: str = None) -> bool:
|
|
"""检查元素是否存在"""
|
|
if text:
|
|
return self.d(text=text).exists(timeout=3)
|
|
if resource_id:
|
|
return self.d(resourceId=resource_id).exists(timeout=3)
|
|
return False
|
|
|
|
def wait_for(self, text: str = None, resource_id: str = None, timeout: float = 10) -> bool:
|
|
"""等待元素出现"""
|
|
if text:
|
|
return self.d(text=text).wait(timeout=timeout)
|
|
if resource_id:
|
|
return self.d(resourceId=resource_id).wait(timeout=timeout)
|
|
return False
|
|
|
|
def screenshot(self) -> bytes:
|
|
"""截图"""
|
|
return self.d.screenshot(format='raw')
|
|
|
|
def get_ui_tree(self) -> str:
|
|
"""获取UI树"""
|
|
return self.d.dump_hierarchy()
|
|
|
|
def sleep(self, seconds: float):
|
|
"""等待"""
|
|
self.d.sleep(seconds)
|