You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用requestAuthorizationWhenInUse()后LocationManager仍卡在.notDetermined状态

问题描述

我正在尝试用Swift、SwiftUI和CoreLocation开发第一个应用,以下是我的代码:

LocationManager 可观察类

import Foundation
import CoreLocation
import SwiftUI

@Observable class LocationManager: NSObject, CLLocationManagerDelegate {
    let manager: CLLocationManager
    
    var lastLocation: CLLocation? {
        manager.location
    }
    
    override init() {
        manager = CLLocationManager()
        super.init()
        
        manager.delegate = self
        manager.desiredAccuracy = kCLLocationAccuracyBest
    }
}

extension LocationManager {
    
    private func redirectToSettings() {
        if let url = URL(string: UIApplication.openSettingsURLString) {
            UIApplication.shared.open(url)
        }
    }
    
    func requestWhenInUseAuthorization() {
        return manager.requestWhenInUseAuthorization()
    }
    
    private func handleAuthorizationStatusChange(_ status: CLAuthorizationStatus) {
        switch status {
        case .notDetermined:
            print("not determined")
            requestWhenInUseAuthorization()
        case .authorizedWhenInUse:
            print("yes")
            manager.requestAlwaysAuthorization()
            return manager.startUpdatingLocation()
        case .authorizedAlways:
            return manager.startUpdatingLocation()
        case .denied, .restricted:
            return redirectToSettings()
        @unknown default:
            print("Unknown authorization status")
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print("\(error)")
    }
    
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        handleAuthorizationStatusChange(status)
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        print(locations)
    }
}

FirstView 视图代码

import SwiftUI

struct FirstView: View {
    @Environment(LocationManager.self) var locationManager
    
    var body: some View {
        if let clLocation = locationManager.lastLocation {
            Text(clLocation.description)
        } else {
            Text("No location")
        }
    }
}

#Preview {
    FirstView()
}

ContentView 代码

struct ContentView: View {
    var body: some View {
        TabView {
            FirstView()
                .tabItem {
                    Label("Explore", systemImage: "globe")
                }
            SecondView()
                .tabItem {
                    Label("Tortoise", systemImage: "tortoise")
                }
            ThirdView()
                .tabItem {
                    Label("Tortoise", systemImage: "tortoise")
                }
        }
    }
}

#Preview {
    ContentView()
}

遇到的问题

授权回调触发时,状态是.notDetermined,于是调用requestWhenInUseAuthorization()请求授权,但用户没有收到授权弹窗,状态也没变化,回调不会再次触发。设备设置里的定位服务已经开启,请问可能是什么原因?


可能的原因及解决方法
  • Info.plist 缺少权限描述
    CoreLocation 请求授权时,必须在Info.plist中添加对应的权限说明,否则系统不会弹出授权弹窗。
    若请求"When In Use"授权,需添加NSLocationWhenInUseUsageDescription(字符串类型),填写向用户说明权限用途的文案,比如"需要获取你的位置来提供相关服务"。
    如果后续要请求"Always"授权,还需添加NSLocationAlwaysAndWhenInUseUsageDescription(iOS 11及以上)。

  • 未主动触发授权请求
    当前LocationManager初始化后仅设置了代理,未主动发起授权请求。虽然didChangeAuthorization回调首次触发时会调用授权方法,但如果系统因缺少权限描述等原因不响应,就会卡住。可以在视图加载时主动触发,比如给FirstView添加onAppear:

    struct FirstView: View {
        @Environment(LocationManager.self) var locationManager
        
        var body: some View {
            // ... 原有视图代码
            .onAppear {
                locationManager.requestWhenInUseAuthorization()
            }
        }
    }
    

    同时要确保在App入口注入LocationManager环境对象:

    @main
    struct YourApp: App {
        var body: some Scene {
            WindowGroup {
                ContentView()
                    .environment(LocationManager())
            }
        }
    }
    
  • 授权逻辑的循环误区
    当状态为.notDetermined时调用requestWhenInUseAuthorization(),这个操作本身不会再次触发didChangeAuthorization回调——只有用户在授权弹窗中做出选择后,回调才会再次触发。如果弹窗因为权限描述缺失不出现,状态就会一直停留在.notDetermined,导致流程卡住。所以优先解决权限描述问题是关键。

  • 预览环境的限制
    FirstView的预览中没有注入LocationManager环境对象,预览时无法正常测试授权流程,但真机或模拟器运行时的问题与预览无关,只需确保正式运行时环境对象已正确注入即可。


内容的提问来源于stack exchange,提问作者explosivemango

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 18:41:11