Swift实现iOS应用被终止/杀死时获取用户位置的方法
iOS应用被终止后追踪位置的解决方案
你的当前代码仅能处理前台/后台的位置更新,应用被完全终止后,常规的startUpdatingLocation无法触发系统唤醒应用。要实现类似Apple Maps、Google Maps的终止后追踪,必须利用iOS提供的重大位置变化服务或地理围栏监测,同时满足权限和配置要求。
核心要求
- 权限必须为Always Allow:用户必须授予"始终允许"位置权限,否则应用被终止后系统不会唤醒它。
- 配置Info.plist权限描述:添加以下两个键,描述要明确告知用户需求:
NSLocationAlwaysAndWhenInUseUsageDescriptionNSLocationWhenInUseUsageDescription
- 开启后台位置更新模式:在Xcode项目的"Signing & Capabilities"中,添加"Background Modes",勾选"Location updates"。
具体实现方案
方案一:重大位置变化服务(推荐,低功耗)
该服务由系统管理,当用户位置发生显著变化(通常几百米,由系统根据移动速度等判断)时,即使应用被终止,系统也会唤醒应用并传递位置更新。
代码修改步骤
修改位置启动逻辑:
将原有的startMonitoring()方法替换为同时支持常规更新和重大变化监测:func startMonitoring() { locManager.allowsBackgroundLocationUpdates = true locManager.pausesLocationUpdatesAutomatically = false // 前台用高精度更新,后台/终止用重大变化服务 if UIApplication.shared.applicationState == .active { locManager.startUpdatingLocation() } else { locManager.startMonitoringSignificantLocationChanges() } }处理应用被唤醒的情况:
在AppDelegate中添加启动时的位置唤醒处理:import UIKit import CoreLocation @main class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate { var locManager: CLLocationManager! func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 检查是否因位置变化被唤醒 if launchOptions?[.location] != nil { locManager = CLLocationManager() locManager.delegate = self locManager.allowsBackgroundLocationUpdates = true // 重新启动重大位置变化监测 locManager.startMonitoringSignificantLocationChanges() } return true } // 接收位置更新(应用被终止后唤醒时会调用) func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { guard let location = locations.last else { return } // 处理位置上传逻辑,复用原有postLocation方法 let viewController = UIApplication.shared.keyWindow?.rootViewController as? ViewController viewController?.postLocation(location: location) // 启动后台任务,确保有足够时间完成上传 var backgroundTask = UIBackgroundTaskIdentifier.invalid backgroundTask = UIApplication.shared.beginBackgroundTask(withName: "LocationUploadTask") { UIApplication.shared.endBackgroundTask(backgroundTask) backgroundTask = .invalid } DispatchQueue.global().async { viewController?.callApi() UIApplication.shared.endBackgroundTask(backgroundTask) backgroundTask = .invalid } } }适配应用状态切换:
在ViewController中监听应用状态切换,动态调整位置更新模式:override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) NotificationCenter.default.addObserver(self, selector: #selector(handleAppActive), name: UIApplication.didBecomeActiveNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(handleAppBackground), name: UIApplication.didEnterBackgroundNotification, object: nil) } @objc func handleAppActive() { // 回到前台,切换到高精度位置更新 locManager.stopMonitoringSignificantLocationChanges() locManager.startUpdatingLocation() } @objc func handleAppBackground() { // 进入后台,切换到重大位置变化服务 locManager.stopUpdatingLocation() locManager.startMonitoringSignificantLocationChanges() }
方案二:地理围栏监测(适合特定区域追踪)
如果需要在用户进入/离开特定地理区域时唤醒应用,可以使用地理围栏:
// 添加地理围栏 func addGeofence(latitude: CLLocationDegrees, longitude: CLLocationDegrees, radius: CLLocationDistance) { let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) let region = CLCircularRegion(center: coordinate, radius: radius, identifier: "MyGeofence") region.notifyOnEntry = true region.notifyOnExit = true locManager.startMonitoring(for: region) } // 监听区域事件(应用被终止后唤醒时会调用) func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) { guard let location = manager.location else { return } postLocation(location: location) } func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) { guard let location = manager.location else { return } postLocation(location: location) }
关键注意事项
- 禁止使用Timer后台定时:应用被终止后Timer会完全失效,且Apple不允许此类后台定时任务,仅能通过系统提供的位置服务唤醒应用。
- 后台任务时长限制:应用被唤醒后,后台任务最多有30秒左右的处理时间,需尽快完成位置上传等操作。
- 测试注意事项:必须用真机测试,且不能通过Xcode直接终止应用(Xcode终止的应用不会被系统唤醒),需手动从多任务界面划掉应用后测试。
内容的提问来源于stack exchange,提问作者Pankaj Dhameliya
相关产品推荐
相关产品推荐

