Files
ios-location-track/README.md
T
jbjf6666 4a5d676c7b docs: 新增《画轨迹 · 折线绘制 · 开始虚拟轨迹》详细教程
TUTORIAL-DRAW-AND-PLAY.txt,中英双语纯文本,1305 行 / 64 KB。

内容按真实界面元素写(对照 web/index.html 与 web/js/app.js 的实际按钮 / 交互):
- A 开始之前:三件必须做完的事(连接设备 / 挂载镜像 / 手机在手边)
- B 界面总览:四块区域 + 三个最关键按钮
- C 地图操作:平移缩放全览、切换底图、快速定位到坐标
- D 三种造轨迹方式
    D1 折线绘制(点击加点、双击或 Esc 结束、至少 2 点)
    D2 途经点 + OSRM 路线规划(拖拽排序、双击改坐标、改完要重新加载)
    D3 导入 GPX
- E 编辑:撤销 / 删除 / 移动 / 排序
- F 出行模式(驾车/骑行/步行/飞行)与播放倍速(0.1x-50x)的区别
- G 真实感参数逐个讲解:漂移 / 速度浮动 / 节奏抖动 / 位移推算速度 / 粗差跳点
- H 开始播放:前置检查清单 + 逐步现象 + 失败提示对照
- I 播放中控制:暂停 / 继续 / 拖动跳转 / 停止 的区别
- J 结束与恢复真实定位(三种方式 + 恢复不了的例外)
- K 保存复用(localStorage 与 GPX 的区别)
- L 快捷键总表
- M 常见问题(含错误提示原文对照)
- N 参数速查表

编码:UTF-8 with BOM + CRLF(记事本友好),.gitattributes 锁定 eol=crlf。
README.md / README.en.md 加入口,Location.spec 随 Windows 包一起装到安装目录。
2026-10-16 12:49:34 +08:00

