添加未信任状态,优化goios启动逻辑。 此版本为稳定版。

This commit is contained in:
2025-11-27 14:35:58 +08:00
parent 648f6cdfee
commit 68b985115e
2 changed files with 83 additions and 39 deletions

View File

@@ -69,33 +69,53 @@ class DeviceInfo:
LogManager.method_info("进入主循环", "listen", udid="system")
print("[Listen] 开始监听设备上下线...")
last_broadcast = 0.0 # 用来做“心跳全量同步”的时间戳
while True:
try:
usb = Usbmux().device_list()
# 只看 USB 连接的设备
online = {d.udid for d in usb if d.conn_type == ConnectionType.USB}
except Exception as e:
LogManager.warning(f"[device_list] 异常:{e}", udid="system")
print("[Listen] device_list 出错,本轮视为无设备,防止状态脏死")
usb = []
online = set()
time.sleep(1)
continue
now = time.time()
# 当前已知的设备(本轮循环开始时)
with self._lock:
known = set(self._models.keys())
# ---------- 1. 新设备 ----------
now = time.time()
# 1. 处理在线设备
for udid in online:
# 更新心跳时间
self._last_seen[udid] = now
if udid not in known:
try:
self._add_device(udid)
except Exception as e:
LogManager.warning(f"[Add] 处理设备 {udid} 异常: {e}", udid=udid)
print(f"[Add] 处理设备 {udid} 异常: {e}")
# ---------- 2. 可能离线设备 ----------
# 已经在列表里的设备,直接跳过“是否信任”检查
if udid in known:
continue
# 只对“新发现”的设备做一次信任检查
try:
if not self._is_trusted(udid):
# 未信任 / 未配对 / 暂时不可用,本轮直接跳过
LogManager.info(f"[Add] 设备未信任或未就绪,跳过本轮添加: {udid}", udid=udid)
print(f"[Add] 设备未信任或未就绪,跳过: {udid}")
continue
except Exception as e:
# 信任检查本身异常,也当作暂时未就绪处理
LogManager.warning(f"[Add] 检测设备 {udid} 信任状态异常: {e}", udid=udid)
print(f"[Add] 检测设备 {udid} 信任状态异常: {e}")
continue
# 确认“已信任”的新设备,才真正走 _add_device
try:
self._add_device(udid)
except Exception as e:
# 单设备异常不能干掉整个循环
LogManager.warning(f"[Add] 处理设备 {udid} 异常: {e}", udid=udid)
print(f"[Add] 处理设备 {udid} 异常: {e}")
# 2. 处理可能离线的设备(只看本轮开始时 known 里的)
for udid in list(known):
if udid not in online:
last = self._last_seen.get(udid, 0)
@@ -106,17 +126,26 @@ class DeviceInfo:
LogManager.method_error(f"移除失败:{e}", "listen", udid=udid)
print(f"[Remove] 移除失败 {udid}: {e}")
# ---------- 3. 心跳:每 5 秒强制同步一次到 Flask ----------
if now - last_broadcast > 5.0:
try:
self._manager_send()
except Exception as e:
print(f"[Listen] 周期同步到 Flask 失败: {e}")
else:
last_broadcast = now
time.sleep(1)
# 判断设备是否信任
def _is_trusted(self, udid: str) -> bool:
try:
d = tidevice.Device(udid)
# 随便读一个需要 lockdown/配对的字段
_ = d.product_version # 或 d.info视你当前 tidevice 版本而定
return True
except Exception as e:
msg = str(e)
# 这里只是示意,你可以根据你本地真实报错关键字再精细一点
if "NotTrusted" in msg or "Please trust" in msg or "InvalidHostID" in msg:
print(f"[Trust] 设备未信任udid={udid}, err={msg}")
return False
# 如果是别的错误(比如瞬时通信异常),我倾向于当作“暂时不信任”,避免把有问题的设备加进去
print(f"[Trust] 检测信任状态出错,当作未信任处理 udid={udid}, err={msg}")
return False
# ==========================
# 添加设备
# ==========================

View File

