• v1.1.1 e6880efdc6

    admin released this 2026-10-29 07:51:01 +00:00 | 0 commits to main since this release

    v1.1.1 变更清单(Windows)

    本次只在 Windows 端更新。macOS 端尚未重新构建,等你更新 mac 后一起发布。
    版本号 1.1.0 → 1.1.1(bug 修复 + 交互改进)。


    一、修复的 Bug

    严重(会导致功能错误 / 给错设备下发定位)

    1. 切换设备时复用了上一台设备的 RSD → 给错误的手机下发定位
    core/server.py: provider_for()

    原逻辑只在「没有任何隧道」时才调 tunnel.ensure(device.udid)。如果先连 A 再选 B,
    隧道状态仍是 connected,于是 B 的 provider 拿到的是 A 的 RSD 对象 ——
    DVT 流量全发到 A,而界面显示的是 B,没有任何地方会报错。

    修复:无条件调用 tunnel.ensure(device.udid),由它内部比对 UDID 并决定是否重建。

    2. tunnel.stop() 竞态:释放期间 ready 仍为 True 但 rsd_object() 已是 None
    core/tunnel.py: stop()

    原逻辑先清 _rsd,最后才清 host/port/state。中间那段时间(最长 25 秒)并发的
    provider_for 会走到 address() 回退分支,拿用户态隧道地址去做内核 TCP 连接,
    必然报 OSError [WinError 1231] 网络位置不可达。

    修复:在锁内一次性把 state / host / port / rsd 全部清掉再释放资源。
    另外新增 invalidate(reason),用于把隧道标记为失效但不释放资源。

    3. 隧道静默断开后仍然报告 connected,持续注入已死的 RSD
    core/tunnel.py: ready

    pymobiledevice3 的 UserspaceRsdTunnel 在 USB 拔出/传输中断时会自己 aclose()
    并把内部 rsd 置空,但 TunnelManager 还留着旧引用。表现为界面显示「已连接」,
    但怎么操作都不生效,只能手动断开重连。

    修复:ready 增加健康检查 —— self._userspace_tunnel.rsd is None 时判定为不可用,
    下一次 ensure() 会重建隧道。新增 is_alive() 供上层判断。

    4. AMDS 已装好、只是 27015 探针失败时,会去下 193MB 的 iTunes
    core/apple_driver.py: ensure()

    服务装着且在运行、但 usbmuxd 协议往返失败时,原逻辑直接进入安装阶梯:
    先跑 38MB 的 AMDS MSI(返回 1638「已安装」被当成成功),复检仍不通,
    于是继续下载 193MB 的完整 iTunes 包,再试 winget。整个过程纯属浪费。

    修复:服务存在时先重启服务(最多两次,带退避),成功即返回;
    仍不通则给出明确的排查建议(防火墙/安全软件拦截 127.0.0.1:27015、重插数据线),
    而不是盲目重装。新增 restart_service()。

    中等

    5. clear_location() 之后保活任务被永久停掉
    core/location_provider.py

    clear_location() 里调了 _stop_keepalive(),之后再次 set_location 也不会重启
    保活任务 —— 等于「设了点但暂停/静止」这个最需要保活的场景彻底失去保护,
    而保活正是 Windows 用户态隧道防「静默断线导致手机恢复真实定位」的关键。

    修复:clear_location 不再停保活(循环本来就会在 _last_location is None 时空转);
    set_location 幂等地重新拉起任务兜底。

    6. DDI 暂存选错目录 → 可能拷进残缺素材,挂载必失败
    core/server.py: _stage_personalized_ddi()

    原逻辑「找到第一个有 Image.dmg 的目录就用」,但只有三件齐全(Image.dmg /
    BuildManifest.plist / Image.dmg.trustcache)才能挂载。如果打包内置目录缺 trustcache,
    会拷一份残缺素材进缓存,然后挂载失败。

    修复:只挑选三件齐全的目录(与 apple_driver.ddi_status() 判定一致),
    拷贝后再校验一次落地完整性,缺任何一件就明确报错并返回 False。

    7. 「进入程序」被可选项拖住 / 「管理员权限」在不需要时也阻塞
    core/setup_window.py

    • 底部按钮原本只在全部检查结束后才刷新,可选项(网络探测 3×6s、PnP 最长 45s)
      没跑完时,即使必需项全绿按钮也是灰的。修复:每完成一项就刷新底部。
    • 「管理员权限」原本恒为必需。但 userspace 隧道本身不需要管理员,
      只有「需要安装 Apple 驱动」时才真的需要。源码模式 / 非管理员启动会被锁死。
      修复:_needs_item() —— 驱动已就绪时,权限项不再阻塞「进入程序」。

    8. 连接失败时 provider 泄漏 + 启动后重复探测驱动
    core/server.py / main.py

    • provider_for 里会话建立失败后,新建的 provider 未关闭(DVT/lockdown 泄漏)。
      修复:失败时先关闭再抛出。
    • 环境窗口刚做过完整驱动检查,main() 启动后又跑一遍深度探测
      (sc + 27015 + Get-PnpDevice + 注册表)并可能再次进入安装阶梯。
      修复:setup_result is True 时跳过重复探测。

    9. keep-alive 连接上「不读 body 的接口」会污染下一个请求

    core/server.py

    /api/devices/connect、/api/devices/disconnect、/api/tunnel
    这些 handler 从不读请求体。在 HTTP/1.1 keep-alive 连接上,没被读走的 {}
    留在 socket 缓冲区,被 BaseHTTPRequestHandler 当成下一个请求的请求行:

    501 Unsupported method ('{}POST')
    

    间歇性出现(取决于客户端是否复用连接),最终用户看到的是"偶发操作失败"。
    这是我在打包版冒烟测试里实际撞到的。

    修复:do_POST 进入路由前先把请求体读完并缓存;handle_one_request 每请求重置缓存
    (否则第二个请求会读到上一个请求的 body —— 这是修复第一版引入的新隐患,已一并处理)。
    新增回归脚本 tools/keepalive_probe.py(同连接连发 3 个 POST 验证不串)。

    轻微

    9. 窗口销毁后 Tk 报 invalid command name "..._pump"
    core/setup_window.py

    _pump 的 after 回调在窗口销毁后仍在队列里。命令行模式下会刷错误。
    修复:记录 after id,销毁前取消;并在 _pump 开头检查 winfo_exists()。

    10. 日志文件无限增长
    core/server.py

    app.log 只追加不滚动,长期使用会越来越大。
    修复:启动时若超过 5MB 则滚动为 app.log.1(保留一份旧日志)。

    11. 死代码清理

    • setup_window._update_footer 里的 self.state.get("__x__")(无意义表达式)
    • apple_driver.ensure 里自相矛盾的 if result.get("ok"): if name=="msi" and not result.get("ok")
    • apple_driver.ensure 里 service_state() 的空调用
    • main.py 的 driver_state 字典(写入但从未读取)
    • server._stage_personalized_ddi 尾部整段不可达代码(残留的 _cmd_mount_status 函数体)

    二、功能改进

    改进 说明
    环境窗口显示版本号 标题旁显示 v1.1.1 · Windows,便于确认版本
    环境窗口「打开日志目录」 一键打开 %LOCALAPPDATA%\iOSLocationTrack\logs,装驱动失败时可自行取证
    网络检查更准确 分成「Apple TSS 签名」(必须)和「镜像下载源」(可选)两条,不再把 GitHub 被墙误报成"连不上 Apple"
    「重启提权」按钮 权限项右侧按钮,点击后通过 UAC 拉起管理员实例,本实例自动退出
    --check-driver 更完整 增加开发者镜像状态与目录、日志目录信息
    驱动安装失败提示 明确提示「需要重启 Windows 后生效」而不是笼统的失败

    三、验收

    tests/selftest.py                83/83   PASS
    tests/drift_sim.py               40/40   PASS
    tests/offline_tiles.py           13/13   PASS
    tests/setup_window_selftest.py     7/7   PASS(新增:环境窗口检测→确认→放行全流程)
    tests/win_e2e.py                   7/7   PASS(真机 iPhone 11 / iOS 26.6.1)
    tests/win_app_e2e.py               9/9   PASS(真机,走 App 真实装配路径)
    

    打包版 exe 实测:发现设备 → 0.3s 隧道 → DVT → 两次下发 → 恢复真实定位 → 干净退出。


    四、已知未修(留待后续)

    审查还提了几项,本轮未动(风险或成本较高,且不影响当前功能):

    项 说明
    保活取消的竞态 _stop_keepalive() 只 cancel() 不 await,理论上可能与 clear()/close() 抢同一个 DTX 通道;窗口极小
    probe() 失败路径泄漏 lockdown iOS<17 老路径才有,且失败即报错,影响有限
    provider_for 长时间持锁 连接期间最长持锁约 2 分钟,并发 disconnect/shutdown 会阻塞(无死锁)
    DDI 下载无 SHA 校验 镜像源可变,目前只按文件大小判断完整性
    console=False 隐藏 CLI 输出 打包版 --check-driver 的输出看不到,需要另开控制台版本
    Win32 调用缺 argtypes ctypes 未声明原型,当前 64 位下实测正常,但属未定义行为

    其中建议下一轮优先处理:隧道断线自动重连(目前仍需手动断开重连)、
    打包版 CLI 输出可见性。

    Downloads
  • v1.1.0 c60e4b5cd4

    admin released this 2026-10-29 07:51:20 +00:00 | 5 commits to main since this release

    v1.1.0 — 新增 Windows 支持 🎉

    同一个代码库,macOS 与 Windows 两个平台都能构建、都实测跑通真机。

    关于 macOS 包:本次没有重新构建 macOS 版本,上传的 DMG 与 v1.0.0 是同一份二进制
    (SHA256 完全一致),只是按新的命名规范加了 _mac 后缀。macOS 端功能没有任何变化,
    应用内显示的版本号仍是 v1.0.0。下次在 Mac 上执行 ./scripts/build_app.sh 时会产出
    真正的 1.1.0。


    下载哪个?

    平台 文件 说明
    Windows iOSLocationTrack-1.1.0_win-setup.exe 安装包(推荐),中文向导
    Windows iOSLocationTrack-1.1.0_win-portable.zip 绿色免安装版,解压即用
    macOS iOSLocationTrack-1.1.0_mac.dmg 打开 DMG,把 App 拖进 Applications(二进制同 v1.0.0)

    Windows 版

    1. 建隧道不需要管理员权限

    iOS 17+ 的 RSD 隧道在 Windows 上换成了 UserspaceRsdTunnel —— 纯 Python 的 PyTCP
    用户态协议栈:

    • ❌ 不需要内核虚拟网卡,❌ 不需要 Wintun 驱动,❌ 不需要管理员权限
    • ✅ 实测建立耗时 约 0.3 秒
    • ⚠️ 代价是设备地址只在本进程内可达,所以不能沿用 macOS 那套
      「隧道助手子进程 + 解析 HOST PORT」的架构,必须把隧道返回的 RSD 对象直接注入 DVT 层

    对比过 5 个同类实现(GeoPort、locwarp、fake-location-cli、iFakeLocation 及其分支、go-ios),
    它们的 Windows 方案都需要管理员权限 + 内核隧道或后台 tunneld 守护进程。

    2. 自动安装 Apple Mobile Device Support

    Windows 上 usbmuxd 由 Apple 的驱动提供,没有它一台设备都发现不了。程序会按顺序自动降级:

    启动已有服务 → 独立 AMDS MSI(38MB) → 完整 iTunes 包(193MB) → winget

    3. 「环境准备」窗口

    每次启动弹出自检窗口,逐项列出依赖:已就绪的显示绿色 ✓,缺失的显示红色 ✗ 且右侧
    有「安装 / 下载」按钮,必需项全部就绪后「进入程序」才可点击。

    检查项:Python 运行时、pymobiledevice3、Apple Mobile Device Support、RSD 隧道依赖、
    开发者镜像、管理员权限、iPhone 连接(可选)、网络连通(可选)。

    4. 启动即请求管理员权限

    exe 清单写入 requireAdministrator,免去用户手动右键提权(只用于装驱动;
    隧道本身不需要)。

    5. 保活机制

    Windows 用户态隧道会静默断开,设备随后偷偷恢复真实定位而界面看起来一切正常。
    因此设了点但停止播放时,每 15 秒重发一次。


    实测环境与结果

    Windows 11 x64 · Python 3.12.14 · pymobiledevice3 11.31.0 · iPhone 11 / iOS 26.6.1

    tests/selftest.py        83/83     协议、几何、播放引擎、配置、瓦片、端到端
    tests/drift_sim.py       40/40     真实感模型
    tests/offline_tiles.py   13/13     瓦片离线缓存
    tests/win_e2e.py          7/7      真机:隧道→镜像→DVT→下发→恢复
    tests/win_app_e2e.py      9/9      真机:走 App 真实装配路径
    

    打包版 exe 实测:发现设备 → 0.3s 隧道 → DVT 会话 → 两次下发定位 → 恢复真实定位 → 干净退出。


    已知限制

    • iOS 16 及更早不支持(经典开发者镜像需 Apple 按构建号签发,第三方镜像会被设备拒签)
    • 同一时间只能有一个工具占用 RSD 连接,用之前请关掉爱思助手 / i4Tools / Xcode
    • 一个进程只能有一条 userspace 隧道,请不要双开
    • exe 与安装包没有代码签名,会有 SmartScreen 提示 → 点「更多信息 → 仍要运行」
    • 挂载开发者镜像需要联网(Apple TSS 在线签名)

    文档


    本 Release 暂未附带二进制文件(仓库当前提供的是 v1.1.1 的安装包与免安装包);如需 v1.1.0 可从源码自行构建。

    Downloads