cllocationmanager - requestwheninuseauthorization - location manager swift tutorial
CLLocation Manager en Swift para obtener la ubicaciĆ³n del usuario (11)
Estoy tratando de convertir una aplicación antigua en ObjC a Swift como ejercicio de práctica y me he topado con algunos problemas. De la forma en que lo tenía en la aplicación anterior, estaba estableciendo CLLocation Manager y luego usaría:
manager = [[CLLocationManager alloc]init];
manager.delegate = self;
manager.desiredAccuracy = kCLLocationAccuracyBest;
[manager startUpdatingLocation]
que llamaría automáticamente:
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
}
y de allí pude extraer toda la información que necesitaba. Pero en breve, no hay autocompletado de este método y no puedo encontrar la manera de reproducirlo. La documentación dice que
startUpdatingLocation()
todavía será llamado por el delegado, pero no está sucediendo.
Esto es lo que tengo hasta ahora:
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"
}
}
Se agradecerá cualquier ayuda o punteros sobre dónde mirar. Gracias.
EDITAR: actualizado de Sugerencias, pero aún no funciona
EDIT2: Parece ser un error que no permite que el método funcione correctamente en ViewController
Agregue la propiedad de abajo 2 en info.plist
NSLocationWhenInUseUsageDescription : Location information is used for fraud prevention
Privacy - Location Usage Description : Location information is used for fraud prevention
Aquí está mi código muy simple que funciona:
primero agregue el marco de Ubicación principal en Marcos generales / vinculados y bibliotecas
luego agregue los siguientes en Info.plist:
<key>NSLocationWhenInUseUsageDescription</key>
<string>blablabla</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>blablabla</string>
este es mi archivo 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)")
}
}
Espero que haya dos formas.
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()
}
Implementación 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
}
Verificación de la autorización de 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
}
}
Nota: changeStatusToOn o changeStatusToOff es un método UILabel Extenion que activa / desactiva el texto de la etiqueta con colores verdes / rojos.
Esto pedirá permiso y rastreará si se le dio permiso para abandonarlo con una alerta. Detiene el rastreo al presionar el botón Atrás.
info.plist
<key>NSLocationAlwaysUsageDescription</key>
<string>Allow tracking while completing a survey</string>
Clase:
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)
})
}
}
No estoy seguro de por qué, pero parece que startUpdatingLocation
no presenta el mensaje del usuario en el simulador de iOS 7, pero cuando lo habilité manualmente, funcionó como esperaba si utilizaba la forma más reciente del método de delegado:
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)")
}
El formato que está utilizando ha quedado obsoleto desde iOS 5 o 6, por lo que aparentemente no es compatible con las rápidas capas puente.
Primero agrega esta dos líneas en un archivo plist
1) NSLocationWhenInUseUsageDescription
2) NSLocationAlwaysUsageDescription
Entonces esta es la clase de trabajo completa implementar esto
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)")
}
}
}
Si desea obtener la ubicación del usuario actualizada de manera predeterminada, sin hacer clic en "Simular ubicación" cada vez, vaya a
YourProject-->Build Phases-->Link Binary with libraries-->Add corelocation.framework
La ubicación se actualiza automáticamente / de forma predeterminada cuando ejecuta la aplicación en el simulador. ¡Probado y funciona en Swift 2!
Te faltan dos cosas. En primer lugar, debe solicitar permiso utilizando requestAlwaysAuthorization
o requestWhenInUseAuthorization()
. Entonces su viewDidLoad()
debería ser así:
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()
}
Segundo, edite su Info.plist
como se indica aquí .
no olvide agregar NSLocationWhenInUseUsageDescription o NSLocationAlwaysUsageDescription en su archivo de configuración (target / Info / custom target properties)
tenía el mismo problema didUpdateLocations - no funcionaba. Ejecuta tu aplicación. Vaya a la página Configuración -> Privacidad -> Ubicación y apague los Servicios de ubicación. didFailWithError detectará el error sobre los servicios de ubicación ausentes. Luego enciéndelo. Desde ese momento didUpdateLocations captará ubicaciones.
Para 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)")
}
}