@@ -4,13 +4,15 @@ import time
import threading
import subprocess
from typing import Optional, Callable
from Entity.Variables import WdaAppBundleId
class IOSActivator:
"""
给 iOS17+ 用的 go-ios 激活器(单例):
- 维护一条全局 tunnel 进程
- 流程tunnel start -> pair(重试) -> image auto(致命) -> runwda(多次重试+日志判定成功)
- 流程tunnel start -> pair(可多次重试) -> image auto(致命) -> runwda(多次重试+日志判定成功)
- WDA 启动成功后触发回调 on_wda_ready(udid)
"""
@@ -28,13 +30,13 @@ class IOSActivator:
return cls._instance
def __init__(
self,
ios_path: Optional[str] = None,
pair_timeout: int = 60, # 配对最多等多久
pair_retry_interval: int = 3, # 配对重试间隔
runwda_max_retry: int = 10, # runwda 最大重试次数
runwda_retry_interval: int = 3,# runwda 重试间隔
runwda_wait_timeout: int = 25 # 单次 runwda 等待“成功日志”的超时时间
self,
ios_path: Optional[str] = None,
pair_timeout: int = 60, # 配对最多等多久
pair_retry_interval: int = 3, # 配对重试间隔
runwda_max_retry: int = 10, # runwda 最大重试次数
runwda_retry_interval: int = 3, # runwda 重试间隔
runwda_wait_timeout: int = 25 # 单次 runwda 等待“成功日志”的超时时间
):
if getattr(self, "_inited", False):
return
@@ -59,18 +61,25 @@ class IOSActivator:
self._lock = threading.Lock()
# Windows 隐藏黑框
# ========= 关键:这里改成“真正隐藏窗口”的安全版 =========
self._creationflags = 0
self._startupinfo = None
if os.name == "nt":
try:
# 只用 CREATE_NO_WINDOW不搞 DETACHED_PROCESS / NEW_PROCESS_GROUP 之类的骚操作
self._creationflags = subprocess.CREATE_NO_WINDOW # type: ignore[attr-defined]
except Exception:
self._creationflags = 0
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW # type: ignore[attr-defined]
try:
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW # type: ignore[attr-defined]
except Exception:
# 某些极端环境下可能没有 STARTF_USESHOWWINDOW忽略即可
pass
si.wShowWindow = 0 # SW_HIDE
self._startupinfo = si
# ========= 关键部分结束 =========
self._inited = True
@@ -134,8 +143,9 @@ class IOSActivator:
print(f"[ios][{name}] 读取 stderr 异常: {e}")
def _spawn_tunnel(self):
"""启动 / 复用全局 tunnel"""
"""启动 / 复用全局 tunnel(不隐藏窗口)"""
with IOSActivator._tunnel_lock:
# 已有并且还在跑就复用
if IOSActivator._tunnel_proc is not None and IOSActivator._tunnel_proc.poll() is None:
print("[ios] tunnel 已经在运行,跳过重新启动")
return
@@ -148,8 +158,8 @@ class IOSActivator:
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
creationflags=self._creationflags,
startupinfo=self._startupinfo,
creationflags=self._creationflags, # 0不隐藏
startupinfo=self._startupinfo, # None不隐藏
)
except Exception as e:
print("[ios] 启动 tunnel 失败(忽略):", e)
@@ -158,6 +168,7 @@ class IOSActivator:
IOSActivator._tunnel_proc = proc
print("[ios] tunnel 启动成功, PID=", proc.pid)
# 后台吃日志
threading.Thread(
target=self._drain_process_output,
args=(proc, "tunnel"),
@@ -181,6 +192,10 @@ class IOSActivator:
)
text = (out or "") + "\n" + (err or "")
# 打印一份完整输出,方便调试
if text.strip():
print("[ios][pair] output:\n", text.strip())
if "Successfully paired" in text:
print(f"[ios] 设备 {udid} 配对成功")
return
@@ -238,7 +253,7 @@ class IOSActivator:
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
creationflags=self._creationflags,
creationflags=self._creationflags, # 0不隐藏
startupinfo=self._startupinfo,
)
except Exception as e:
@@ -255,7 +270,7 @@ class IOSActivator:
continue
print(f"[WDA-LOG] {line}")
lower = line.lower()
# 这里是你实测的“成功特征”
# 你实测的“成功特征”
if "got capabilities" in lower or '"authorized":true' in lower:
success_evt.set()
print(f"[ios] 捕获到 WDA 启动成功日志({tag})udid={udid}")
@@ -316,7 +331,7 @@ class IOSActivator:
def activate_ios17(self, udid: str, on_wda_ready: Optional[Callable[[str], None]] = None) -> None:
print(f"[WDA] iOS17+ 激活开始udid={udid}, 回调={on_wda_ready}")
# 1. tunnel
# 1. 先确保 tunnel 在跑
self._spawn_tunnel()
# 2. 配对