web-dev-qa-db-fra.com

CLLocationManager dans Swift pour obtenir l'emplacement de l'utilisateur

J'essaie de convertir une vieille application d'ObjC en Swift en tant qu'exercice pratique et j'ai rencontré quelques problèmes. Comme je l'avais dans l'ancienne application, cela créait le gestionnaire de CLLocation, puis j'utilisais:

manager = [[CLLocationManager alloc]init];
manager.delegate = self;
manager.desiredAccuracy = kCLLocationAccuracyBest;    
[manager startUpdatingLocation]

qui appellerait automatiquement:

-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
}

et à partir de là, je pourrais extraire toutes les informations dont j'avais besoin. Mais dans Swift, il n'y a pas d'auto-complétion de cette méthode et je ne peux pas comprendre comment la reproduire. La documentation dit que 

startUpdatingLocation()

sera toujours appelé par le délégué, mais cela ne se produit pas. 

C'est ce que j'ai jusqu'ici:

import UIKit
import corelocation

class ViewController: UIViewController,CLLocationManagerDelegate{

@IBOutlet var gpsResult : UILabel

var manager:CLLocationManager!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    manager = CLLocationManager()
    manager.delegate = self
    manager.desiredAccuracy = kCLLocationAccuracyBest
    manager.startUpdatingLocation()
}

func locationManager(manager:CLLocationManager, didUpdateLocations locations:AnyObject[]) {
    println("locations = \(locations)")
    gpsResult.text = "success"
}
}

Toute aide ou indication sur les endroits où chercher serait appréciée. Merci.

EDIT: mis à jour à partir de suggestions, mais ne fonctionne toujours pas

EDIT2: Il semble y avoir un bogue empêchant la méthode de fonctionner correctement dans ViewController

27
Sean Fitz

Il te manque deux choses. Tout d'abord, vous devez demander l'autorisation en utilisant requestAlwaysAuthorization ou requestWhenInUseAuthorization(). Donc, votre viewDidLoad() devrait être comme ceci:

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    locationManager = CLLocationManager()
    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.requestAlwaysAuthorization()
    locationManager.startUpdatingLocation()
}

Deuxièmement, éditez votre Info.plistcomme indiqué ici .

61
danilopez.dev

Ajoutez d'abord ces deux lignes dans le fichier plist

1) NSLocationWhenInUseUsageDescription

2) NSLocationAlwaysUsageDescription

Ensuite, ceci est un travail de classe complet

import UIKit

import CoreLocation

@UIApplicationMain

class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {

var window: UIWindow?
var locationManager: CLLocationManager!
var seenError : Bool = false
var locationFixAchieved : Bool = false
var locationStatus : NSString = "Not Started"

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
    initLocationManager();
    return true
}

// Location Manager helper stuff
func initLocationManager() {
    seenError = false
    locationFixAchieved = false
    locationManager = CLLocationManager()
    locationManager.delegate = self
    locationManager.locationServicesEnabled
    locationManager.desiredAccuracy = kCLLocationAccuracyBest

    locationManager.requestAlwaysAuthorization()
}

// Location Manager Delegate stuff
// If failed
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
    locationManager.stopUpdatingLocation()
    if (error) {
        if (seenError == false) {
            seenError = true
           print(error)
        }
    }
}

func locationManager(manager: CLLocationManager!, didUpdateLocations locations: AnyObject[]!) {
    if (locationFixAchieved == false) {
        locationFixAchieved = true
        var locationArray = locations as NSArray
        var locationObj = locationArray.lastObject as CLLocation
        var coord = locationObj.coordinate

        println(coord.latitude)
        println(coord.longitude)
    }
}

// authorization status
func locationManager(manager: CLLocationManager!,
    didChangeAuthorizationStatus status: CLAuthorizationStatus) {
        var shouldIAllow = false

        switch status {
        case CLAuthorizationStatus.Restricted:
            locationStatus = "Restricted Access to location"
        case CLAuthorizationStatus.Denied:
            locationStatus = "User denied access to location"
        case CLAuthorizationStatus.NotDetermined:
            locationStatus = "Status not determined"
        default:
            locationStatus = "Allowed to location Access"
            shouldIAllow = true
        }
        NSNotificationCenter.defaultCenter().postNotificationName("LabelHasbeenUpdated", object: nil)
        if (shouldIAllow == true) {
            NSLog("Location to Allowed")
            // Start location services
            locationManager.startUpdatingLocation()
        } else {
            NSLog("Denied access: \(locationStatus)")
        }
}
}
21
jayesh kavathiya

