完善tidevice逻辑

This commit is contained in:
2025-09-23 20:17:33 +08:00
parent b0525ce817
commit 0d2782ddb8
13 changed files with 144 additions and 49 deletions

8
.idea/workspace.xml generated
View File

@@ -6,9 +6,14 @@
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="eceeff5e-51c1-459c-a911-d21ec090a423" name="Changes" comment="20250904-初步功能已完成"> <list default="true" id="eceeff5e-51c1-459c-a911-d21ec090a423" name="Changes" comment="20250904-初步功能已完成">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Module/DeviceInfo.py" beforeDir="false" afterPath="$PROJECT_DIR$/Module/DeviceInfo.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Module/FlaskService.py" beforeDir="false" afterPath="$PROJECT_DIR$/Module/FlaskService.py" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Module/FlaskService.py" beforeDir="false" afterPath="$PROJECT_DIR$/Module/FlaskService.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Module/Main.py" beforeDir="false" afterPath="$PROJECT_DIR$/Module/Main.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Utils/LogManager.py" beforeDir="false" afterPath="$PROJECT_DIR$/Utils/LogManager.py" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Utils/LogManager.py" beforeDir="false" afterPath="$PROJECT_DIR$/Utils/LogManager.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/script/ScriptManager.py" beforeDir="false" afterPath="$PROJECT_DIR$/script/ScriptManager.py" afterDir="false" /> <change beforePath="$PROJECT_DIR$/build-tidevice.bat" beforeDir="false" afterPath="$PROJECT_DIR$/build-tidevice.bat" afterDir="false" />
<change beforePath="$PROJECT_DIR$/build.bat" beforeDir="false" afterPath="$PROJECT_DIR$/build.bat" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/tidevice.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/tidevice.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/tidevice_entry.py" beforeDir="false" afterPath="$PROJECT_DIR$/tidevice_entry.py" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -86,6 +91,7 @@
<recent name="C:\Users\zhangkai\Desktop\20250916ios\iOSAI\resources" /> <recent name="C:\Users\zhangkai\Desktop\20250916ios\iOSAI\resources" />
</key> </key>
<key name="MoveFile.RECENT_KEYS"> <key name="MoveFile.RECENT_KEYS">
<recent name="E:\code\Python\iOSAi" />
<recent name="E:\Code\python\iOSAI\resources" /> <recent name="E:\Code\python\iOSAI\resources" />
<recent name="E:\Code\python\iOSAI" /> <recent name="E:\Code\python\iOSAI" />
</key> </key>

View File

