记一次 CoreLocation 后台定位的踩坑:三档精度切换与格子地图的实现
起因:一条骑了大半年的通勤路
去年冬天我每天骑车上班,同一条路骑了大半年,某天突然想知道自己在这座城市到底覆盖了多少面积。打开某运动 App 看轨迹,密密麻麻的线叠在一起根本看不出覆盖率。试了几个热力图工具,要么强制登录同步云端,要么后台耗电太狠直接被系统杀掉。
我想要的东西其实很简单:把城市切成像素格子,走过就点亮,重复走的路会变色升级。一个纯本地的、单机的地图养成玩法。找了一圈没有满意的方案,索性自己动手写了一个,最终做成了「像素征途」这个 App。
这篇文章主要分享实现过程中 CoreLocation 后台定位的技术选型,以及格子数据结构的设计思路。
CoreLocation 三档精度:省电与轨迹质量的平衡
做后台持续定位的人都知道这个老问题——精度高了掉电快,精度低了轨迹飘得没法看。我最终的方案是做三档切换,让用户根据场景自己选:
enum TrackingMode: Int {
case powerSave = 0 // kCLLocationAccuracyHundredMeters, 100m格子
case balanced = 1 // kCLLocationAccuracyNearestTenMeters
case continuous = 2 // kCLLocationAccuracyBest, allowsBackgroundLocationUpdates
var desiredAccuracy: CLLocationAccuracy {
switch self {
case .powerSave: return kCLLocationAccuracyHundredMeters
case .balanced: return kCLLocationAccuracyNearestTenMeters
case .continuous: return kCLLocationAccuracyBest
}
}
}
省电模式只用 significantLocationChange 触发,适合日常通勤挂着不管;平衡模式十米级精度,citywalk 时打开;持续模式给骑行和出差用,高铁上也能不掉线。实测 iPhone 15 在平衡模式下一天额外耗电约 4%-6%,对日常使用来说可以接受。
踩过的坑:iOS 17 后台保活
这里重点说一下踩坑经历。最初我用 startMonitoringSignificantLocationChanges 配合 allowsBackgroundLocationUpdates,在 iOS 17 上偶发拿不到回调,表现为 App 进后台十几分钟后定位就断了。查了很久,后来改成 CLBackgroundActivitySession 配合 liveActivity 做保活,稳定性好了很多。代价是需要申请 Always 权限而不是 WhenInUse。
权限申请这块也折腾了一番。审核被拒过一次,后来在 Info.plist 的 NSLocationAlwaysAndWhenInUseUsageDescription 里写清楚「用于后台记录步行/骑行轨迹以点亮地图格子,所有数据仅存储在您的设备上」才过审。苹果对 Always 权限的文案要求确实越来越严格了,必须说明白为什么需要、数据去哪里。
格子升级的数据结构设计
地图被切成固定大小的像素格,根据缩放级别对应 GeoHash 前缀。每个格子存一个轻量结构:visitCount、lastVisitDate、level。visitCount 到阈值就升级,level 决定渲染颜色(灰色→蓝色→金色)。整个数据用 SwiftData 存本地,单个城市几万格子查询毫秒级,不需要远程数据库。
我觉得这个方案比 Fog of World 那种全量雾面擦除更省资源,也比 Strava 热力图更有「养成感」。因为你能看到一条路从暗淡变亮再变金的过程,而不是只看一张静态的密度图。配合 8×8 的领地征服系统、科技树和徽章收集,日常出行变成了一套完整的养成闭环。
设计上的一些取舍
这个 App 面向的是 25-40 岁有固定通勤或日常步行习惯的城市用户。不是跑步竞速工具,也不是社交打卡平台,更像一个单机游戏。没有排行榜,没有好友系统,没有 UGC 内容。数据全部存在本地,没有服务器,我看不到任何用户去过哪里。
自己用了两周,最爽的场景是出差。到一个新城市打开持续模式,从机场到酒店一路点亮,第二天看地图上多了一条新线路,有种「领地扩张」的满足感。通勤那条路已经升到金色了,每天看着会觉得这条路是「我的」。
如果你也对后台定位、GeoHash 网格化这些技术感兴趣,或者单纯想把日常出行变成一个安静的单机游戏,可以在 App Store 搜索「像素征途」试试看。

浙公网安备 33010602011771号