按 docs/WINDOWS_PORT.md 完成 Windows 移植,并修正该文档中若干与实测不符之处。
macOS 构建链完整保留,单一代码库双平台构建。
核心:iOS 17+ RSD 隧道在 Windows 上换了实现方式
- macOS 借 Apple remoted(--native,内核可路由),Windows 改走 UserspaceRsdTunnel
(纯 Python PyTCP 用户态协议栈)
- 实测:不需要管理员权限、不需要 Wintun 驱动(pytun_pmd3 自带 wintun.dll)、
建立耗时约 0.3 秒
- 关键坑:用户态隧道的设备地址**只在本进程可达**。拿 (host, port) 另建 RSD 会得到
OSError [WinError 1231] 网络位置不可达。必须把 aopen() 返回的 rsd 对象本身注入
DVT 层(RealLocationProvider 早有 rsd= 注入口),因此 Windows 不能沿用
「隧道助手子进程 + 解析 HOST PORT」那套架构
- 修正 WINDOWS_PORT.md 的错误:类名是 UserspaceRsdTunnel 不是 UserspaceTunnel;
remote start-tunnel 没有 --userspace;Wintun 不是必需项
新增
- core/platform.py 平台抽象层(数据目录/浏览器探测/进程管理/提权/信号)
- core/apple_driver.py Apple Mobile Device Support 检测与自动安装
(服务启动 → 独立 AMDS MSI → 完整 iTunes 包 → winget 逐级降级)
+ 开发者镜像下载
- core/setup_window.py 启动时的「环境准备」窗口:逐项列出依赖,缺失项右侧可点安装,
必需项全部就绪后「进入程序」才可点击
- scripts/run.ps1, build.ps1, installer/iosloc.iss, installer/version_info.txt
- tools/make_ico.py(由已有 PNG 图标集生成多尺寸 .ico)
- tools/probe_tunnel_win.py(隧道可行性诊断)
- tests/win_e2e.py(7 项)、tests/win_app_e2e.py(9 项)真机验收
- docs/README-WINDOWS.md
- .gitattributes(避免 Windows 写出 CRLF 的 .sh 把 macOS 构建搞坏)
修改
- core/tunnel.py Windows 走进程内 userspace 隧道;macOS 路径不变
- core/server.py TunnelManager 注入 runner;provider_for 注入 rsd 对象;
资源目录与数据目录分离;日志落盘
- core/location_provider.py 平台化错误提示;新增保活(隧道静默断开会让设备
偷偷恢复真实定位,停止播放时每 15s 重发)
- main.py 「环境准备」窗口、Apple 驱动后台检查、
--check-driver / --install-driver、跨平台浏览器与信号
- Location.spec 平台分支;Windows 用 .ico + uac_admin=True(启动即请求管理员)
+ version_info.txt;单一 spec 不分叉
- tests/drift_sim.py / offline_tiles.py 去掉硬编码 /tmp,改用 tempfile.gettempdir()
打包
- exe 清单写入 requireAdministrator(用户要求:启动时直接请求管理员权限)
- 绿色版 dist\iOSLocationTrack\iOSLocationTrack.exe
- 安装包 dist\installer\iOSLocationTrack-1.0.0-setup.exe(Inno Setup)
实测(Windows 11 x64 / Python 3.12.14 / pymobiledevice3 11.31.0 / iPhone 11 iOS 26.6.1)
- 隧道→镜像→DVT→下发定位→恢复真实定位 全链路跑通,连接 0.8s
- selftest 83/83、drift_sim 40/40、offline_tiles 13/13
- win_e2e 7/7、win_app_e2e 9/9
- 打包版 exe:发现设备 → 0.3s 隧道 → DVT → 两次下发 → 恢复真实定位 → 干净退出
14 KiB
Windows 版说明(iOS 虚拟定位轨迹工具)
本文档面向 Windows 用户与维护者。 macOS 侧说明见 README.md;移植决策与背景见 WINDOWS_PORT.md。
1. 三分钟上手
- 运行
iOSLocationTrack-1.0.0-setup.exe安装,或直接双击绿色版dist\iOSLocationTrack\iOSLocationTrack.exe。 - 程序会请求管理员权限(UAC 弹窗点「是」)—— 用于首次自动安装 Apple 驱动。
- 弹出**「环境准备」**窗口,逐项列出所需组件:
- 已就绪的项目显示绿色 ✓,右侧按钮变成「已就绪」(不可点)
- 缺失的项目显示红色 ✗,右侧是可点的「安装 / 下载」按钮
- 必需项全部就绪后,「进入程序」才会变亮
- 点「进入程序」→ 浏览器以无地址栏应用窗口打开界面。
- 用数据线连接 iPhone → 解锁 → 手机上点「信任」→ 界面点「连接设备」。
从源码运行:
.\scripts\run.ps1(会自动建 venv、装依赖、补镜像素材)。
2. 「环境准备」窗口检查哪些项
| 项目 | 必需 | 检查方式 | 缺失时的「安装」做什么 |
|---|---|---|---|
| Python 运行时 | ✅ | 版本号 | —(已随 exe 打包) |
| pymobiledevice3 | ✅ | 导入 + 版本 | —(已随 exe 打包) |
| Apple Mobile Device Support | ✅ | 服务状态 + 27015 协议往返 | 自动下载安装(约 40~200 MB) |
| RSD 隧道依赖 | ✅ | pytun_pmd3 / pmd_pytcp 等导入 |
—(已随 exe 打包) |
| 开发者镜像 | ✅ | resources/ddi/personalized/ 三个文件 |
下载个性化镜像(约 15 MB) |
| 管理员权限 | ✅ | IsUserAnAdmin |
右键「以管理员身份运行」 |
| iPhone 连接 | ➖ 可选 | usbmuxd ListDevices |
—(接上手机即可) |
| 网络连通 | ➖ 可选 | TCP 连 gs.apple.com:443 |
—(挂载镜像时 Apple 需在线签名) |
判定 usbmuxd「能用」的唯一权威信号是 127.0.0.1:27015 上的协议往返,不是端口能连上。
ReadBUID 不需要插设备,因此可以在没有手机的情况下单独验证服务是否正常。
想看文字版自检
# 绿色版
.\dist\iOSLocationTrack\iOSLocationTrack.exe --check-driver
# 源码
.venv\Scripts\python.exe main.py --check-driver
输出示例:
平台:Windows(管理员:是)
服务:RUNNING(Apple Mobile Device Service)
版本:Apple Mobile Device Support 20.0.0.35
usbmuxd(127.0.0.1:27015):可通信
设备:1 台
· 00008030-001551840A02402E(USB)
结论:Apple Mobile Device Service 正在运行,usbmuxd 可通信
3. 自动安装 Apple Mobile Device Support
「环境准备」窗口里点 Apple 那一行的「安装」,或在命令行跑:
main.py --install-driver # 源码
iOSLocationTrack.exe --install-driver # 绿色版
安装策略按顺序自动降级(core/apple_driver.py):
| 顺序 | 策略 | 说明 |
|---|---|---|
| 0 | 启动已有服务 | 服务已装但没运行时,sc start 一下就够(最常见、最便宜) |
| 1 | 独立 AMDS MSI | Apple CDN 上的 AppleMobileDeviceSupport64.msi(约 38 MB) |
| 2 | 完整 iTunes 包 | https://www.apple.com/itunes/download/win64(约 193 MB) |
| 3 | winget | Apple.AppleMobileDeviceSupport / Apple.iTunes |
成功退出码:0、3010、1641、1638(MSI 语义,3010/1641 表示需要重启)。
必须知道的几个坑(都已在真机取证)
- 服务名是带空格的
Apple Mobile Device Service。AppleMobileDeviceService只是 exe 文件名,sc query AppleMobileDeviceService会报 1060。 - Windows 上没有
\\.\pipe\usbmuxd,usbmuxd 只暴露为 TCP127.0.0.1:27015。 - 不要用
usbaapl64判断驱动是否存在。AMDS 的 MSI 里 0 个.inf/.sys/.cat, 它不提供 USB 驱动;现代机器上 iPhone 实际绑定appleusb.inf(服务名WINUSB/usbccgp)。用usbaapl64判断会在健康机器上误报「缺失」。 - AMDS 的 ProductCode 每个版本都变,稳定的标识是 UpgradeCode
{5CF0656E-F3B8-11DB-BA81-804E56D89593}(x86/x64 通用)。 - Apple 没有稳定的「latest」直链;
iTunes64Setup.exe的地址带构建号。因此 本项目对能固定 SHA256 的文件做校验,校验不过会明确报错而不是装上一个来路不明的包。 - Microsoft Store 版 iTunes 与经典版互斥:经典安装包的
LaunchCondition里写死了NOT ITUNES_STORE_APP_INSTALLED。另外 Store 版的守护进程不支持 Wi-Fi 发现设备。 pymobiledevice3 官方也推荐经典版。
4. 与 macOS 版的架构差异(重要)
移植时最容易踩的坑:两个平台的 RSD 隧道建立方式本质不同,
所以 core/tunnel.py 里 Windows 与 macOS 走的是两条完全不同的路径。
| macOS | Windows | |
|---|---|---|
| 隧道方式 | remote start-tunnel --native(借 Apple remoted) |
UserspaceRsdTunnel(纯 Python PyTCP 用户态协议栈) |
| 需要 root/管理员 | 不需要 | 不需要 |
| 需要第三方驱动 | 否 | 否(不需要 Wintun) |
| RSD 地址可达范围 | 内核可路由,任何进程都能连 | 仅本进程可达(用户态协议栈内) |
| 实现方式 | 子进程 + 解析 stdout 的 HOST PORT |
在本应用的事件循环里建立并持有 rsd 对象 |
| 实测耗时 | — | 约 0.3 秒 |
为什么 Windows 不能用「隧道助手子进程」那套
macOS 版把隧道跑在子进程里,打印 HOST PORT,主进程用普通 TCP 连上去。
Windows 上这样行不通:
- 用户态隧道的设备地址只存在于建立它的那个进程的协议栈里;
- pymobiledevice3 的做法是把一个 relay dialer 注入它返回的
RemoteServiceDiscoveryService对象(open_connection=dial_plane.dial); - 拿
(host, port)另建一个 RSD 会退回 stdlib dialer,直接打到操作系统网络栈上, 结果是OSError [WinError 1231] 网络位置不可达(本项目实测复现过)。
正确做法:把隧道返回的 rsd 对象本身注入给 DVT 层。
RealLocationProvider 早就预留了 rsd= 注入口(core/location_provider.py),
core/server.py:provider_for() 在 Windows 上走的就是这条路。
关于 Wintun
docs/WINDOWS_PORT.md 让先装 Wintun,实测不需要:
- userspace 隧道走纯 Python 的 PyTCP 协议栈,不创建内核网卡;
- 而且
pytun_pmd3这个依赖自带各架构的wintun.dll(pytun_pmd3/wintun/bin/amd64/wintun.dll),本来也不用另外下载。
实测环境
| 项 | 值 |
|---|---|
| 系统 | Windows 11 家庭版 中文版(10.0.26200,x64) |
| Python | 3.12.14 |
| pymobiledevice3 | 11.31.0 |
| 设备 | iPhone 11(iPhone12,1),iOS 26.6.1 |
| Apple Mobile Device Support | 20.0.0.35 |
| iTunes | 12.13.11.1(经典版) |
连接耗时实测 0.8 秒(隧道 0.3s + 镜像/DVT 会话)。
5. 数据与日志位置
| 内容 | 路径 |
|---|---|
| 配置 / 瓦片缓存 / 日志 | %LOCALAPPDATA%\iOSLocationTrack\ |
| 应用日志 | %LOCALAPPDATA%\iOSLocationTrack\logs\app.log |
| MSI 安装日志 | %LOCALAPPDATA%\iOSLocationTrack\logs\msi-*.log |
| 下载的安装包缓存 | %LOCALAPPDATA%\iOSLocationTrack\installers\ |
| 开发者镜像缓存 | %USERPROFILE%\.pymobiledevice3\Xcode_iOS_DDI_Personalized\ |
app.log 是 UTF-8、Tab 分隔:时间戳 \t 级别 \t 消息。
用记事本或 Get-Content -Encoding UTF8 打开(PowerShell 5.1 默认按 ANSI 读会乱码)。
6. 构建
# 一键:图标 → 镜像素材 → 测试 → PyInstaller → Inno Setup
.\scripts\build.ps1
# 只打 exe
.\scripts\build.ps1 -NoInstaller
# 跳过测试快速重建
.\scripts\build.ps1 -SkipTests -SkipIcon -SkipDdi
产物:
| 文件 | 说明 |
|---|---|
dist\iOSLocationTrack\iOSLocationTrack.exe |
绿色版 onedir,整个目录一起拷走 |
dist\installer\iOSLocationTrack-1.0.0-setup.exe |
安装包(Inno Setup 6) |
前置条件:
python -m venv .venv
.venv\Scripts\python.exe -m pip install -i https://mirrors.aliyun.com/pypi/simple/ pymobiledevice3 pillow pyinstaller
winget install -e --id JRSoftware.InnoSetup # 可选,只影响安装包
打包时踩过的坑(都已修好,改 spec 时注意别踩回去)
- 不要排除
distutils/setuptools/wheel/pip。 PyInstaller 与 setuptools 的 hook 会强制导入或别名它们,排除后构建直接失败:ValueError: Target module "distutils" already imported as ExcludedModule('distutils',) ValueError: Target module "wheel" already imported as ExcludedModule('wheel',) - 不要排除
tkinter——「环境准备」窗口靠它(见下)。 copy_metadata必须带上apple_compress等包,否则挂载镜像时报No package metadata was found for apple_compress。- 不要排除
questionary/prompt_toolkit/pygments, 它们是 pymobiledevice3 运行期导入的;排掉后真机功能会静默失效 (表现为设备发现退化成 libimobiledevice)。 --windowed时sys.stdout是None,打印前必须判空。.ps1必须带 UTF-8 BOM。Windows PowerShell 5.1 只有在文件开头看到 BOM 时才按 UTF-8 解析脚本,否则按系统 ANSI 代码页(中文机器上是 GBK)读 —— 结果是中文全部乱码, 并且脚本直接语法报错(The string is missing the terminator)。scripts\run.ps1/scripts\build.ps1都已存为 UTF-8 with BOM。 编辑这两个文件时务必保持 BOM,否则它们会突然无法运行。
启动时请求管理员权限
Location.spec 里 Windows 分支设了 uac_admin=True,PyInstaller 会把
requestedExecutionLevel level="requireAdministrator" 写进 exe 清单。
用 strings 或在 exe 里搜 requireAdministrator 可以验证。
注:userspace 隧道本身不需要管理员权限;提权只是为了首次运行能自动安装 Apple Mobile Device Support,免去用户手动右键提权。
7. 验收
# 无需设备(136 项)
.venv\Scripts\python.exe tests\selftest.py # 83 项:协议/几何/播放/配置/瓦片/端到端
.venv\Scripts\python.exe tests\drift_sim.py # 40 项:真实感模型
.venv\Scripts\python.exe tests\offline_tiles.py # 13 项:瓦片离线缓存
# 平台可行性(真机,7 项)
.venv\Scripts\python.exe tests\win_e2e.py --confirm
# 应用层(真机,9 项;走 App 的真实装配路径)
.venv\Scripts\python.exe tests\win_app_e2e.py --confirm
# 无设备跑界面
.venv\Scripts\python.exe main.py --mock
真机验收 6 步(对应 WINDOWS_PORT.md 第 7 节):
pymobiledevice3 usbmux list能看到设备 ✅- 挂载开发者镜像成功 ✅
- 「连接设备」→ 隧道建立 → DVT 会话就绪 ✅
- 播放轨迹 → 手机定位真的移动 ✅
- 「停止」→ 手机恢复真实定位 ✅
- 应用层 9/9、平台层 7/7 全绿 ✅
8. 已知限制与注意事项
| 限制 | 说明 |
|---|---|
| 一个进程只能有一条 userspace 隧道 | PyTCP 协议栈是进程内全局单例。所以别双开本程序。 |
| 同一时间只能有一个工具占 RSD 连接 | 爱思助手 / i4Tools / Xcode 会互相挤掉,用之前先关掉。 |
| iOS 16 及更早不支持 | 经典镜像需 Apple 按构建号签发,第三方镜像会被设备拒签。本项目面向 iOS 17+。 |
| DVT 只能改经纬度 | simulateLocationWithLatitude:longitude: 只有两个参数;海拔、精度、传感器数据由 iOS 合成,无法注入。 |
| 挂载镜像需要联网 | 个性化镜像由 Apple TSS 按设备在线签发。 |
| 隧道可能静默断开 | Windows 用户态协议栈会偶发断开,设备会自己恢复真实定位而界面看起来正常。已加保活:设了点但停止播放时,每 15 秒重发一次(core/location_provider.py:KEEPALIVE_INTERVAL)。 |
| iOS 26.4.x 的镜像挂载可能干扰 DVT | 有同类工具报告 26.4.1 上传镜像会中断隧道,导致后续 DVT 报 InvalidService。本机 iOS 26.6.1 实测正常。若遇到,先在别的工具里挂好镜像再连。 |
| 未签名 exe 会有 SmartScreen 提示 | 没有代码签名证书。点「更多信息 → 仍要运行」。 |
| Windows 10 1809 以下不支持 | 安装包 MinVersion=10.0。 |
9. 文件对照(Windows 相关改动)
| 文件 | 说明 |
|---|---|
core/platform.py |
新增。平台抽象层:数据目录、浏览器探测、进程管理、提权、信号 |
core/apple_driver.py |
新增。Apple Mobile Device Support 检测/安装 + 开发者镜像下载 |
core/setup_window.py |
新增。「环境准备」窗口(tkinter) |
core/tunnel.py |
重写。Windows 走进程内 userspace 隧道;macOS 保持子进程 native 隧道 |
core/server.py |
注入 runner 给 TunnelManager;provider_for() 注入 rsd 对象;日志落盘;资源目录与数据目录分离 |
core/location_provider.py |
平台化错误提示;新增保活(_keepalive_loop) |
main.py |
「环境准备」窗口、Apple 驱动后台检查、--check-driver / --install-driver、跨平台浏览器与信号 |
Location.spec |
平台分支;Windows 用 .ico + uac_admin=True + version_info.txt;单一 spec,不分叉 |
tools/make_ico.py |
新增。由已有 PNG 图标集生成多尺寸 .ico |
tools/probe_tunnel_win.py |
新增。隧道可行性诊断脚本 |
scripts/run.ps1 / build.ps1 |
新增。Windows 启动 / 构建 |
installer/iosloc.iss |
新增。Inno Setup 安装包脚本 |
installer/version_info.txt |
新增。exe 版本资源 |
installer/languages/ChineseSimplified.isl |
新增。Inno Setup 6.7 起不再自带中文,随仓库携带 |
tests/win_e2e.py / win_app_e2e.py |
新增。真机验收(平台层 / 应用层) |
macOS 侧的构建链(tools/make_dmg.py、scripts/run.sh、build_app.sh、
Location.spec 的 BUNDLE 分支)全部保留,同一份代码库两个平台都能构建。