Je ne sais pas pourquoi, mais il semble que startUpdatingLocation ne présente pas l'invite de l'utilisateur sur le simulateur iOS 7, mais lorsque je l'ai activée manuellement, cela fonctionnait comme prévu si j'utilisais le nouveau formulaire de la méthode déléguée:

var manager:CLLocationManager!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    manager = CLLocationManager()
    manager.delegate = self
    manager.desiredAccuracy = kCLLocationAccuracyBest
    manager.startUpdatingLocation()
}

func locationManager(manager:CLLocationManager, didUpdateLocations locations:[AnyObject]) { // Updated to current array syntax [AnyObject] rather than AnyObject[]
    println("locations = \(locations)")
}

Le format que vous utilisez est obsolète depuis iOS 5 ou 6, donc apparemment, il n'est pas pris en charge du tout par les couches de pontage Swift.

6
David Berry

avait le même problème. didUpdateLocations - ne fonctionnait pas. Exécutez votre application. Accédez à la page Paramètres -> Confidentialité -> Localisation et désactivez les services de localisation. didFailWithError intercepte l'erreur concernant les services de localisation absents. Puis allumez-le. Depuis ce moment, didUpdateLocations capturera des emplacements.

3
salty

J'espère qu'il y a deux façons.

    var locationManager: CLLocationManager = CLLocationManager()
  var initialLocation :CLLocation?
  var updatedUserLocation :CLLocation?

  override func viewDidLoad() {
    super.viewDidLoad() {

        //MapView Location
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingLocation()
        locationManager.startUpdatingHeading()
}

Implémentation de CLLocationManagerDelegate:

//CLLocationManager Delegate
  func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

// This only works when user location is updated.
gpsProviderStatusLabel.changeStatusToOn(gpsProviderStatusLabel)

  }
  func locationManager(manager: CLLocationManager,
    didFailWithError error: NSError) {

//Error indicates GPS permission restricted

      gpsProviderStatusLabel.changeStatusToOff(gpsProviderStatusLabel)

//Initial Location
initialLocation = locations.first

//Getting Updated Location
updatedUserLocation = locations.last

  }

Vérification de l'autorisation CLLocationDelegate: 

 func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {

//This method does real time status monitoring.

        switch status {
        case .NotDetermined:
          print(".NotDetermined")
          break

        case .AuthorizedAlways:
          print(".AuthorizedAlways")
          gpsProviderStatusLabel.changeStatusToOn(gpsProviderStatusLabel)
          break


        case .Denied:
          print(".Denied")
          gpsProviderStatusLabel.changeStatusToOff(gpsProviderStatusLabel)
          break

        case .AuthorizedWhenInUse:
          print(".AuthorizedWhenInUse")
          gpsProviderStatusLabel.changeStatusToOn(gpsProviderStatusLabel)
          break

        case .Restricted:
          print(".Restricted")
          break

        default:
          print("Unhandled authorization status")
          break

        }
      }

Remarque: changeStatusToOn ou changeStatusToOff est une méthode d’extension UILabel qui rend le texte de l’étiquette activé/désactivé avec des couleurs vert/rouge.

2
A.G

Pour Swift 3

import UIKit
import CoreLocation

class ViewController: UIViewController,CLLocationManagerDelegate {


    var locationManager:CLLocationManager!

