| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- # 定义抽象类
- import json
- import logging
- from abc import ABC, abstractmethod
- import uiautomator2 as u2
- class AbsUi(ABC):
- def __init__(self, serial: str):
- """
- :param serial: 设备序列号。 例如 127.0.0.1:6555
- 可以通过 `adb devices` 获取
- """
- # u2.logger.setLevel(logging.DEBUG)
- # 屏幕高度
- self.height = 0
- # 屏幕宽度
- self.width = 0
- self.d = u2.connect(serial)
- self._points = {}
- self.point_path = 'point.json'
- self.enable_click_monitor()
- self._func = []
- def enable_click_monitor(self):
- """
- 启用点击监控,在屏幕上显示点击位置
- """
- # self.d.settings['operation_delay'] = (0.5, 0.5) # 增加操作延迟以便观察
- self.d.debug = True
- self.d.toast.show('点击监控已启用') # 显示提示
- # 确保有悬浮窗权限
- self.d.set_fastinput_ime(True) # 启用ime
- self.d.show_float_window(True) # 显示悬浮窗
- # 可选:打开开发者选项中的"指针位置"
- self.d.shell('settings put system pointer_location 1')
- def to_top_swipe(self):
- """
- 滑动到屏幕最顶部,通过多次滑动确保到达顶部
- """
- width, height = self.get_screen_size()
- # 循环滑动直到无法继续滑动
- for _ in range(3):
- self.d.swipe(width // 2, height * 0.8, width // 2, height) # 向上滑动
- # 短暂等待确保滑动完成
- self.d.sleep(0.1)
- def click_point(self, x: int, y: int):
- """
- 点击指定坐标
- :param x: x坐标
- :param y: y坐标
- """
- self.d.click(x, y)
- def click_xpath(self, xpath: str):
- """
- 点击指定xpath
- """
- el = self.d.xpath(xpath).get()
- if el:
- el.click()
- else:
- logging.warning(f"未找到元素: {xpath}")
- def to_next_swipe(self):
- """
- 向上滑动一屏
- """
- width, height = self.get_screen_size()
- # 从屏幕下方向上滑动到顶部
- self.d.swipe(width // 2, height * 0.8, width // 2, height * 0.2, duration=0.1) # 向上滑动
- def get_screen_size(self):
- """
- 获取屏幕尺寸,宽度和高度
- """
- self.width, self.height = self.d.window_size()
- logging.info(f"屏幕尺寸: {self.width}x{self.height}")
- return self.width, self.height
- def drag_slider_ext(self, start_x: int, start_y: int, end_x: int, end_y: int, steps: int = 50):
- """
- 精确拖动滑块
- :param start_x: 起始x坐标
- :param start_y: 起始y坐标
- :param end_x: 结束x坐标
- :param end_y: 结束y坐标
- :param steps: 步数,值越大滑动越平滑
- """
- self.d.swipe_ext(start_x, start_y, end_x, end_y, steps)
- def add_point(self, point=None):
- """
- 添加坐标点
- point = {
- "name": "",
- "x": 0,
- "y": 0,
- "desc": "",
- "xpath": ""
- }
- """
- logging.info("保存坐标点: %s", point)
- self._points[point['name']] = point
- def add_func(self, func):
- """
- 添加坐标点采集函数
- """
- self._func.append(func)
- def save_point(self):
- """
- 保存坐标
- """
- self.to_top_swipe()
- self.d.sleep(2)
- for func in self._func:
- func()
- __tmp__ = {}
- for k, v in self._points.items():
- __tmp__[k] = v
- with open(self.point_path, "w", encoding="utf-8") as f:
- json.dump(__tmp__, f, ensure_ascii=False, indent=4)
- def get_point(self, info: dict):
- """
- 获取坐标点
- info 数据结构
- {
- "name": "btn_mairu_kaiduo",
- "desc": "买入/开多",
- "xpath": '//*[@content-desc="买入/开多"]'
- """
- el = self.d.xpath(info['xpath']).get()
- x, y = el.center()
- self.add_point({
- "name": info['name'],
- "x": x,
- "y": y,
- "desc": info['desc'],
- "xpath": info['xpath'],
- })
- return x, y
|