| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- import json
- import uiautomator2 as u2
- class UiElement(object):
- def __init__(self, d: u2.Device, xpath: str = None, description: str = None, debug: bool = True, point: dict = None) -> None:
- x, y = 0, 0
- self.info = {}
- self.d = d
- self.debug = debug
- if point is not None:
- self.info['point'] = point
- self.info['xpath'] = xpath
- self.info['description'] = description
- return
- if xpath is not None:
- self.info['xpath'] = xpath
- el = d.xpath(xpath)
- x, y = el.center()
- elif description is not None:
- self.info['description'] = description
- el = d(description=description)
- x, y = el.center()
- self.info['point'] = {'x': x, 'y': y}
- def log(self, *args, sep=' ', end='\n', file=None):
- if self.debug:
- print(args, sep=sep, end=end, file=file)
- def click(self):
- """
- 点击
- """
- point = self.info['point']
- self.log("点击元素:", self.info)
- self.d.shell(f"input tap {point['x']} {point['y']}")
- def text(self, text: str = None):
- """
- 设置文本框内容
- text 文本内容
- """
- point = self.info['point']
- self.log("点击元素:", self.info)
- self.d.shell(f"input tap {point['x']} {point['y']}")
- self.log("设置文本:", text)
- self.d.shell(f"input text '{text}'") # 输入文本内容
- def clear(self, length: int = 10):
- """
- 清空文本框
- """
- point = self.info['point']
- self.log("点击元素:", self.info)
- self.d.shell(f"input tap {point['x'] + length} {point['y']}")
- self.log("清空文本框:")
- # 模拟删除键输入
- # self.d.shell(f"for i in {{1..{20}}}; do input keyevent KEYCODE_CLEAR; done") # 20 次删除键事件
- for _ in range(length):
- self.d.shell("input keyevent 67")
- class UiFactory(object):
- """
- 这个类对 u2.connect 的几个方法做了封装,主要解决耗时问题。
- 并且做缓存。不重复定位。
- 可以使用 load_point 方法 加载 xxx_point.json中,已经配置好的坐标。
- """
- _cache = {}
- def __init__(self, serial: str):
- """
- :param serial: 设备序列号。 例如 127.0.0.1:6555
- 可以通过 `adb devices` 获取
- """
- self.d = u2.connect(serial)
- pass
- def xpath(self, alisa: str, xpath: str = None):
- """
- 通过 xpath获取元素
- alisa 别名
- xpath 如果别名没有获取缓存, 会通过xpath 重新定位,并且缓存
- """
- if alisa in self._cache:
- return self._cache[alisa]
- el = UiElement(self.d, xpath=xpath)
- self._cache[alisa] = el
- return el
- def desc(self, alisa: str, desc: str = None):
- """
- 通过文本获取元素
- alisa 别名
- desc 如果别名没有获取缓存, 会通过description 重新定位,并且缓存
- """
- if alisa in self._cache:
- return self._cache[alisa]
- el = UiElement(self.d, description=desc)
- self._cache[alisa] = el
- return el
- def load_point(self, point_json: str):
- __tmp__ = {}
- with open(point_json, "r", encoding="utf-8") as f:
- __tmp__ = json.load(f)
- for k, v in __tmp__.items():
- if 'xpath' in v:
- self._cache[k] = UiElement(self.d, xpath=v['xpath'], point=v['point'])
- elif 'description' in v:
- self._cache[k] = UiElement(self.d, description=v['description'], point=v['point'])
- def save_point(self, point_json: str):
- """
- 保存坐标
- """
- __tmp__ = {}
- for k, v in self._cache.items():
- __tmp__[k] = v.info
- with open(point_json, "w", encoding="utf-8") as f:
- json.dump(__tmp__, f, ensure_ascii=False, indent=4)
- def check_app_running(self, appid: str):
- # 获取所有运行的APP
- running_apps = self.d.app_list_running()
- print("安装列表:", running_apps)
- # 如果app没有启动, 启动APP
- if appid not in running_apps:
- print(f"{appid} 重新启动")
- self.d.app_start(appid)
- return True
- return False
|