调用stopUpdatingLocation()后后台临时定位授权重置问题咨询
临时定位权限(Allow Once)返回应用后变回
.notDetermined的问题解答 现象是否为预期行为?
是,这属于苹果临时定位权限的预期行为。
苹果对「Allow Once」权限的定义是:仅在当前应用会话内有效,当用户将应用切换到后台且定位任务结束后,系统会自动将授权状态重置为.notDetermined。这里的「ceases to use the app」不仅指应用被终止,还包括用户结束当前的定位使用场景——即使应用只是进入后台,只要定位任务停止,临时权限就会失效,授权状态被重置。
解决办法
- 引导用户授予持久化权限:
在请求权限前,通过弹窗或引导页向用户说明应用需要持续定位的场景,请求用户选择「Allow While Using App」(使用期间允许)或「Allow Always」(始终允许),这两种权限不会在后台结束定位后重置状态。可在checkRequestPermission方法中,针对临时权限过期的情况,提示用户选择持久化权限。 - 优化权限检查逻辑:
回到前台检查权限时,若发现状态为.notDetermined,可先判断用户是否有过临时授权记录(比如通过本地存储标记),再决定是否直接请求权限,减少对用户的打扰。
修正后的相关代码
class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let scene = (scene as? UIWindowScene) else { return } window = UIWindow(windowScene: scene) window?.makeKeyAndVisible() window?.rootViewController = MainViewController() } func sceneDidBecomeActive(_ scene: UIScene) { AppDelegate.loc.checkRequestPermission() } } class MainViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .red let button = ReusableUIElements.createButton(title: "Start") view.addSubview(button) button.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside) ReusableUIElements.buttonConstraints(button: button, safeArea: view.safeAreaLayoutGuide, bottomAnchorConstant: -40) } @objc func buttonPressed() { // 手动切后台时触发定位 AppDelegate.loc.retrieveLocation() } } class Location: NSObject, CLLocationManagerDelegate { var locationManager: CLLocationManager! // 标记用户是否使用过临时权限 private var hadTemporaryAuth = false override init() { super.init() locationManager = CLLocationManager() locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyBest locationManager.allowsBackgroundLocationUpdates = true locationManager.showsBackgroundLocationIndicator = true } func checkRequestPermission() { let status = locationManager.authorizationStatus if status == .notDetermined { if hadTemporaryAuth { // 提示用户选择持久化权限 let alert = UIAlertController(title: "定位权限", message: "为了持续提供服务,请选择「使用期间允许」或「始终允许」", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "知道了", style: .default) { _ in self.locationManager.requestWhenInUseAuthorization() }) UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: true) } else { locationManager.requestWhenInUseAuthorization() } } else if status == .authorizedWhenInUse || status == .authorizedAlways { print("已拥有持久化定位权限") } else { print("定位权限被拒绝,请前往设置开启") } } func retrieveLocation() { locationManager.startUpdatingLocation() DispatchQueue.main.asyncAfter(deadline: .now() + 10) { print("10秒后停止定位") self.locationManager.stopUpdatingLocation() } } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { guard let location = locations.last else { return } let geocoder = CLGeocoder() geocoder.reverseGeocodeLocation(location) { placemarks, error in if let error = error { print("逆地理编码失败:\(error.localizedDescription)") return } guard let placemark = placemarks?.first else { return } print(placemark) } } func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { print("定位失败:\(error.localizedDescription)") } func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { print("授权状态变更") switch locationManager.authorizationStatus { case .denied, .restricted: print("权限被拒绝/受限") case .authorizedWhenInUse, .authorizedAlways: print("已授权") case .authorizedOnce: // 标记用户使用过临时权限 hadTemporaryAuth = true print("临时授权") default: print("未确定") } } }
内容的提问来源于stack exchange,提问作者Shiv Nik
相关产品推荐
相关产品推荐

