在我调用 requestWhenInUseAuthorization() 之前触发位置权限对话框

Posted

技术标签:

【中文标题】在我调用 requestWhenInUseAuthorization() 之前触发位置权限对话框【英文标题】:Location permission dialog fires before I call requestWhenInUseAuthorization() 【发布时间】:2020-09-09 08:55:40 【问题描述】:

当我的视图出现时:

struct TurnOnLocation: View 
    
    var body: some View 
        ZStack 
            Color.orange
                .edgesIgnoringSafeArea(.all)
            VStack 
                Spacer()
                Image(systemName: "globe")
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .foregroundColor(.white)
                Spacer()

                Button(action: 
                    let locationManager = LocationManager()
                    locationManager.locationManager.requestWhenInUseAuthorization()
                    locationManager.locationManager.startUpdatingLocation()
                ) 
                    Text("Turn on location")
                .foregroundColor(Color.black)
                .font(Font.system(size:22))
                .padding(20)
                .background(
                    Rectangle()
                        .fill(Color.white)
                        .border(Color.white, width:1)
                )
                .cornerRadius(50)
                .shadow(radius: 10)
                .padding(50)
            
        
    

它会在点击Button 之前询问用户位置。为什么是这样?我在下面添加了我的模型,以便在初始化时触发(应该是在单击按钮时)。

class LocationManager: NSObject, ObservableObject 
    @Published var locationStatus: CLAuthorizationStatus? = CLAuthorizationStatus.notDetermined
    @Published var locationPermissionStatus = PermissionStatus.unknown
    @Published var location: CLLocation?
    let locationManager = CLLocationManager()
    
    override init()
        super.init()
        self.locationManager.delegate = self
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
        self.locationManager.requestWhenInUseAuthorization()
        self.locationManager.startUpdatingLocation()
    
    
    enum PermissionStatus 
        case unknown
        case authorizedWhenInUse
        case authorizedAlways
        case restricted
        case denied
    
    
    func getLocation() -> CLLocationCoordinate2D? 
        return self.location?.coordinate
    
    

知道如何确保对话框仅在单击按钮后显示吗?

编辑:

我已经更新了代码:

Button(action: 
    let locationManager = LocationManager()
    locationManager.requestPermission()
)

型号

class LocationManager: NSObject, ObservableObject , CLLocationManagerDelegate 
    @Published var locationStatus: CLAuthorizationStatus? = CLAuthorizationStatus.notDetermined
    @Published var locationPermissionStatus = PermissionStatus.unknown
    @Published var location: CLLocation?
    let locationManager = CLLocationManager()
    
    override init()
        super.init()
        self.locationManager.delegate = self
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
    
    
    func requestPermission()
        self.locationManager.requestWhenInUseAuthorization()
    
    
    func locationManager(_ manager: CLLocationManager,
                         didChangeAuthorization status: CLAuthorizationStatus)    switch status 
          case .restricted, .denied:
             // Disable your app's location features
            print("restricted")
             break
                
          case .authorizedWhenInUse:
             // Enable your app's location features.
            print("authorizedWhenInUse")
            self.locationManager.startUpdatingLocation()
             break
                
          case .authorizedAlways:
             // Enable or prepare your app's location features that can run any time.
            print("authorizedAlways")
            self.locationManager.startUpdatingLocation()
             break
                
          case .notDetermined:
            print("notDetermined")
             break
       
    

但是,当我单击按钮时,询问位置权限的对话框会在一秒钟后消失。知道为什么吗?

【问题讨论】:

【参考方案1】:

有两件事需要解决:

    您已经在init 中调用了requestWhenInUseAuthorization,这就是您在构建按钮时看到警报的原因。您应该删除 init 中的 requestWhenInUseAuthorization

    您应该在确定您获得授权后致电startUpdatingLocationLocationManager

func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) 
    switch status 
    case .authorizedAlways, .authorizedWhenInUse:
        manager.startUpdatingLocation()
    default:
        print("no auth")
    

