在自定义Sirikit、iOS、swift中访问用户当前位置

在自定义Sirikit、iOS、swift中访问用户当前位置,ios,swift,ios12,sirikit,Ios,Swift,Ios12,Sirikit,我创建了一个自定义Sirikit intent,在IntentHandler类中,我找不到默认设置了位置隐私“Always”的用户位置。 请看代码 import Foundation import CoreData import CoreLocation class PhotoOfTheDayIntentHandler: NSObject, PhotoOfTheDayIntentHandling { let context = CoreDataStorage.mainQueueConte

我创建了一个自定义Sirikit intent,在IntentHandler类中,我找不到默认设置了位置隐私“Always”的用户位置。 请看代码

    import Foundation
import CoreData
import CoreLocation
class PhotoOfTheDayIntentHandler: NSObject, PhotoOfTheDayIntentHandling {
let context = CoreDataStorage.mainQueueContext()
var counter : DistanceEntity?
var locationManger = CLLocationManager()
    func confirm(intent: PhotoOfTheDayIntent, completion: @escaping (PhotoOfTheDayIntentResponse) -> Void) {
        completion(PhotoOfTheDayIntentResponse(code: .ready, userActivity: nil))
}

func handle(intent: PhotoOfTheDayIntent, completion: @escaping (PhotoOfTheDayIntentResponse) -> Void) {
    self.context.performAndWait{ () -> Void in
        let counter = NSManagedObject.findAllForEntity("DistanceEntity", context: self.context)
        if (counter?.last != nil) {
            self.counter = (counter!.last as! DistanceEntity)
                let currentLocation: CLLocation = locationManger.location!
                let greenLocation = CLLocation(latitude:self.counter!.latitude, longitude: self.counter!.longitude)
                let distanceInMeters = currentLocation.distance(from: greenLocation) // result is in meters
                debugPrint("distanceInMeters",distanceInMeters)
                completion(PhotoOfTheDayIntentResponse.success(photoTitle: "\(distanceInMeters) Meter"))
            completion(PhotoOfTheDayIntentResponse.success(photoTitle: "\(self.counter!.distance) Meter"))
        }
    }
}
}

如果我对位置管理器进行注释,它会崩溃。

TLDR:在主线程中创建
CLLocationManager
,它应该可以工作

import CoreLocation
class WhateverYouWant: NSObject{
let userLocation = UserLocationManager()



func handle(intent: DistanceOfGreenIntent, completion: @escaping (DistanceOfGreenIntentResponse) -> Void) {
    
    if(userLocation.locationManager.location == nil){
        userLocation.locationManager.requestAlwaysAuthorization()
        userLocation.locationManager.desiredAccuracy = kCLLocationAccuracyBest
    }
    
    
    if let currentLocation: CLLocation = userLocation.locationManager.location{
        self.context.performAndWait{ () -> Void in
           completion(DistanceOfGreenIntentResponse.success(distanceString:"Please Start a game on course to get distances"))
    }else{
        debugPrint("Please enable your location")
        completion(DistanceOfGreenIntentResponse.success(distanceString: "Please enable your location to get distances"))
    }}
}

如果您在mac上打开Console.app并监视正在运行Siri Intent的设备,您可能会收到类似以下消息:

在主线程以外的线程上执行的调度队列上创建了位置管理器(0xe86bdf0)

(就像这个问题:)

问题是核心位置必须在连接到主循环的运行循环中创建。最简单的解决方案是在主循环中创建
CLLocationManager

下面是一个使用位置的示例意图处理程序

import Foundation
import CoreLocation

class ExampleIntentHandler: NSObject, ExampleIntentIntentHandling, CLLocationManagerDelegate {
    private var locationManager: CLLocationManager?

    var onDidChangeAuthorization: ((ExampleIntentResponse) -> Void)?
    var onDidUpdateLocations: ((ExampleIntentResponse) -> Void)?

    func confirm(intent: CurrentSpeedIntent, completion: @escaping (CurrentSpeedIntentResponse) -> Void) {
        DispatchQueue.main.async {
            self.onDidChangeAuthorization = completion
            self.locationManager = CLLocationManager()
            self.locationManager?.delegate = self
            self.locationManager?.requestWhenInUseAuthorization()
        }
    }

    func handle(intent: CurrentSpeedIntent, completion: @escaping (CurrentSpeedIntentResponse) -> Void) {
        DispatchQueue.main.async {
            self.onDidUpdateLocations = completion
            self.locationManager = CLLocationManager()
            self.locationManager?.delegate = self
            self.locationManager?.desiredAccuracy = kCLLocationAccuracyBest
            self.locationManager?.startUpdatingLocation()
        }
    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        switch status {
        case .authorizedAlways, .authorizedWhenInUse:
            let response = ExampleIntentResponse(code: .ready, userActivity: nil)
            onDidChangeAuthorization?(response)
        default:
            let response = ExampleIntentResponse(code: .failure, userActivity: nil)
            onDidChangeAuthorization?(response)
        }
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.last else {
            return
        }

        // Do something with the `location` but note that this
        // method could be called multiple times by iOS. So if
        // you do more that just responding, like fetching a
        // photo, or manipulate something in your database you
        // will probably set some kind of variable here and 
        // stop if that is already set.
        // 
        // Example:
        //     guard intentHandled == false else { return }
        //     intentHandled = true
        // 
        // The `intentHandled` must of course be a instance variable

        // Don't forget to respond!
        let response = ExampleIntentResponse(code: .success, userActivity: nil)
        self.onDidUpdateLocations?(response)
    }
}
这也将仅在实际存在位置时执行。我可以看到,你正在强制展开你的位置,这是一个糟糕的做法,因为它可能是零,然后你的意图就会崩溃。在这里,当我们找到位置时,我们将做我们需要的事情

import Foundation
import CoreLocation

class ExampleIntentHandler: NSObject, ExampleIntentIntentHandling, CLLocationManagerDelegate {
    private var locationManager: CLLocationManager?

    var onDidChangeAuthorization: ((ExampleIntentResponse) -> Void)?
    var onDidUpdateLocations: ((ExampleIntentResponse) -> Void)?

    func confirm(intent: CurrentSpeedIntent, completion: @escaping (CurrentSpeedIntentResponse) -> Void) {
        DispatchQueue.main.async {
            self.onDidChangeAuthorization = completion
            self.locationManager = CLLocationManager()
            self.locationManager?.delegate = self
            self.locationManager?.requestWhenInUseAuthorization()
        }
    }

    func handle(intent: CurrentSpeedIntent, completion: @escaping (CurrentSpeedIntentResponse) -> Void) {
        DispatchQueue.main.async {
            self.onDidUpdateLocations = completion
            self.locationManager = CLLocationManager()
            self.locationManager?.delegate = self
            self.locationManager?.desiredAccuracy = kCLLocationAccuracyBest
            self.locationManager?.startUpdatingLocation()
        }
    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        switch status {
        case .authorizedAlways, .authorizedWhenInUse:
            let response = ExampleIntentResponse(code: .ready, userActivity: nil)
            onDidChangeAuthorization?(response)
        default:
            let response = ExampleIntentResponse(code: .failure, userActivity: nil)
            onDidChangeAuthorization?(response)
        }
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.last else {
            return
        }

        // Do something with the `location` but note that this
        // method could be called multiple times by iOS. So if
        // you do more that just responding, like fetching a
        // photo, or manipulate something in your database you
        // will probably set some kind of variable here and 
        // stop if that is already set.
        // 
        // Example:
        //     guard intentHandled == false else { return }
        //     intentHandled = true
        // 
        // The `intentHandled` must of course be a instance variable

        // Don't forget to respond!
        let response = ExampleIntentResponse(code: .success, userActivity: nil)
        self.onDidUpdateLocations?(response)
    }
}

如果尚未完成,则还必须首先在应用程序中请求使用位置。

您是否找到了在intent handler中获取用户位置的解决方案?是的,我找到了解决方案。您可以将解决方案发布在此处吗?我也有同样的问题。Thanks@Tongo我确实在下面添加了一个可能对您有所帮助的答案。你能解释一下吗?我仍然无法理解您如何在应用程序中初始化locationManager