iOS 虚拟定位工具:从 RSD 隧道到 DVT 注入
这个工具做的事情很直接:把 iPhone / iPad 的位置「挪」到地图上任意一点,或者让设备沿一条画好的轨迹按真实速度移动。支持 iOS 17 – iOS 27.2,桌面端是 macOS + Windows 双平台。
界面看起来像一个原生桌面应用,实际上是一个本地 Web 应用:Python 标准库起个 HTTP 服务,浏览器以 Chrome / Edge 的 app window 方式打开 127.0.0.1:8787,地图、路由、播放引擎、设备通信全部在本机完成。
1. iOS 17 之后,为什么必须先建隧道
iOS 16 及以前,位置模拟走 usbmux 就够了。从 iOS 17 开始,Apple 换成了 RSD(Remote Service Discovery)隧道:设备对外只暴露一条隧道,位置模拟的 DVT 会话必须运行在这条隧道之上。
项目里的做法是复用 Apple 自己的 remoted 隧道——调用 pymobiledevice3 remote start-tunnel --native --script-mode,拿到 HOST PORT 后再连 DVT。打包成独立 app 之后没有外部 Python,于是用了「自调用」:app 二进制自己再以 tunnel-helper 参数启动一次,由它负责建隧道。
隧道必须保持连接:一旦 DVT 会话断开,虚拟位置会立刻失效。这也是播放引擎不能用「每个点重连一次」这种实现的原因。
2. 真正的注入点:DVT 的 LocationSimulation
隧道建好后,连接 com.apple.instruments.dtservicehub 服务,调用其中的 LocationSimulation.set(lat, lon) 写入坐标、clear() 恢复真实位置。这正是 Xcode 自带定位模拟走的通道,所以不需要越狱,也不需要改设备。
代价是:DVT 只能设置经纬度两个参数。horizontalAccuracy、altitude、floor、气压计、计步器这些数据无法通过这条通道注入——它们是 iOS 自己合成或硬件直接产生的。这是所有同类工具的共同边界。
3. 轨迹播放引擎
播放引擎按弧长积分推进:把折线轨迹按累计距离参数化,每一帧根据当前速度前进一段距离,再反算出坐标。速度不是恒定的——根据转弯角度生成速度曲线(急弯减速、直道加速),再做平滑,所以加速减速看起来是连续的。
发送端由一个专门线程维护「只有一个请求在飞」:上一个点确认送达后才发下一个,保证顺序严格、不会因为异步回调乱序。播放倍率只影响进度推进速度,不影响实际发送频率。
4. 让轨迹「像真的」
真实 GPS 的误差不是随机跳变,而是有惯性的平滑漂移。工具里用多倍频 value noise 做漂移:120 m(慢)、30 m(中)、15 m(快)三种相关长度叠加,近似真实 GPS 误差的功率谱,归一化到配置半径并在 1.8 倍处截断,保证连续、不出现随机跳点。
| 参数 | 作用 |
|---|---|
| 位置漂移 | 模拟 GPS 误差,半径 0–50 m(默认 4 m) |
| 速度抖动 | 瞬时速度围绕设定值平滑波动(默认 ±8%) |
| 发送间隔抖动 | 0.85–1.15 s 随机,约 2% 概率丢点(真实 GPS 不会严格每秒一次) |
| 位移推导速度 | 上报速度 = 实际位移 ÷ 实际间隔,保证速度、位移、时间戳自洽 |
| 粗大误差注入 | 默认关闭,用于测试自己 App 的异常点过滤逻辑 |
5. 坐标系:WGS84 与 GCJ-02
内部所有坐标统一用 WGS84。但高德瓦片是 GCJ-02 坐标系,如果在渲染时只转换瓦片不转换标记,地图上的点和设备的实际位置会差大约 500 米。所以前端在请求瓦片和放置标记时都做同一套坐标转换,两边才会对齐。
6. 地图与瓦片缓存
瓦片由本地服务端代理请求,并落盘缓存(默认上限 1 GB,LRU 淘汰),已经看过的区域断网也能继续显示。部分地图服务在无数据时会返回「全透明空瓦片」,代码里会识别并丢弃,避免缓存被垃圾填满。路由优先走 OSRM 真实路网,离线时回退成直线并在地图上标注引擎类型。
7. Windows 移植:免管理员、不用 Wintun
这次 Windows 版(v1.1.1)的重点是把 macOS 那套隧道逻辑换成纯 Python 用户态实现:
- 不需要管理员权限,也不依赖 Wintun 之类的虚拟网卡驱动;
- 首次启动自动检测并安装 Apple Mobile Device Support,缺依赖时直接引导安装;
- 打开时先做一次环境自检(驱动、服务、库版本),有问题在窗口里直接说明;
- 用 PyInstaller onedir 打包 + ad-hoc 签名,隧道建立通过
<app> tunnel-helper自调用完成,目标机器不需要装 Python。
构建产物是 dist\iOSLocationTrack\iOSLocationTrack.exe 和安装包 iOSLocationTrack-1.1.1_win-setup.exe,另外还有免安装的 portable ZIP。
8. 已知边界
- DVT 只能注入经纬度,海拔 / 气压 / 计步等数据无法伪造;
- 一台 iOS 17+ 设备同一时刻只有一条 RSD 连接,爱思助手、Xcode 等工具会和它互相抢占;
- 部分 App 有独立定位通道或服务端轨迹校验,虚拟位置可能被忽略或识别。
这个工具只适合做自己 App 的定位功能测试、路线回归和演示,不要用来伪造考勤或欺骗他人。
仓库地址:git.jbjflab.top/admin/ios-location-track(Python / JavaScript,含 Windows 与 macOS 文档、教程和测试)。
This tool does something simple: move an iPhone / iPad's location anywhere on the map, or make the device follow a drawn route at realistic speeds. It supports iOS 17 – iOS 27.2, with desktop builds for both macOS and Windows.
What looks like a native desktop app is actually a local web app: Python's standard library runs an HTTP server, the browser opens 127.0.0.1:8787 in a Chrome / Edge app window, and the map, routing, playback engine and device communication all run locally.
1. Why iOS 17+ requires a tunnel first
Before iOS 16, usbmux was enough for location simulation. Starting with iOS 17, Apple switched to an RSD (Remote Service Discovery) tunnel: the device exposes a single tunnel, and the DVT session for location simulation must run over it.
The project reuses Apple's own remoted tunnel — calling pymobiledevice3 remote start-tunnel --native --script-mode, then connecting DVT with the returned HOST PORT. Since the packaged app has no external Python, it uses self-invocation: the app binary launches itself again with a tunnel-helper argument to establish the tunnel.
The tunnel must stay alive: once the DVT session drops, the virtual location stops working immediately. That is also why the playback engine cannot reconnect for every point.
2. The actual injection point: DVT's LocationSimulation
Once the tunnel is up, connect to com.apple.instruments.dtservicehub and call LocationSimulation.set(lat, lon) to write coordinates, and clear() to restore the real location. This is exactly the channel Xcode's own location simulation uses, so no jailbreak or device modification is needed.
The cost: DVT can only set two parameters — latitude and longitude. horizontalAccuracy, altitude, floor, barometer and pedometer data cannot be injected through this channel; they are synthesized by iOS or produced directly by hardware. This is a shared boundary of every tool in this category.
3. Route playback engine
The playback engine advances by arc-length integration: the polyline route is parameterized by cumulative distance, the engine moves forward by the current speed each frame, then inverts back to coordinates. Speed is not constant — a speed profile is generated from turn angles (slow down in sharp corners, accelerate on straights) and then smoothed, so acceleration looks continuous.
The sending side keeps exactly one request in flight on a dedicated thread: the next point is sent only after the previous one is acknowledged, guaranteeing strict ordering without async callback reordering. The playback multiplier only affects progress rate, not the actual send frequency.
4. Making the track “look real”
Real GPS error doesn't jump randomly; it drifts smoothly with inertia. The tool uses multi-octave value noise for drift: three correlation lengths (120 m slow, 30 m medium, 15 m fast) are stacked to approximate the power spectrum of real GPS error, normalized to the configured radius and clipped at 1.8x, keeping it continuous without random jumps.
| Parameter | What it does |
|---|---|
| Position drift | Simulates GPS error, radius 0–50 m (default 4 m) |
| Speed jitter | Instantaneous speed fluctuates smoothly around the target (default ±8%) |
| Send-interval jitter | 0.85–1.15 s random, ~2% chance of a dropped sample (real GPS is never exactly once per second) |
| Derive speed from displacement | Reported speed = actual displacement ÷ actual interval, keeping speed, displacement and timestamps self-consistent |
| Gross error injection | Off by default; used to test outlier filtering in your own app |
5. Coordinate systems: WGS84 and GCJ-02
All coordinates internally use WGS84. But AMap tiles are in GCJ-02; if you convert only the tiles and not the marker, the map point and the device's actual position will be about 500 metres apart. So the frontend applies the same conversion both when requesting tiles and when placing markers, keeping the two aligned.
6. Maps and tile caching
Tiles are proxied by the local server and cached to disk (default cap 1 GB, LRU eviction), so already-viewed areas still render offline. Some tile providers return fully transparent “empty tiles” when they have no data; the code detects and discards them so the cache doesn't fill with garbage. Routing prefers OSRM's real road network and falls back to a straight line offline, labelling the engine type on the map.
7. Windows port: no admin rights, no Wintun
The focus of this Windows release (v1.1.1) was replacing the macOS tunnel logic with a pure-Python userspace implementation:
- No administrator rights required, and no dependency on virtual network adapter drivers such as Wintun;
- On first launch it detects and installs Apple Mobile Device Support automatically, guiding the install when a dependency is missing;
- Runs an environment self-check at startup (driver, service, library versions) and explains problems directly in the window;
- Packaged with PyInstaller onedir plus an ad-hoc signature; the tunnel is established via the
<app> tunnel-helperself-invocation, so the target machine doesn't need Python installed.
Build outputs are dist\iOSLocationTrack\iOSLocationTrack.exe and the installer iOSLocationTrack-1.1.1_win-setup.exe, plus an optional portable ZIP.
8. Known boundaries
- DVT can only inject latitude / longitude; altitude, barometer and pedometer data cannot be faked;
- An iOS 17+ device has only one RSD connection at a time; tools like i4Tools and Xcode will compete with it;
- Some apps use their own location channel or server-side trajectory validation, so the virtual location may be ignored or detected.
This tool is intended only for testing location features of your own app, route regression and demos. Do not use it to fake attendance or deceive others.
Repository: git.jbjflab.top/admin/ios-location-track (Python / JavaScript, with Windows and macOS docs, tutorials and tests).