@@ -6,11 +6,9 @@ import time
from concurrent.futures import ThreadPoolExecutor, as_completed from concurrent.futures import ThreadPoolExecutor, as_completed
from pathlib import Path from pathlib import Path
from typing import Dict, Optional, List from typing import Dict, Optional, List
import wda import wda
from tidevice import Usbmux, ConnectionType from tidevice import Usbmux, ConnectionType
from tidevice._device import BaseDevice from tidevice._device import BaseDevice
from Entity.DeviceModel import DeviceModel from Entity.DeviceModel import DeviceModel
from Module.FlaskSubprocessManager import FlaskSubprocessManager from Module.FlaskSubprocessManager import FlaskSubprocessManager
from Utils.LogManager import LogManager from Utils.LogManager import LogManager
@@ -19,15 +17,12 @@ from Utils.LogManager import LogManager
class DeviceInfo: class DeviceInfo:
def __init__(self): def __init__(self):
self._port = 9110 self._port = 9110
self._models: Dict[str, DeviceModel] = {} # udid -> model self._models: Dict[str, DeviceModel] = {}
self._procs: Dict[str, subprocess.Popen] = {} # udid -> iproxy proc self._procs: Dict[str, subprocess.Popen] = {}
self._manager = FlaskSubprocessManager.get_instance() self._manager = FlaskSubprocessManager.get_instance()
self._iproxy_path = self._find_iproxy() self._iproxy_path = self._find_iproxy()
self._pool = ThreadPoolExecutor(max_workers=6) self._pool = ThreadPoolExecutor(max_workers=6)
# 可选10 秒一次扫野进程
threading.Thread(target=self._janitor, daemon=True).start()
# ---------------- 主循环 ---------------- # ---------------- 主循环 ----------------
def listen(self): def listen(self):
while True: while True:
@@ -89,13 +84,20 @@ class DeviceInfo:
except Exception: except Exception:
return 828, 1792, 2.0 return 828, 1792, 2.0
...
# ---------------- 原来代码不变,只替换下面一个函数 ----------------
def _start_iproxy(self, udid: str, port: int) -> Optional[subprocess.Popen]: def _start_iproxy(self, udid: str, port: int) -> Optional[subprocess.Popen]:
try: try:
# 隐藏窗口的核心参数
kw = {"creationflags": subprocess.CREATE_NO_WINDOW}
return subprocess.Popen( return subprocess.Popen(
[self._iproxy_path, "-u", udid, str(port), "9100"], [self._iproxy_path, "-u", udid, str(port), "9100"],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
**kw
) )
except Exception: except Exception as e:
print(e)
return None return None
def _kill(self, proc: Optional[subprocess.Popen]): def _kill(self, proc: Optional[subprocess.Popen]):
@@ -124,16 +126,11 @@ class DeviceInfo:
base = Path(__file__).resolve().parent.parent base = Path(__file__).resolve().parent.parent
name = "iproxy.exe" name = "iproxy.exe"
path = base / "resources" / "iproxy" / name path = base / "resources" / "iproxy" / name
print(str(path))
if path.is_file(): if path.is_file():
return str(path) return str(path)
raise FileNotFoundError(f"iproxy 不存在: {path}") raise FileNotFoundError(f"iproxy 不存在: {path}")
# ---------------- janitor扫野进程 ----------------
def _janitor(self):
while True:
time.sleep(10)
self._cleanup_orphan_iproxy()
# ------------ Windows 专用:列出所有 iproxy 命令行 ------------ # ------------ Windows 专用:列出所有 iproxy 命令行 ------------
def _get_all_iproxy_cmdlines(self) -> List[str]: def _get_all_iproxy_cmdlines(self) -> List[str]:
try: try:

View File

@@ -2,12 +2,10 @@ import json
import os import os
import socket import socket
import threading import threading
import time
from pathlib import Path from pathlib import Path
from queue import Queue from queue import Queue
from typing import Any, Dict from typing import Any, Dict
from Entity.AnchorModel import AnchorModel
from Utils.AiUtils import AiUtils from Utils.AiUtils import AiUtils
from Utils.IOSAIStorage import IOSAIStorage from Utils.IOSAIStorage import IOSAIStorage
from Utils.LogManager import LogManager from Utils.LogManager import LogManager
@@ -19,7 +17,7 @@ from Entity.ResultData import ResultData
from Utils.ControlUtils import ControlUtils from Utils.ControlUtils import ControlUtils
from Utils.ThreadManager import ThreadManager from Utils.ThreadManager import ThreadManager
from script.ScriptManager import ScriptManager from script.ScriptManager import ScriptManager
from Entity.Variables import anchorList, prologueList, addModelToAnchorList, removeModelFromAnchorList from Entity.Variables import addModelToAnchorList
import Entity.Variables as ev import Entity.Variables as ev
from Utils.JsonUtils import JsonUtils from Utils.JsonUtils import JsonUtils
@@ -268,7 +266,7 @@ def stopScript():
udid = body.get("udid") udid = body.get("udid")
LogManager.method_info(f"接口收到 /stopScript udid={udid}", method="task") LogManager.method_info(f"接口收到 /stopScript udid={udid}", method="task")
code, msg = ThreadManager.stop(udid) code, msg = ThreadManager.stop(udid)
return ResultData(code=code, data="", message=msg).toJson() return ResultData(code=code, data=[], message=msg).toJson()
# 关注打招呼 # 关注打招呼
@@ -576,7 +574,7 @@ def delete_last_message():
def stopAllTask(): def stopAllTask():
idList = request.get_json() idList = request.get_json()
code, msg = ThreadManager.batch_stop(idList) code, msg = ThreadManager.batch_stop(idList)
return ResultData(code, "", msg).toJson() return ResultData(code, [], msg).toJson()
# @app.route("/killWda", methods=['POST']) # @app.route("/killWda", methods=['POST'])