    override func viewDidLoad() {
        super.viewDidLoad()

        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestAlwaysAuthorization()
        locationManager.startUpdatingLocation()

        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func locationManager(_ manager:CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        print("locations = \(locations)")
    }


}
2
Steffen

Voici mon code très simple qui fonctionne:

ajoutez d'abord le cadre d'emplacement principal dans les cadres et bibliothèques généraux/liés

puis ajoutez ce qui suit dans Info.plist:

<key>NSLocationWhenInUseUsageDescription</key>
<string>blablabla</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>blablabla</string>

voici mon fichier ViewController.Swift:

import UIKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate {

    var locationManager:CLLocationManager!

    override func viewDidLoad() {
        super.viewDidLoad()

        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestAlwaysAuthorization()
        locationManager.startUpdatingLocation()
    }


    func locationManager(manager:CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        print("locations = \(locations)")
    }

}
2
Jarda Pavlíček

n'oubliez pas d'ajouter NSLocationWhenInUseUsageDescription ou NSLocationAlwaysUsageDescription dans votre fichier de configuration (cible/Info/propriétés de cible iOS personnalisées

1
Vassily

Rapide:

Ajouter la suite dans 

import CoreLocation
class YourViewController: UIViewController
{
       var locationManager:CLLocationManager!
}


//MARK:- Location Manager
extension YourViewController: CLLocationManagerDelegate {

    func stratLocationManager()
    {
        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        self.checkUsersLocationServicesAuthorization()
        locationManager.startUpdatingLocation()

    }

    func checkUsersLocationServicesAuthorization(){
        /// Check if user has authorized Total Plus to use Location Services
        if CLLocationManager.locationServicesEnabled()
        {
            switch CLLocationManager.authorizationStatus()
            {
            case .notDetermined:
                // Request when-in-use authorization initially
                // This is the first and the ONLY time you will be able to ask the user for permission
                self.locationManager.delegate = self
                locationManager.requestWhenInUseAuthorization()
                break

            case .restricted, .denied:
                // Disable location features
                PrintLogs("Location Access Not Available")
                break

            case .authorizedWhenInUse, .authorizedAlways:
                // Enable features that require location services here.
                PrintLogs("Location Access Available")
                break
            }
        }
    }

    func locationManager(_ manager:CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        print("locations = \(locations)")
    }
}
0
svmrajesh

Cela demandera la permission et suivra si une permission est donnée sinon quitter avec une alerte. Arrête le suivi en appuyant sur le bouton de retour.

info.plist

<key>NSLocationAlwaysUsageDescription</key>
<string>Allow tracking while completing a survey</string>

Classe:

import UIKit
import CoreLocation    

class LocationViewController: BaseViewController, CLLocationManagerDelegate {

        // MARK: Constants

        private static let enableLocationServices = [
            "title" : "Location",
            "message" : "Enable location services",
            "buttonTitle" : "OK"
        ]

        // MARK: Private variables

        private var manager: CLLocationManager?

        // MARK: UIViewCOntroller methods

        @IBAction func backButtonPressed(sender : UIButton) {
            stopTracking()
            detatchLocationManager()
            dismissViewControllerAnimated(true, completion: nil)
        }

        override func viewDidLoad() {
            super.viewDidLoad()

            attachLocationManager()    
        }

        // Mark: Location

        func locationManager(manager: CLLocationManager,
                             didChangeAuthorizationStatus status: CLAuthorizationStatus)
        {
            if status == .AuthorizedAlways {
                manager.startUpdatingLocation()
            } else if status != .NotDetermined {
                showEnableLocationServicesAlert()
            }
        }

        func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
            for location in locations {
                getDependencyService().getProject().appendLocationTrackingFile(location.timestamp, latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
            }
        }

        // MARK: LocationViewController

        private func attachLocationManager() {
            manager = CLLocationManager()
            manager?.delegate = self
            manager?.desiredAccuracy = kCLLocationAccuracyBest

            if CLLocationManager.authorizationStatus() != .AuthorizedAlways {
                manager?.requestAlwaysAuthorization()
            } else if CLLocationManager.locationServicesEnabled() {
                startTracking()
            }
        }

        private func detatchLocationManager() {
            manager?.stopUpdatingLocation()
            manager?.delegate = nil
            manager = nil
        }

        private func startTracking() {
            manager?.startUpdatingLocation()
        }

        private func stopTracking() {
            manager?.stopUpdatingLocation()
        }

        private func showEnableLocationServicesAlert() {
getDependencyService().getUiHelper().showAlert(FrogFirstSurveyViewController.enableLocationServices, completion: {
                self.dismissViewControllerAnimated(true, completion: nil)
            })
        }

    }
0
Gary Davies

Si vous souhaitez que l'emplacement de l'utilisateur soit mis à jour par défaut, sans cliquer sur "Simuler l'emplacement" à chaque fois, accédez à

YourProject-->Build Phases-->Link Binary with libraries-->Add corelocation.framework

L'emplacement est mis à jour automatiquement/par défaut lorsque vous exécutez l'application dans le simulateur. Testé et fonctionne dans Swift 2!

0
Naishta

Ajouter ci-dessous 2 biens dans info.plist

NSLocationWhenInUseUsageDescription : Location information is used for fraud prevention

Privacy - Location Usage Description : Location information is used for fraud prevention
0
Mitul Marsoniya