307 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# iOS 虚拟定位轨迹工具(macOS / Windows)
[**中文**](README.md) | [English](README.en.md)
在电脑上给 iPhone / iPad 做**虚拟定位**与**轨迹模拟**的桌面工具:在地图上绘制路线、添加途经点、按真实速度沿轨迹驱动手机定位。
支持 **iOS 17 ~ iOS 27.2**(RSD 隧道 + DVT `SimulateLocation`),应用内内置了全系共用的开发者镜像素材,**不需要安装 Python 环境**。
界面为本机网页应用,用 Chrome / Edge 的应用窗口打开(无地址栏,像原生 App),也可以直接用浏览器访问 `http://127.0.0.1:8787`。地图、轨迹、播放引擎、设备通信全部在本机完成,只有地图瓦片和(可选的)路线规划需要联网。
> **Windows 用户请看 [docs/README-WINDOWS.md](docs/README-WINDOWS.md)**。
> Windows 版:免管理员建立隧道(纯 Python 用户态协议栈,不需要 Wintun 驱动)、
> 启动时自动检测并安装 Apple Mobile Device Support、带「环境准备」自检窗口。
> 构建产物:`dist\iOSLocationTrack\iOSLocationTrack.exe` 与
> `dist\installer\iOSLocationTrack-1.1.0_win-setup.exe`。
>
> 📄 快速上手(中英双语纯文本,可直接用记事本打开):[USAGE.txt](USAGE.txt)
> 📄 详细教程:**画轨迹 · 折线绘制 · 开始虚拟轨迹**:[TUTORIAL-DRAW-AND-PLAY.txt](TUTORIAL-DRAW-AND-PLAY.txt)
---
## 1. 快速开始
### 方式一:直接下载安装包(推荐)
从 [Releases](https://github.com/jbjf6666/ios-location-track/releases) 下载对应平台的安装包:
| 平台 | 文件名 | 说明 |
| --- | --- | --- |
| **Windows** | `iOSLocationTrack-<版本>_win-setup.exe` | 安装包。也可用绿色版压缩包,解压即用 |
| **macOS** | `iOSLocationTrack-<版本>_mac.dmg` | 打开 DMG,把 App 拖进 `Applications` |
Windows 版首次启动会请求管理员权限并弹出「环境准备」窗口自动补齐依赖,
详见 [docs/README-WINDOWS.md](docs/README-WINDOWS.md)。
macOS 版:打开 DMG,把 `虚拟定位轨迹.app` 拖进 `Applications`;首次打开若提示
「来自身份不明的开发者」→ 右键 → 打开 → 再点「打开」。
**不需要安装 Python、不需要任何依赖**,Python 运行时与全部依赖都已打包在应用内(约 80 MB)。
数据(配置、瓦片缓存)写到 `~/Library/Application Support/iOSLocationTrack/`。
> 只支持 **Apple Silicon(M 系列)**。Intel Mac 可用下方源码方式,或在 Intel 机器上执行 `./scripts/build_app.sh`(脚本通用)。
### 方式二:源码运行
```bash
git clone https://github.com/jbjf6666/ios-location-track.git
cd ios-location-track
# 首次运行会自动创建虚拟环境并安装依赖(走国内镜像)
./scripts/run.sh
```
启动后会自动打开界面。命令行等价方式:
```bash
./.venv/bin/python main.py # 正常启动(自动打开界面)
./.venv/bin/python main.py --mock # 无设备模拟模式(演示/验收轨迹与播放)
./.venv/bin/python main.py --port 8899 --no-browser
./.venv/bin/python main.py --window browser # 用默认浏览器打开而不是应用窗口
```
### 三种运行形态
| 形态 | 路径 | 是否需要环境 | 适用场景 |
| --- | --- | --- | --- |
| **DMG 安装包** | Release 附件(45 MB) | **不需要** | 分发 / 换机器 |
| **独立版** | `dist/虚拟定位轨迹.app`(约 80 MB 展开) | **不需要**:Python、依赖、前端、图标、镜像素材全在包内 | 双击即用 |
| 源码版 | `./scripts/run.sh` | 需要 Python 3.11+(首次自动装依赖) | 改代码、调试 |
```bash
# 重新打包(一步完成:图标 → 打包 → ad-hoc 签名 → 制作 DMG → 验证)
./scripts/build_app.sh
```
DMG 里放了应用本体、`Applications` 快捷方式(拖进去即安装)和一份安装说明。
如需自定义 DMG 外观:改 `tools/make_dmg.py` 顶部的常量。
> 首次运行会请求「控制 Chrome/Edge」的权限(用于以应用窗口方式打开界面)。
---
## 2. 支持的系统
| 系统 | 支持 | 说明 |
| --- | --- | --- |
| **iOS 17 ~ 27.2** | ✅ | 走 RSD 隧道 + DVT。应用内置全系共用的个性化镜像素材 |
| iOS 16 及更早 | ❌ | 其开发者镜像必须由 Apple 按系统构建号签发,第三方镜像会被设备拒签(实测 `Failed to verify the disk image signature`,换 libimobiledevice 同样失败) |
**为什么一套镜像就够**:iOS 17 起 Apple 改用「个性化」开发者镜像 —— 一份基础镜像(`Image.dmg`)+ `BuildManifest.plist`,**全系统版本共用**;挂载时由 Apple TSS 服务器按当前设备在线签发,因此不需要逐版本素材。本工具把这套素材打包在内(约 16 MB),点「挂载开发者镜像」即可离线使用(仅签名步骤需要联网)。
---
## 3. 设备准备(关键)
| 要求 | 说明 |
| --- | --- |
| 数据线连接 | 建议用 USB;Wi-Fi 连接在传输大文件时容易断 |
| 解锁并「信任」 | 手机弹出「要信任此电脑吗」必须点**信任**并输入锁屏密码 |
| 开启开发者模式 | 设置 → 隐私与安全性 → **开发者模式** → 打开 → **重启手机** → 重启后确认开启 |
| 挂载开发者镜像 | 点界面上的「挂载开发者镜像」(应用已内置素材),或用 Xcode 连接一次自动完成 |
| 关闭同类工具 | 爱思助手 / i4Tools / Xcode 等会与本工具争抢同一条 RSD 连接,**同一时间只能开一个** |
### 挂载开发者镜像
界面上点 **「挂载开发者镜像」** 即可,过程实时输出到右侧运行日志。命令行等价方式:
```bash
# 查看是否已挂载(返回 [] 表示没挂)
./.venv/bin/python -m pymobiledevice3 mounter list
# 自动挂载
./.venv/bin/python -m pymobiledevice3 mounter auto-mount --udid <你的UDID>
```
也可以直接用 Xcode:连接设备 → Window → Devices and Simulators → 等待 "Preparing device for development" 完成。
> macOS 装有 Xcode 时,系统自带的 `CoreDeviceService` 通常会在设备接入后**自动挂载**
> (`/Library/Developer/DeveloperDiskImages/`),此时无需任何操作。
> 打包版(.app)内部用 pymobiledevice3 的 **Python API** 完成挂载,不依赖任何命令行工具。
### 关于 iOS 17+ 的隧道(RSD)
iOS 17 起,虚拟定位服务不再走 usbmux,必须先建立 **RSD 隧道**。本工具有三种方式:
1. **免 root(默认,推荐)**:自动执行 `pymobiledevice3 remote start-tunnel --native --script-mode`,借用 Apple 自带 `remoted` 的隧道。打包版通过 `tunnel-helper` 自调用实现,**不依赖外部 Python**。
2. **管理员模式**:界面上点「以管理员权限重建隧道」(会弹系统密码框),或直接 `sudo ./scripts/run.sh`。
3. **手动填 RSD**:界面「手动 RSD」按钮,填入 `HOST PORT`(例如从其它工具或 `tunneld` 拿到)。
> `remote tunneld`、`lockdown start-tunnel`、经典 `remote start-tunnel` 都**必须 root**,本工具不会静默提权。
---
## 4. 界面功能
### 顶部:设备区
- 设备名 / 型号 / iOS 版本 / 连接方式(USB/网络)
- **隧道**状态、**虚拟定位**状态、**开发者模式**状态
- 「刷新设备」「连接设备」「断开」
### 左侧:轨迹设置
- **出行模式**:驾车 / 骑行 / 步行 / 飞行(决定基准速度与是否走真实路网)
- **播放倍速**:0.1x ~ 50x(只影响轨迹推进速度,不影响下发频率)
- **循环播放**:到终点自动回到起点
- **真实感模拟**(可随时开关、播放中也能改):
- **定位漂移**:模拟 GPS 误差导致的缓慢游走,半径 0~50 米(默认 4 米)。
用多尺度平滑噪声实现——沿轨迹连续变化、有惯性,**不会出现随机跳点**。
- **速度浮动**:瞬时速度在设定值上下平滑波动,幅度 0~60%(默认 ±8%)。
- **发送节奏抖动**(默认开):真实手机 GPS 不是精确每秒一次,而是 0.85~1.15 秒抖动、
偶发丢一次采样(约 2%)。间隔完全均匀是最容易被数据侧识别的特征之一。
- **速度由位移推算**(默认开):上报速度 = 实际位移 ÷ 实际时间间隔,与 iOS 从坐标序列
推算 `CLLocation.speed` 的方式一致,因此**速度、位移、时间戳三者自洽**。
- **注入粗差跳点**(默认关):按概率插入多径/城市峡谷导致的坏点,
用来测你自己 App 的 `horizontalAccuracy` 过滤与跳点剔除逻辑是否生效。
- 所有开关与幅度都会持久化,下次启动沿用。
- **快速定位到坐标**:输入经纬度直接跳转,可收藏常用位置
- **路线概览**:总距离、预计耗时、路径点数、途经点数、路线引擎(OSRM 真实路网 / 直线)
- **途经点列表**:拖拽排序、双击改坐标、删除、定位到该点
- **本地保存的路线**:保存 / 载入 / 删除(浏览器本地存储)
- **底图**:高德矢量(GCJ-02,带中文标注)/ 高德卫星 / 全球卫星(Esri) / OpenStreetMap
- 操作:「加载 OSRM 路线」「清空」「导出 GPX」「导入 GPX」「恢复真实定位」
- 瓦片缓存:显示缓存目录与占用,「清理瓦片缓存」
### 地图工具条
- **选择**:拖动地图、拖拽途经点、点击编辑
- **添加途经点**:在地图上连续点击加点(最常用的绘制方式)
- **折线绘制**:连续点击画折线,双击或 Esc 结束
- **撤销上一步**、**删除选中点**、**全览**
### 底部:播放条
- 播放 / 暂停 / 继续 / 停止
- 进度条(可拖动跳转,即 seek)
- 已用时间、剩余时间、序号
- 实时速度、当前坐标、倍速
### 右侧:运行日志
实时显示设备连接、隧道建立、镜像挂载、每次定位下发的日志,便于排查问题。
---
## 5. 典型用法
**A. 沿真实道路跑一条轨迹**
1. 连接设备 → 「连接设备」(iOS 17+ 会自动建隧道,最长约 1 分钟)
2. 点「添加途经点」,在地图上点起点、中间点、终点(至少 2 个)
3. 点「加载 OSRM 路线」→ 生成真实路网折线(无网络时自动退化为直线)
4. 调「播放倍速」(例如 20x 可以在几秒内跑完 10 公里)
5. 点「播放」→ 手机定位会沿轨迹移动;地图上定位点与进度实时更新
6. 点「停止」→ 手机立刻恢复真实定位
**B. 单点定位(钉在某处不动)**
在「选择」工具下双击地图任意位置,或点「快速定位到坐标」输入经纬度。用完点「恢复真实定位」。
**C. 导入已有轨迹**
点「导入 GPX」选择 `.gpx` 文件 → 轨迹出现在地图上 → 播放。导出的 GPX 也能导入 Google Earth、Strava 等工具。
**D. 没有设备时预览效果**
```bash
./.venv/bin/python main.py --mock
```
界面、轨迹绘制、播放引擎、进度条全部可用,只是定位不会真正下发到手机(顶部会显示「当前为模拟模式」)。
---
## 6. 命令行工具与自检
```bash
# 列出设备 + 开发者模式 + DVT 可用性
./.venv/bin/python tools/probe_device.py
./.venv/bin/python tools/probe_device.py --probe # 实际连一次 DVT
# 单点虚拟定位(命令行版)
./.venv/bin/python tools/probe_location.py --lat 39.9088 --lon 116.3975
./.venv/bin/python tools/probe_location.py --clear # 恢复真实定位
# 离线自检:83 项单元 + 端到端(不需要真机)
./.venv/bin/python tests/selftest.py
# 真实感模拟(GPS 漂移 + 速度浮动 + 节奏抖动,40 项)
./.venv/bin/python tests/drift_sim.py
# 瓦片本地缓存(13 项) / 浏览器级离线可用(9 项)
./.venv/bin/python tests/offline_tiles.py
./.venv/bin/python tests/offline_browser.py
# 图形界面验收(20 项,自动起浏览器)
./.venv/bin/python tests/ui_acceptance.py
# 独立版打包产物验证:干净环境启动 + 全部接口(22 项)
./.venv/bin/python tools/verify_bundle.py
# 真机端到端:会真的改变手机定位,结束后自动恢复
./.venv/bin/python tests/real_device_e2e.py --confirm --duration 5 --speed 20
# 给界面截图(视觉验收)
./.venv/bin/python tools/screenshot.py http://127.0.0.1:8787/ /tmp/ui.png --wait 9
```
打包相关:
```bash
./.venv/bin/python tools/make_icon.py # 生成应用图标(程序化绘制)
./.venv/bin/python tools/fetch_ddi.py # 获取开发者镜像素材
./.venv/bin/python tools/make_dmg.py # 制作 DMG
```
---
## 7. 故障排查
| 现象 | 原因与处理 |
| --- | --- |
| 界面显示「本地服务未连接」 | 服务端没起来或端口被占。看终端是否有报错;换端口 `--port 8899` |
| 未检测到设备 | 数据线 + 解锁 + 点「信任」 |
| 提示「需要开发者模式」 | 设置 → 隐私与安全性 → 开发者模式 → 打开并重启手机 |
| 「挂载开发者镜像」失败,提示签名被拒 | 设备是 iOS 16 或更早(不支持);或网络不通导致 TSS 签名失败,检查网络后重试 |
| 连接设备报「隧道」相关错误 | ① 关闭爱思助手等同类工具(会抢 RSD 连接);② 点「以管理员权限重建隧道」;③ 确认开发者镜像已挂载 |
| 定位不生效(手机没动) | 确认「虚拟定位」显示"模拟中";iOS 17+ 必须隧道正常 |
| 地图一片空白 | 瓦片源被网络限制,换底图(高德卫星 / Esri);**已浏览过的区域断网也能显示**(瓦片落在 `~/.ios-location-tiles`,上限 1GB,LRU 淘汰) |
| 隧道建好后手机定位立刻恢复 | 有别的程序(爱思/i4Tools/Xcode)在抢同一条 RSD 连接,关掉它们 |
---
## 8. 技术说明(实现要点)
- **通信**:Python 标准库 `http.server` + 手写 WebSocket(RFC 6455),无第三方 Web 框架;设备侧用 `pymobiledevice3`。
- **虚拟定位**:DVT 服务 `com.apple.instruments.dtservicehub`(iOS 17+,走 RSD 隧道),调用 `LocationSimulation.set(lat, lon)` / `clear()`。
**连接必须长连接保持**——DVT 会话一断,模拟定位立即失效,这决定了播放引擎不能每发一个点就重连。
- **播放引擎**:按弧长积分推进;速度剖面按转弯角度生成(急弯自动减速)再做滑动平均,因此加减速自然。独立线程 + 单一在途请求,保证下发顺序严格不乱。
- **真实感模型**:位置漂移用**多尺度值噪声**(慢漂 120m + 中尺度 30m + 快抖 15m 相关长度,接近真实 GPS 误差的幂律谱),幅值标定到设定半径并做上限裁剪(1.8 倍);相邻上报点之间平滑过渡,不会出现随机跳点造成的毛刺。
- **坐标**:内部与后端**一律 WGS84**;高德瓦片是 GCJ-02,由前端在请求瓦片与落点时做转换,避免"地图上的点和实际定位差 500 米"。
- **瓦片**:服务端代理 + 磁盘缓存(默认 `~/.ios-location-tiles`,上限 1GB,LRU 淘汰)。会自动识别并丢弃服务商返回的"全透明空瓦片"。
- **路线**:优先 OSRM 真实路网(`router.project-osrm.org`),无网络时退化为直线并在地图上标注引擎类型。
- **独立打包**:PyInstaller onedir + ad-hoc 签名。隧道建立通过「自调用」实现(`<应用自身> tunnel-helper`),因此打包后不需要机器上有 Python。
- **接口契约**:见 [docs/PROTOCOL.md](docs/PROTOCOL.md)。
- **Windows 移植**:见 [docs/WINDOWS_PORT.md](docs/WINDOWS_PORT.md)(可移植性审计、隧道方案替换、
打包链路改造、验收基线)。核心逻辑层约 90% 可直接复用,只有隧道建立与分发链路需重写。
---
## 9. 已知限制
- **DVT 只能改经纬度**:`simulateLocationWithLatitude:longitude:` 仅接受两个参数。`horizontalAccuracy`、`verticalAccuracy`、`altitude`、`floor`、`sourceInformation.isSimulatedBySoftware` 以及加速度计/陀螺仪/计步器由 iOS 自行合成或来自硬件,**DVT 通道无法注入**。这是所有同类工具(含 Xcode 自带的模拟定位)的共同边界。
- **部分 App 不受影响**:使用独立定位通道、或在服务端做运动学交叉校验的 App 可能不会跟随模拟定位,或跟随了但数据被判定无效。
- **同一时间只能有一个工具占隧道**:iOS 17+ 设备只有一条 RSD 连接,爱思助手/Xcode 与本工具会互相挤掉。
- 首次挂载镜像的签名步骤需要能访问 Apple TSS 服务器。
- 地图瓦片来自公开服务,仅供个人测试使用,请遵守相应服务条款。
---
## 10. 合法使用
本工具用于**软件测试、开发调试、位置相关功能的回归验证**等正当用途,例如:
- 测试 App 在不同城市/国家的展示与逻辑
- 验证轨迹回放、电子围栏、打卡类功能的边界情况
- 演示与教学
请勿用于欺骗他人、伪造行程记录、规避考勤或任何违法违规用途。使用本工具产生的一切后果由使用者承担。
特别说明:本工具**不提供**针对第三方应用风控/反作弊的绕过能力。如果你需要测试依赖海拔、气压计、计步器等硬件数据的功能,唯一可靠的方式是在你自己 App 的 Debug 构建里加入定位注入入口、自行构造完整的 `CLLocation`。