【讨论】:

谢谢,我已经在我的编辑中更新了上面的代码。但是,由于某种原因,请求位置许可的对话框在一秒钟后消失了。知道为什么吗? 我最好的猜测是它与 SwiftUI 本身有关。您正在视图中创建一个经理,并且可以在完成其课程之前将其解除分配。您应该将按钮的操作定向到交互器(大概是@ObservableObject)并在该交互器中分配 LocationManager,您确信它会一直保留到您认为不再需要它为止。您可以通过实现 LocationManager 的 'deinit' 方法来尝试它,或者在 Button 的操作中打印。【参考方案2】:

您在LocationManager init 方法中请求授权。 您应该从 init 中删除该代码。

class LocationManager: NSObject, ObservableObject 
    @Published var locationStatus: CLAuthorizationStatus? = CLAuthorizationStatus.notDetermined
    @Published var locationPermissionStatus = PermissionStatus.unknown
    @Published var location: CLLocation?
    let locationManager = CLLocationManager()
    
    override init()
        super.init()
        self.locationManager.delegate = self
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
        self.locationManager.requestWhenInUseAuthorization()
        self.locationManager.startUpdatingLocation()
    

    func requestAuthorization() 
        self.locationManager.requestWhenInUseAuthorization()
    

    func startUpdate() 
        self.locationManager.startUpdatingLocation()
    
    
    enum PermissionStatus 
        case unknown
        case authorizedWhenInUse
        case authorizedAlways
        case restricted
        case denied
    
    
    func getLocation() -> CLLocationCoordinate2D? 
        return self.location?.coordinate
    
    

在你看来:

struct TurnOnLocation: View 
    
    var body: some View 
        ZStack 
            Color.orange
                .edgesIgnoringSafeArea(.all)
            VStack 
                Spacer()
                Image(systemName: "globe")
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .foregroundColor(.white)
                Spacer()

                Button(action: 
                    let locationManager = LocationManager()
                    locationManager.requestAuthorization()
                    // you should check for authorization result first
                    locationManager.startUpdatingLocation()
                ) 
                    Text("Turn on location")
                .foregroundColor(Color.black)
                .font(Font.system(size:22))
                .padding(20)
                .background(
                    Rectangle()
                        .fill(Color.white)
                        .border(Color.white, width:1)
                )
                .cornerRadius(50)
                .shadow(radius: 10)
                .padding(50)
            
        
    

【讨论】:

这行得通 - 但是在我单击按钮后,位置对话框会在 1 秒后消失。有什么想法吗?【参考方案3】:

要修复 1 秒后消失的问题,请尝试像这里一样初始化位置管理:

struct TurnOnLocation: View 
    let locationManager = LocationManager() <- try to init location manager here

    var body: some View 
        ZStack 
            Color.orange
                .edgesIgnoringSafeArea(.all)
            VStack 
                Spacer()
                Image(systemName: "globe")
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .foregroundColor(.white)
                Spacer()

                Button(action:    
                 locationManager.locationManager.requestWhenInUseAuthorization()
                    locationManager.locationManager.startUpdatingLocation()
                ) 
                    Text("Turn on location")
                .foregroundColor(Color.black)
                .font(Font.system(size:22))
                .padding(20)
                .background(
                    Rectangle()
                        .fill(Color.white)
                        .border(Color.white, width:1)
                )
                .cornerRadius(50)
                .shadow(radius: 10)
                .padding(50)
            
        
    

【讨论】:

以上是关于在我调用 requestWhenInUseAuthorization() 之前触发位置权限对话框的主要内容,如果未能解决你的问题,请参考以下文章

无法在我的组件中调用 redux 操作

为啥在我的 java 代码中没有调用通知

为啥我应该在我的代码中尽量减少系统调用的使用?

在我的 webview 上调用 didFinish 不起作用

在我调用 paypal 沙盒 api 的网页底部显示额外内容

为啥当我使用 presentModelViewController 时未在我的 UITabBArController 中调用 viewWillAppear?