iOS13 SwiftUI背景位置更新处理器实现技术问询
解决SwiftUI后台持续更新位置的问题(无需「始终允许」权限)
我很理解你的困扰——不少开发者都碰到过这个问题:用户通常不愿意把位置权限从「使用应用期间」切换到「始终允许」,但我们又需要在APP后台时持续获取位置更新。结合你给出的配置和代码,我来帮你调整出正确的实现方式:
一、先完善Info.plist的配置
你的plist已经加了UIBackgroundModes的location项,这很好,但还有两个细节要调整:
- 替换旧的
NSLocationUsageDescription为NSLocationWhenInUseUsageDescription(前者在iOS 11+已经被废弃,requestWhenInUseAuthorization需要这个描述) - 确保
NSLocationAlwaysAndWhenInUseUsageDescription保留,后续请求「始终允许」权限时会用到
调整后的相关配置片段:
<key>NSLocationWhenInUseUsageDescription</key> <string>Delivering location based Fuel Price Updates, Weather, News & Sports. As well as local offers.</string> <key>NSLocationAlwaysAndWhenInUseUsageDescription</key> <string>Delivering location based Fuel Price Updates, Weather, News & Sports. As well as local offers.</string> <key>UIBackgroundModes</key> <array> <string>location</string> <!-- 如果不需要audio后台模式可以移除 --> <string>audio</string> </array>
二、修改LocationManager的核心实现
你的现有代码缺少后台位置更新的关键配置,我来帮你调整:
修改后的完整LocationManager代码
import Foundation import CoreLocation import Combine import UIKit import SwiftUI class LocationManager: NSObject, CLLocationManagerDelegate, ObservableObject { private let manager: CLLocationManager static var LMlat = 0.0 static var LMlong = 0.0 @Published var lastKnownLocation: CLLocation? override init() { self.manager = CLLocationManager() super.init() // 提前设置delegate,避免延迟 self.manager.delegate = self // 开启后台位置更新权限 self.manager.allowsBackgroundLocationUpdates = true // 禁止系统自动暂停位置更新 self.manager.pausesLocationUpdatesAutomatically = false // 如果是导航类应用,可以设置activityType优化后台更新频率 self.manager.activityType = .automotiveNavigation } func startUpdating() { // 先请求「使用应用期间」权限 if manager.authorizationStatus == .notDetermined { manager.requestWhenInUseAuthorization() } manager.startUpdatingLocation() } // 权限状态变化处理 func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { switch status { case .denied, .restricted: print("位置权限被拒绝/受限") // 这里可以引导用户去设置开启权限 case .authorizedWhenInUse, .authorizedAlways: print("位置权限已授权") manager.startUpdatingLocation() default: break } } // 位置更新回调(后台也会触发) func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { guard let newLocation = locations.last else { return } // 过滤掉精度低的位置(可选,根据需求调整) guard newLocation.horizontalAccuracy < 100 else { return } lastKnownLocation = newLocation // 仅当位置变化超过阈值时才更新服务器(避免频繁请求) let locationChanged = abs(newLocation.coordinate.latitude - LocationManager.LMlat) > 0.0001 || abs(newLocation.coordinate.longitude - LocationManager.LMlong) > 0.0001 if locationChanged { LocationManager.LMlat = newLocation.coordinate.latitude LocationManager.LMlong = newLocation.coordinate.longitude updateServerLocation(latitude: LocationManager.LMlat, longitude: LocationManager.LMlong) print("位置已更新,同步到服务器") } } func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { print("位置更新失败:\(error.localizedDescription)") } // 同步位置到服务器 private func updateServerLocation(latitude:Double,longitude:Double) { let locationurl = URL(string: "https://EXAMPLE.com/lat=\(latitude)&long=\(longitude)")! URLSession.shared.dataTask(with: locationurl) { _, _, err in if let err = err { print("同步服务器失败:\(err.localizedDescription)") return } DispatchQueue.main.async { print("位置已成功同步到服务器") } }.resume() } }
关键修改点说明
- 初始化时配置后台更新:在
init里就设置allowsBackgroundLocationUpdates = true和pausesLocationUpdatesAutomatically = false,这是后台持续更新的核心开关 - 优化权限请求逻辑:只在权限未确定时请求「使用应用期间」权限,避免重复请求;权限状态变化后自动启动更新
- 过滤无效位置:添加了精度过滤,避免使用误差过大的位置数据
- 优化位置变化判断:用阈值判断位置是否真的变化,减少不必要的服务器请求
- 设置activityType:如果你的应用是导航类,设置
.automotiveNavigation可以让iOS更积极地在后台提供位置更新
三、ContentView中的正确调用
确保你用@StateObject持有LocationManager(SwiftUI 2.0+),避免对象被意外释放:
struct ContentView: View { @StateObject private var locationManager = LocationManager() var lat: String{ return "\(locationManager.lastKnownLocation?.coordinate.latitude ?? 0.0)" } var lon: String{ return "\(locationManager.lastKnownLocation?.coordinate.longitude ?? 0.0)" } var body: some View { Text("当前位置:\(lat), \(lon)") .onAppear { locationManager.startUpdating() } } }
重要注意事项
- 即使只有「使用应用期间」权限,开启
allowsBackgroundLocationUpdates后,APP在后台仍然可以获取位置更新,但iOS会根据应用类型限制更新频率(导航类应用会获得更频繁的更新) - 不要滥用后台位置更新,否则可能被App Store拒绝,确保你的使用场景符合Apple的后台模式规范
- 如果后续需要请求「始终允许」权限,建议在用户主动触发某个需要后台持续定位的功能时再发起请求,而不是盲目弹出权限弹窗
内容的提问来源于stack exchange,提问作者RussellHarrower
相关产品推荐
相关产品推荐

