1
0

abs_ui.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. # 定义抽象类
  2. import json
  3. import logging
  4. from abc import ABC, abstractmethod
  5. import uiautomator2 as u2
  6. class AbsUi(ABC):
  7. def __init__(self, serial: str):
  8. """
  9. :param serial: 设备序列号。 例如 127.0.0.1:6555
  10. 可以通过 `adb devices` 获取
  11. """
  12. # u2.logger.setLevel(logging.DEBUG)
  13. # 屏幕高度
  14. self.height = 0
  15. # 屏幕宽度
  16. self.width = 0
  17. self.d = u2.connect(serial)
  18. self._points = {}
  19. self.point_path = 'point.json'
  20. self.enable_click_monitor()
  21. self._func = []
  22. def enable_click_monitor(self):
  23. """
  24. 启用点击监控,在屏幕上显示点击位置
  25. """
  26. # self.d.settings['operation_delay'] = (0.5, 0.5) # 增加操作延迟以便观察
  27. self.d.debug = True
  28. self.d.toast.show('点击监控已启用') # 显示提示
  29. # 确保有悬浮窗权限
  30. self.d.set_fastinput_ime(True) # 启用ime
  31. self.d.show_float_window(True) # 显示悬浮窗
  32. # 可选:打开开发者选项中的"指针位置"
  33. self.d.shell('settings put system pointer_location 1')
  34. def to_top_swipe(self):
  35. """
  36. 滑动到屏幕最顶部,通过多次滑动确保到达顶部
  37. """
  38. width, height = self.get_screen_size()
  39. # 循环滑动直到无法继续滑动
  40. for _ in range(3):
  41. self.d.swipe(width // 2, height * 0.8, width // 2, height) # 向上滑动
  42. # 短暂等待确保滑动完成
  43. self.d.sleep(0.1)
  44. def click_point(self, x: int, y: int):
  45. """
  46. 点击指定坐标
  47. :param x: x坐标
  48. :param y: y坐标
  49. """
  50. self.d.click(x, y)
  51. def click_xpath(self, xpath: str):
  52. """
  53. 点击指定xpath
  54. """
  55. el = self.d.xpath(xpath).get()
  56. if el:
  57. el.click()
  58. else:
  59. logging.warning(f"未找到元素: {xpath}")
  60. def to_next_swipe(self):
  61. """
  62. 向上滑动一屏
  63. """
  64. width, height = self.get_screen_size()
  65. # 从屏幕下方向上滑动到顶部
  66. self.d.swipe(width // 2, height * 0.8, width // 2, height * 0.2, duration=0.1) # 向上滑动
  67. def get_screen_size(self):
  68. """
  69. 获取屏幕尺寸,宽度和高度
  70. """
  71. self.width, self.height = self.d.window_size()
  72. logging.info(f"屏幕尺寸: {self.width}x{self.height}")
  73. return self.width, self.height
  74. def drag_slider_ext(self, start_x: int, start_y: int, end_x: int, end_y: int, steps: int = 50):
  75. """
  76. 精确拖动滑块
  77. :param start_x: 起始x坐标
  78. :param start_y: 起始y坐标
  79. :param end_x: 结束x坐标
  80. :param end_y: 结束y坐标
  81. :param steps: 步数,值越大滑动越平滑
  82. """
  83. self.d.swipe_ext(start_x, start_y, end_x, end_y, steps)
  84. def add_point(self, point=None):
  85. """
  86. 添加坐标点
  87. point = {
  88. "name": "",
  89. "x": 0,
  90. "y": 0,
  91. "desc": "",
  92. "xpath": ""
  93. }
  94. """
  95. logging.info("保存坐标点: %s", point)
  96. self._points[point['name']] = point
  97. def add_func(self, func):
  98. """
  99. 添加坐标点采集函数
  100. """
  101. self._func.append(func)
  102. def save_point(self):
  103. """
  104. 保存坐标
  105. """
  106. self.to_top_swipe()
  107. self.d.sleep(2)
  108. for func in self._func:
  109. func()
  110. __tmp__ = {}
  111. for k, v in self._points.items():
  112. __tmp__[k] = v
  113. with open(self.point_path, "w", encoding="utf-8") as f:
  114. json.dump(__tmp__, f, ensure_ascii=False, indent=4)
  115. def get_point(self, info: dict):
  116. """
  117. 获取坐标点
  118. info 数据结构
  119. {
  120. "name": "btn_mairu_kaiduo",
  121. "desc": "买入/开多",
  122. "xpath": '//*[@content-desc="买入/开多"]'
  123. """
  124. el = self.d.xpath(info['xpath']).get()
  125. x, y = el.center()
  126. self.add_point({
  127. "name": info['name'],
  128. "x": x,
  129. "y": y,
  130. "desc": info['desc'],
  131. "xpath": info['xpath'],
  132. })
  133. return x, y