commit 3c60d3c7d23f4251686f57302ed26b96ccfb6189
Author: zw <12345678>
Date: Fri Aug 1 13:43:51 2025 +0800
创建仓库
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b6bbb41
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,124 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+docs/.doctrees/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+.python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type checker
+.pytype/
+
+# Cython debug symbols
+cython_debug/
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/iOSAI.iml b/.idea/iOSAI.iml
new file mode 100644
index 0000000..6cb8b9a
--- /dev/null
+++ b/.idea/iOSAI.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..5dcfaf3
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..491e71f
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..a841d58
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Entity/DeviceModel.py b/Entity/DeviceModel.py
new file mode 100644
index 0000000..50644b8
--- /dev/null
+++ b/Entity/DeviceModel.py
@@ -0,0 +1,18 @@
+
+# 设备模型
+class DeviceModel(object):
+ def __init__(self, deviceId, screenPort, type):
+ super(DeviceModel, self).__init__()
+ self.deviceId = deviceId
+ self.screenPort = screenPort
+ # 1 添加 2删除
+ self.type = type
+
+
+ # 转字典
+ def toDict(self):
+ return {
+ 'deviceId': self.deviceId,
+ 'screenPort': self.screenPort,
+ 'type': self.type
+ }
\ No newline at end of file
diff --git a/Entity/ResultData.py b/Entity/ResultData.py
new file mode 100644
index 0000000..f0c19f2
--- /dev/null
+++ b/Entity/ResultData.py
@@ -0,0 +1,16 @@
+import json
+
+# 返回数据模型
+class ResultData(object):
+ def __init__(self, code=200, data=None, msg="获取成功"):
+ super(ResultData, self).__init__()
+ self.code = code
+ self.data = data
+ self.msg = msg
+
+ def toJson(self):
+ return json.dumps({
+ "code": self.code,
+ "data": self.data,
+ "msg": self.msg
+ }, ensure_ascii=False) # ensure_ascii=False 确保中文不会被转义
\ No newline at end of file
diff --git a/Entity/Variables.py b/Entity/Variables.py
new file mode 100644
index 0000000..3cc17e4
--- /dev/null
+++ b/Entity/Variables.py
@@ -0,0 +1,4 @@
+# Tik Tok app bundle id
+tikTokApp = "com.zhiliaoapp.musically"
+# wda apple bundle id
+WdaAppBundleId = "com.vv.wda.xctrunner"
diff --git a/Flask/FlaskService.py b/Flask/FlaskService.py
new file mode 100644
index 0000000..979adf8
--- /dev/null
+++ b/Flask/FlaskService.py
@@ -0,0 +1,175 @@
+import json
+import os
+import socket
+import threading
+from queue import Queue
+import tidevice
+import wda
+from flask import Flask, request
+from flask_cors import CORS
+from Entity.ResultData import ResultData
+from script.ScriptManager import ScriptManager
+
+app = Flask(__name__)
+CORS(app)
+
+listData = []
+dataQueue = Queue()
+
+def start_socket_listener():
+ port = int(os.getenv('FLASK_COMM_PORT', 0))
+ print(f"Received port from environment: {port}")
+ if port <= 0:
+ print("⚠️ 未获取到通信端口,跳过Socket监听")
+ return
+
+ try:
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
+ # 设置端口复用,避免端口被占用时无法绑定
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+
+ # 尝试绑定端口
+ try:
+ s.bind(('127.0.0.1', port))
+ print(f"[INFO] Socket successfully bound to port {port}")
+ except Exception as bind_error:
+ print(f"[ERROR] ❌ 端口绑定失败: {bind_error}")
+ return
+
+ # 开始监听
+ s.listen()
+ print(f"[INFO] Socket listener started on port {port}, waiting for connections...")
+
+ while True:
+ try:
+ print(f"[INFO] Waiting for a new connection on port {port}...")
+ conn, addr = s.accept()
+ print(f"[INFO] Connection accepted from: {addr}")
+
+ raw_data = conn.recv(1024).decode('utf-8').strip()
+ print(f"[INFO] Raw data received: {raw_data}")
+
+ data = json.loads(raw_data)
+ print(f"[INFO] Parsed data: {data}")
+ dataQueue.put(data)
+ except Exception as conn_error:
+ print(f"[ERROR] ❌ 连接处理失败: {conn_error}")
+ except Exception as e:
+ print(f"[ERROR] ❌ Socket服务启动失败: {e}")
+
+# 在独立线程中启动Socket服务
+listener_thread = threading.Thread(target=start_socket_listener, daemon=True)
+listener_thread.start()
+
+# 获取设备列表
+@app.route('/deviceList', methods=['GET'])
+def deviceList():
+ while not dataQueue.empty():
+ obj = dataQueue.get()
+ type = obj["type"]
+ if type == 1:
+ listData.append(obj)
+ else:
+ for data in listData:
+ if data.get("deviceId") == obj.get("deviceId") and data.get("screenPort") == obj.get("screenPort"):
+ listData.remove(data)
+ return ResultData(data=listData).toJson()
+
+# 获取设备应用列表
+@app.route('/deviceAppList', methods=['POST'])
+def deviceAppList():
+ param = request.get_json()
+ udid = param["udid"]
+ t = tidevice.Device(udid)
+
+ # 获取已安装的应用列表
+ apps = []
+ for app in t.installation.iter_installed():
+ apps.append({
+ "name": app.get("CFBundleDisplayName", "Unknown"),
+ "bundleId": app.get("CFBundleIdentifier", "Unknown"),
+ "version": app.get("CFBundleShortVersionString", "Unknown"),
+ "path": app.get("Path", "Unknown")
+ })
+
+ # 筛选非系统级应用(过滤掉以 com.apple 开头的系统应用)
+ non_system_apps = [app for app in apps if not app["bundleId"].startswith("com.apple")]
+ return ResultData(data=non_system_apps).toJson()
+
+# 打开置顶app
+@app.route('/launchApp', methods=['POST'])
+def launchApp():
+ body = request.get_json()
+ udid = body.get("udid")
+ bundleId = body.get("bundleId")
+ t = tidevice.Device(udid)
+ t.app_start(bundleId)
+ return ResultData(data="").toJson()
+
+# 回到首页
+@app.route('/toHome', methods=['POST'])
+def toHome():
+ body = request.get_json()
+ udid = body.get("udid")
+ client = wda.USBClient(udid)
+ client.home()
+ return ResultData(data="").toJson()
+
+# 点击事件
+@app.route('/tapAction', methods=['POST'])
+def tapAction():
+ body = request.get_json()
+ udid = body.get("udid")
+ x = body.get("x")
+ y = body.get("y")
+ client = wda.USBClient(udid)
+ session = client.session()
+ session.appium_settings({"snapshotMaxDepth": 0})
+ session.tap(x, y)
+ return ResultData(data="").toJson()
+
+# 拖拽事件
+@app.route('/swipeAction', methods=['POST'])
+def swipeAction():
+ body = request.get_json()
+ udid = body.get("udid")
+ direction = body.get("direction")
+ client = wda.USBClient(udid)
+ session = client.session()
+ session.appium_settings({"snapshotMaxDepth": 0})
+
+ if direction == 1:
+ session.swipe_up()
+ elif direction == 2:
+ session.swipe_left()
+ elif direction == 3:
+ session.swipe_down()
+ else:
+ session.swipe_right()
+ return ResultData(data="").toJson()
+
+# 长按事件
+@app.route('/longPressAction', methods=['POST'])
+def longPressAction():
+ body = request.get_json()
+ udid = body.get("udid")
+ x = body.get("x")
+ y = body.get("y")
+ client = wda.USBClient(udid)
+ session = client.session()
+ session.appium_settings({"snapshotMaxDepth": 5})
+ session.tap_hold(x,y,1.0)
+ return ResultData(data="").toJson()
+
+# 养号
+@app.route('/growAccount', methods=['POST'])
+def growAccount():
+ body = request.get_json()
+ udid = body.get("udid")
+
+ # 启动脚本
+ threading.Thread(target=ScriptManager.growAccount, args=(udid,)).start()
+ return ResultData(data="").toJson()
+
+if __name__ == '__main__':
+ app.run("0.0.0.0", port=5000, debug=True, use_reloader=False)
diff --git a/Module/DeviceInfo.py b/Module/DeviceInfo.py
new file mode 100644
index 0000000..381aaea
--- /dev/null
+++ b/Module/DeviceInfo.py
@@ -0,0 +1,96 @@
+import subprocess
+import threading
+import time
+import wda
+from tidevice import Usbmux
+from Entity.DeviceModel import DeviceModel
+from Entity.Variables import tikTokApp, WdaAppBundleId
+from Module.FlaskSubprocessManager import FlaskSubprocessManager
+
+threadLock = threading.Lock()
+
+class Deviceinfo(object):
+ def __init__(self):
+ self.deviceIndex = 0
+ # 投屏端口
+ self.screenProxy = 9110
+ # 存放pid的数组
+ self.pidList = []
+ # 设备列表
+ self.deviceArray = []
+ # 获取到县城管理类
+ self.manager = FlaskSubprocessManager.get_instance()
+ # 给前端的设备模型数组
+ self.deviceModelList = []
+
+ # 监听设备连接
+ def startDeviceListener(self):
+ while True:
+ lists = Usbmux().device_list()
+ # 添加设备逻辑
+ for device in lists:
+ if device not in self.deviceArray:
+ self.screenProxy += 1
+ self.connectDevice(device.udid)
+ self.deviceArray.append(device)
+ # 创建模型
+ model = DeviceModel(device.udid,self.screenProxy,type=1)
+ self.deviceModelList.append(model)
+ # 发送数据
+ self.manager.send(model.toDict())
+
+ # 处理拔出设备的逻辑
+ def removeDevice():
+ set1 = set(self.deviceArray)
+ set2 = set(lists)
+ difference = set1 - set2
+ differenceList = list(difference)
+ for i in differenceList:
+ for j in self.deviceArray:
+ # 判断是否为差异设备
+ if i.udid == j.udid:
+ # 从设备模型中删除数据
+ for a in self.deviceModelList:
+ if i.udid == a.deviceId:
+ a.type = 2
+ # 发送数据
+ self.manager.send(a.toDict())
+ self.deviceModelList.remove(a)
+
+ for k in self.pidList:
+ # 干掉端口短发进程
+ if j.udid == k["id"]:
+ target = k["target"]
+ target.kill()
+ self.pidList.remove(k)
+ # 删除已经拔出的设备
+ self.deviceArray.remove(j)
+
+ removeDevice()
+ time.sleep(1)
+
+ # 连接设备
+ def connectDevice(self, identifier):
+ d = wda.USBClient(identifier, 8100)
+ d.app_start(WdaAppBundleId)
+ time.sleep(2)
+ d.app_start(tikTokApp)
+ target = self.relayDeviceScreenPort()
+ self.pidList.append({
+ "target": target,
+ "id": identifier
+ })
+
+ # 转发设备端口
+ def relayDeviceScreenPort(self):
+ try:
+ command = f"iproxy.exe {self.screenProxy} 9100"
+ # 创建一个没有窗口的进程
+ startupinfo = subprocess.STARTUPINFO()
+ startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
+ startupinfo.wShowWindow = 0
+ r = subprocess.Popen(command, shell=True, startupinfo=startupinfo)
+ return r
+ except Exception as e:
+ print(e)
+ return 0
diff --git a/Module/FlaskSubprocessManager.py b/Module/FlaskSubprocessManager.py
new file mode 100644
index 0000000..32d6db7
--- /dev/null
+++ b/Module/FlaskSubprocessManager.py
@@ -0,0 +1,101 @@
+import subprocess
+import threading
+import atexit
+import json
+import os
+import socket
+import time
+from typing import Optional, Union, Dict, List
+
+class FlaskSubprocessManager:
+ _instance: Optional['FlaskSubprocessManager'] = None
+ _lock: threading.Lock = threading.Lock()
+
+ def __new__(cls):
+ with cls._lock:
+ if cls._instance is None:
+ cls._instance = super().__new__(cls)
+ cls._instance._init_manager()
+ return cls._instance
+
+ def _init_manager(self):
+ self.process: Optional[subprocess.Popen] = None
+ self.comm_port = self._find_available_port()
+ self._stop_event = threading.Event()
+ atexit.register(self.stop)
+
+ def _find_available_port(self):
+ """动态获取可用端口"""
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
+ s.bind(('0.0.0.0', 0))
+ return s.getsockname()[1]
+
+ def start(self):
+ """启动子进程(Windows兼容方案)"""
+ with self._lock:
+ if self.process is not None:
+ raise RuntimeError("子进程已在运行中!")
+ # 通过环境变量传递通信端口
+ env = os.environ.copy()
+ env['FLASK_COMM_PORT'] = str(self.comm_port)
+
+ self.process = subprocess.Popen(
+ ['python', 'Flask/FlaskService.py'], # 启动一个子进程 FlaskService.py
+ stdin=subprocess.PIPE, # 标准输入流,用于向子进程发送数据
+ stdout=subprocess.PIPE, # 标准输出流,用于接收子进程的输出
+ stderr=subprocess.PIPE, # 标准错误流,用于接收子进程的错误信息
+ text=True, # 以文本模式打开流,否则以二进制模式打开
+ bufsize=1, # 缓冲区大小设置为 1,表示行缓冲
+ encoding='utf-8', # 指定编码为 UTF-8,确保控制台输出不会报错
+ env=env # 指定子进程的环境变量
+ )
+ print(f"Flask子进程启动 (PID: {self.process.pid}, 通信端口: {self.comm_port})")
+
+ # 将日志通过主进程输出
+ def print_output():
+ while True:
+ output = self.process.stdout.readline()
+ if not output:
+ break
+ print(output.strip())
+
+ while True:
+ error = self.process.stderr.readline()
+ if not error:
+ break
+ print(f"Error: {error.strip()}")
+
+ threading.Thread(target=print_output, daemon=True).start()
+
+ def send(self, data: Union[str, Dict, List]) -> bool:
+ """通过Socket发送数据"""
+ try:
+ if not isinstance(data, str):
+ data = json.dumps(data)
+ # 等待子进程启动并准备好
+ time.sleep(1) # 延时1秒,根据实际情况调整
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
+ s.connect(('127.0.0.1', self.comm_port))
+ s.sendall((data + "\n").encode('utf-8'))
+ return True
+ except ConnectionRefusedError:
+ print(f"连接被拒绝,确保子进程在端口 {self.comm_port} 上监听")
+ return False
+ except Exception as e:
+ print(f"发送失败: {e}")
+ return False
+
+ def stop(self):
+ with self._lock:
+ if self.process and self.process.poll() is None:
+ print(f"[INFO] Stopping Flask child process (PID: {self.process.pid})...")
+ self.process.terminate()
+ self.process.wait()
+ print("[INFO] Flask child process stopped.")
+ self._stop_event.set()
+ else:
+ print("[INFO] No Flask child process to stop.")
+
+ @classmethod
+ def get_instance(cls) -> 'FlaskSubprocessManager':
+ return cls()
\ No newline at end of file
diff --git a/Module/Main.py b/Module/Main.py
new file mode 100644
index 0000000..8248797
--- /dev/null
+++ b/Module/Main.py
@@ -0,0 +1,11 @@
+from Module.DeviceInfo import Deviceinfo
+from Module.FlaskSubprocessManager import FlaskSubprocessManager
+
+if __name__ == "__main__":
+ print("启动flask")
+ manager = FlaskSubprocessManager.get_instance()
+ manager.start()
+
+ print("启动主线程")
+ info = Deviceinfo()
+ info.startDeviceListener()
\ No newline at end of file
diff --git a/Module/iproxy.exe b/Module/iproxy.exe
new file mode 100644
index 0000000..3527899
Binary files /dev/null and b/Module/iproxy.exe differ
diff --git a/resources/bgv.png b/resources/bgv.png
new file mode 100644
index 0000000..c334413
Binary files /dev/null and b/resources/bgv.png differ
diff --git a/resources/like.png b/resources/like.png
new file mode 100644
index 0000000..c3e59a3
Binary files /dev/null and b/resources/like.png differ
diff --git a/script/AiTools.py b/script/AiTools.py
new file mode 100644
index 0000000..94f1251
--- /dev/null
+++ b/script/AiTools.py
@@ -0,0 +1,109 @@
+import os
+import time
+import cv2
+import numpy as np
+from PIL import Image
+
+
+# 工具类
+class AiTools(object):
+
+ @classmethod
+ def find_image_in_image(
+ cls,
+ smallImageUrl,
+ bigImageUrl,
+ match_threshold=0.90,
+ consecutive_required=3,
+ scales=None
+ ):
+
+ if scales is None:
+ scales = [0.5, 0.75, 1.0, 1.25, 1.5]
+
+ template = cv2.imread(smallImageUrl, cv2.IMREAD_COLOR)
+ # if template is None:
+ # raise Exception(f"❌ 无法读取模板 '{smallImageUrl}'")
+
+ template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
+
+ cap = cv2.imread(bigImageUrl, cv2.IMREAD_COLOR)
+ # if not cap.isOpened():
+ # print(f"❌ 无法打开视频流: {bigImageUrl}")
+ # return None
+
+ detected_consecutive_frames = 0
+
+ print("🚀 正在检测爱心图标...")
+ while True:
+ print("死了")
+ ret, frame = cap.read()
+ if not ret or frame is None:
+ time.sleep(0.01)
+ continue
+ print("哈哈哈")
+ frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
+
+ current_frame_has_match = False
+ best_match_val = 0
+ best_match_loc = None
+ best_match_w_h = None
+ print("aaaaaaaaaaaa")
+ for scale in scales:
+ resized_template = cv2.resize(template_gray, (0, 0), fx=scale, fy=scale)
+ th, tw = resized_template.shape[:2]
+
+ if th > frame_gray.shape[0] or tw > frame_gray.shape[1]:
+ continue
+
+ result = cv2.matchTemplate(frame_gray, resized_template, cv2.TM_CCOEFF_NORMED)
+ _, max_val, _, max_loc = cv2.minMaxLoc(result)
+
+ if max_val > best_match_val:
+ best_match_val = max_val
+ best_match_loc = max_loc
+ best_match_w_h = (tw, th)
+ if max_val >= match_threshold:
+ current_frame_has_match = True
+ print("break 了")
+ break
+ print("bbbbbbbbbbbbbbbbbbbbbb")
+ if current_frame_has_match:
+ print("111111")
+ detected_consecutive_frames += 1
+ last_detection_info = (best_match_loc, best_match_w_h, best_match_val)
+ else:
+ print("2222222")
+ detected_consecutive_frames = 0
+ last_detection_info = None
+
+ if detected_consecutive_frames >= consecutive_required and last_detection_info:
+ print("333333333")
+ top_left, (w, h), match_val = last_detection_info
+ center_x = top_left[0] + w // 2
+ center_y = top_left[1] + h // 2
+
+ print(f"🎯 成功识别爱心图标: 中心坐标=({center_x}, {center_y}), 匹配度={match_val:.4f}")
+ return center_y, center_y
+ else:
+ return -1, -1
+ cap.release()
+ print("释放了")
+ return -1, -1
+
+
+
+ @classmethod
+ def imagePath(cls, name):
+ current_file_path = os.path.abspath(__file__)
+ # 获取当前文件所在的目录(即script目录)
+ current_dir = os.path.dirname(current_file_path)
+ # 由于script目录位于项目根目录下一级,因此需要向上一级目录移动两次
+ project_root = os.path.abspath(os.path.join(current_dir, '..'))
+ # 构建资源文件的完整路径,向上两级目录,然后进入 resources 目录
+ resource_path = os.path.abspath(os.path.join(project_root, 'resources', name + ".png")).replace('/', '\\\\')
+ return resource_path
+
+
+
+
diff --git a/script/ScriptManager.py b/script/ScriptManager.py
new file mode 100644
index 0000000..7ceacda
--- /dev/null
+++ b/script/ScriptManager.py
@@ -0,0 +1,46 @@
+import cv2
+import lxml
+import wda
+from lxml import etree
+
+from script.AiTools import AiTools
+
+
+# 脚本管理类
+class ScriptManager():
+ def __init__(self):
+ super().__init__()
+
+ # 养号
+ @classmethod
+ def growAccount(self, udid):
+ client = wda.USBClient(udid)
+ session = client.session()
+ session.appium_settings({"snapshotMaxDepth": 0})
+
+ deviceWidth = client.window_size().width
+ deviceHeight = client.window_size().height
+
+ img = client.screenshot()
+ tempPath = "resources/bgv.png"
+ img.save(tempPath)
+
+ bgvPath = AiTools.imagePath("bgv")
+ likePath = AiTools.imagePath("like")
+
+ x, y = AiTools.find_image_in_image(bgvPath, likePath)
+ print(x, y)
+ # client.tap(end[0] / 3 - 2, end[1] / 3 - 2)
+
+
+ # xml = session.source()
+ # print(xml)
+ # root = etree.fromstring(xml.encode('utf-8'))
+ # try:
+ # msg = client.xpath('label="收件箱"')
+ # msg.click()
+ # print(msg)
+ # except Exception as e:
+ # print(e)
+
+
diff --git a/script/screenshot.png b/script/screenshot.png
new file mode 100644
index 0000000..dc5d7f4
Binary files /dev/null and b/script/screenshot.png differ