View File

@@ -1,6 +1,10 @@
import os import os
import sys import sys
from pathlib import Path from pathlib import Path
import wda
import tidevice
from Module.DeviceInfo import DeviceInfo from Module.DeviceInfo import DeviceInfo
from Module.FlaskSubprocessManager import FlaskSubprocessManager from Module.FlaskSubprocessManager import FlaskSubprocessManager
from Utils.DevDiskImageDeployer import DevDiskImageDeployer from Utils.DevDiskImageDeployer import DevDiskImageDeployer
@@ -27,6 +31,27 @@ if "--role=flask" in sys.argv:
# 项目入口 # 项目入口
if __name__ == "__main__": if __name__ == "__main__":
wda.debug = True
# 1. 拿到打包后的临时目录
base_dir = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
# 2. 构造 resources/iproxy 绝对路径
iproxy_dir = os.path.join(base_dir, 'resources', 'iproxy')
# 3. 如果目录存在就追加到 PATH
if os.path.isdir(iproxy_dir):
# Windows 用 ; 分隔Linux/Mac 用 :
sep = os.pathsep
old_path = os.environ.get('PATH', '')
# 避免重复追加
if iproxy_dir not in old_path:
os.environ['PATH'] = old_path + sep + iproxy_dir
else:
# 调试用,打包后可删掉
print(f'warning: {iproxy_dir} not found', file=sys.stderr)
# 添加iOS开发包到电脑上 # 添加iOS开发包到电脑上
deployer = DevDiskImageDeployer(verbose=True) deployer = DevDiskImageDeployer(verbose=True)
deployer.deploy_all() deployer.deploy_all()

View File

@@ -26,7 +26,7 @@ def _force_utf8_everywhere():
except Exception: except Exception:
pass pass
_force_utf8_everywhere() # _force_utf8_everywhere()
class LogManager: class LogManager:
""" """

View File

@@ -6,4 +6,8 @@ pyinstaller -F -n tidevice ^
--collect-all tidevice ^ --collect-all tidevice ^
--noconsole ^ --noconsole ^
--add-data="C:\Users\milk\AppData\Local\Programs\Python\Python312\Lib\site-packages\tidevice;tidevice" ^ --add-data="C:\Users\milk\AppData\Local\Programs\Python\Python312\Lib\site-packages\tidevice;tidevice" ^
tidevice_entry.py tidevice_entry.py
@REM pyinstaller -F -n tidevice -noconsole ^
@REM --collect-all tidevice ^
@REM tidevice_entry.py

View File

@@ -1,18 +1,62 @@
python -m nuitka "Module/Main.py" ^ @REM python -m nuitka "Module/Main.py" ^
--standalone ^ @REM --standalone ^
--msvc=latest ^ @REM --msvc=latest ^
--windows-console-mode=disable ^ @REM --windows-console-mode=disable ^
--output-filename=IOSAI ^ @REM --output-filename=IOSAI ^
--include-package=Module,Utils,Entity,script ^ @REM --include-package=Module,Utils,Entity,script ^
--include-module=flask ^ @REM --include-module=flask ^
--include-module=flask_cors ^ @REM --include-module=flask_cors ^
--include-module=lxml ^ @REM --include-module=lxml ^
--include-module=lxml.etree ^ @REM --include-module=lxml.etree ^
--include-module=requests ^ @REM --include-module=requests ^
--include-module=urllib3 ^ @REM --include-module=urllib3 ^
--include-module=certifi ^ @REM --include-module=certifi ^
--include-module=idna ^ @REM --include-module=idna ^
--include-data-dir="E:/code/Python/iOSAI/SupportFiles=SupportFiles" ^ @REM --include-data-files="E:/code/Python/iOSAI/.venv/Scripts/tidevice.exe=tidevice.exe" ^
--include-data-dir="E:/code/Python/iOSAI/resources=resources" ^ @REM --include-data-dir="E:/code/Python/iOSAI/.venv/Scripts=Scripts" ^
--include-data-files="E:/code/Python/iOSAI/resources/iproxy/*=resources/iproxy/" ^ @REM --include-data-dir="E:/code/Python/iOSAI/SupportFiles=SupportFiles" ^
--windows-icon-from-ico="E:/code/Python/iOSAI/resources/icon.ico" @REM --include-data-dir="E:/code/Python/iOSAI/resources=resources" ^
@REM --include-data-files="E:/code/Python/iOSAI/resources/iproxy/*=resources/iproxy/" ^
@REM --windows-icon-from-ico="E:/code/Python/iOSAI/resources/icon.ico"
@REM python -m nuitka "Module/Main.py" ^
@REM --standalone ^
@REM --msvc=latest ^
@REM --windows-console-mode=force ^
@REM --output-filename=IOSAI ^
@REM --include-package=Module,Utils,Entity,script ^
@REM --include-module=flask ^
@REM --include-module=wda ^
@REM --include-module=flask_cors ^
@REM --include-module=lxml ^
@REM --include-module=lxml.etree ^
@REM --include-module=requests ^
@REM --include-module=urllib3 ^
@REM --include-module=certifi ^
@REM --include-module=idna ^
@REM --include-module=setuptools ^
@REM --include-module=tidevice ^
@REM --include-data-dir=resources=resources ^
@REM --include-data-dir=SupportFiles=SupportFiles ^
@REM --include-data-files="E:/code/Python/iOSAi/resources/iproxy/*=resources/iproxy/" ^
@REM --include-data-files=resources/icon.ico=resources/icon.ico ^
@REM --jobs=20 ^
@REM --windows-icon-from-ico=resources/icon.ico
python -m nuitka Module\Main.py ^
--standalone ^
--msvc=latest ^
--windows-console-mode=force ^
--output-filename=IOSAI ^
--include-package=Module,Utils,Entity,script ^
--include-module=flask,wda,flask_cors,lxml,lxml.etree,requests,urllib3,certifi,idna,setuptools,tidevice ^
--include-data-dir=resources=resources ^
--include-data-dir=SupportFiles=SupportFiles ^
--include-data-files="E:/code/Python/iOSAi/resources/iproxy/*=resources/iproxy/" ^
--include-data-files=resources/icon.ico=resources/icon.ico ^
--jobs=20 ^
--windows-icon-from-ico=resources/icon.ico

Binary file not shown.

View File

@@ -1,16 +1,37 @@
# import sys, traceback, os
# from tidevice.__main__ import main
#
# import sys, os
# with open(os.path.join(os.path.dirname(sys.executable), '_entry_log.txt'), 'w') as f:
# f.write('entry reached\nargs=%r\n' % sys.argv)
#
# if hasattr(sys, 'frozen') and sys.executable.endswith('.exe'):
# # 打包后且无控制台时,把标准流扔掉
# sys.stdout = sys.stderr = open(os.devnull, 'w', encoding='utf-8')
#
# if __name__ == "__main__":
# try:
# main()
# except Exception:
# # 把 traceback 写到日志文件,但**不输出到控制台**
# with open(os.path.expanduser("~/tidevice_crash.log"), "a", encoding="utf-8") as f:
# traceback.print_exc(file=f)
# # 静默退出,返回码 1
# sys.exit(1)
import sys, traceback, os import sys, traceback, os
from tidevice.__main__ import main from tidevice.__main__ import main
if hasattr(sys, 'frozen') and sys.executable.endswith('.exe'):
# 打包后且无控制台时,把标准流扔掉
sys.stdout = sys.stderr = open(os.devnull, 'w', encoding='utf-8')
if __name__ == "__main__": if __name__ == "__main__":
try: try:
main() main()
except Exception: except SystemExit as se: # 允许正常 exit(code) 继续生效
# 把 traceback 写到日志文件,但**不输出到控制台** raise
with open(os.path.expanduser("~/tidevice_crash.log"), "a", encoding="utf-8") as f: except Exception: # 真正异常时才写日志
crash_log = os.path.expanduser("~/tidevice_crash.log")
with open(crash_log, "a", encoding="utf-8") as f:
f.write("----- tidevice exe crash -----\n")
traceback.print_exc(file=f) traceback.print_exc(file=f)
# 静默退出,返回码 1 # 如果想让用户知道崩溃了,可以返回非 0
sys.exit(1) sys.exit(1)