¿Cómo puedo obtener la ubicación actual del usuario en iOS?


Respuestas:


336

La respuesta de RedBlueThing funcionó bastante bien para mí. Aquí hay un código de muestra de cómo lo hice.

Encabezamiento

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>

@interface yourController : UIViewController <CLLocationManagerDelegate> {
    CLLocationManager *locationManager;
}

@end

Archivo principal

En el método init

locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];

Función de devolución de llamada

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
    NSLog(@"OldLocation %f %f", oldLocation.coordinate.latitude, oldLocation.coordinate.longitude);
    NSLog(@"NewLocation %f %f", newLocation.coordinate.latitude, newLocation.coordinate.longitude);
}

ios 6

En iOS 6, la función de delegado estaba en desuso. El nuevo delegado es

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations

Por lo tanto, para obtener la nueva posición, use

[locations lastObject]

iOS 8

En iOS 8, se debe solicitar explícitamente el permiso antes de comenzar a actualizar la ubicación

locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;

if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
    [self.locationManager requestWhenInUseAuthorization];

[locationManager startUpdatingLocation];

También debe agregar una cadena para las teclas NSLocationAlwaysUsageDescriptiono NSLocationWhenInUseUsageDescriptional Info.plist de la aplicación. De lo contrario startUpdatingLocation, se ignorarán las llamadas a y su delegado no recibirá ninguna devolución de llamada.

Y al final, cuando haya terminado de leer la ubicación, llame a stop. Actualice la ubicación en el lugar adecuado.

[locationManager stopUpdatingLocation];

44
+1 gracias por publicar un fragmento de código simple para complementar la respuesta aceptada
AngeloS

12
Tenga cuidado con este ejemplo, estos valores de propiedad conducen a un mayor consumo de batería.
DanSkeel

36
IMPORTANTE: también debe "detener las actualizaciones de ubicación"; de lo contrario, se llamará al método delegado cada vez que el usuario cambie su ubicación. Por lo tanto, el problema de batería mencionado anteriormente y también si se activa otro método en este método delegado, se seguirá llamando. Happy Coding Guys !! ¡¡Salud!!
Apple_iOS0304

55
Usted es el tipo de usuario que hace que StackOverflow sea excelente. Los fragmentos de código son ejemplares y espero que más personas los incluyan con sus respuestas.
Danny

26
Para iOS 8.0+, debe incluir las siguientes claves en Info.plist de su proyecto: NSLocationAlwaysUsageDescriptionsi está utilizando [self.locationManager requestAlwaysAuthorization]o NSLocationWhenInUseUsageDescriptionsi está utilizando [self.locationManager requestWhenInUseAuthorization]. También para admitir iOS 6.0+ a iOS 7.0+ incluye la clave NSLocationUsageDescriptiono 'Privacidad - Descripción del uso de la ubicación'. Más información en el enlace: developer.apple.com/library/ios/documentation/General/Reference/…
Sihad Begovic

79

En iOS 6, el

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

es obsoleto.

Use el siguiente código en su lugar

- (void)locationManager:(CLLocationManager *)manager
     didUpdateLocations:(NSArray *)locations {
    CLLocation *location = [locations lastObject];
    NSLog(@"lat%f - lon%f", location.coordinate.latitude, location.coordinate.longitude);
}

Para iOS 6 ~ 8, el método anterior sigue siendo necesario, pero debe manejar la autorización.

_locationManager = [CLLocationManager new];
_locationManager.delegate = self;
_locationManager.distanceFilter = kCLDistanceFilterNone;
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;

if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0 &&
    [CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedWhenInUse
    //[CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedAlways
   ) {
     // Will open an confirm dialog to get user's approval 
    [_locationManager requestWhenInUseAuthorization]; 
    //[_locationManager requestAlwaysAuthorization];
} else {
    [_locationManager startUpdatingLocation]; //Will update location immediately 
}

Este es el método delegado que maneja la autorización del usuario

#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager*)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    switch (status) {
    case kCLAuthorizationStatusNotDetermined: {
        NSLog(@"User still thinking..");
    } break;
    case kCLAuthorizationStatusDenied: {
        NSLog(@"User hates you");
    } break;
    case kCLAuthorizationStatusAuthorizedWhenInUse:
    case kCLAuthorizationStatusAuthorizedAlways: {
        [_locationManager startUpdatingLocation]; //Will update location immediately
    } break;
    default:
        break;
    }
}

10
¿No debería ser esto [locations lastObject]?
Ian Dundas

1
Intenté exactamente los mismos pasos mencionados anteriormente. Pero me sale "El usuario sigue pensando" impreso en la consola. Entonces, ¿significa que la aplicación no está autorizada para usar la ubicación? En caso afirmativo, ¿cómo permito que la aplicación use la ubicación? Por favor ayuda.
kirans_6891


31

Prueba estos sencillos pasos ...

NOTA: Verifique la ubicación y la latitud de la ubicación del dispositivo si está utilizando medios simuladores. Por defecto, no es ninguno.

Paso 1:CoreLocation marco de importación en el archivo .h

#import <CoreLocation/CoreLocation.h>

Paso 2: Agregar delegado CLLocationManagerDelegate

@interface yourViewController : UIViewController<CLLocationManagerDelegate>
{
    CLLocationManager *locationManager;
    CLLocation *currentLocation;
}

Paso 3: agregue este código en el archivo de clase

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self CurrentLocationIdentifier]; // call this method
}

Paso 4: Método para detectar la ubicación actual

//------------ Current Location Address-----
-(void)CurrentLocationIdentifier
{
    //---- For getting current gps location
    locationManager = [CLLocationManager new];
    locationManager.delegate = self;
    locationManager.distanceFilter = kCLDistanceFilterNone;
    locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    [locationManager startUpdatingLocation];
    //------
}

Paso 5: obtenga la ubicación con este método

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    currentLocation = [locations objectAtIndex:0];
    [locationManager stopUpdatingLocation];
    CLGeocoder *geocoder = [[CLGeocoder alloc] init] ;
    [geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error)
     {
         if (!(error))
         {
             CLPlacemark *placemark = [placemarks objectAtIndex:0];
             NSLog(@"\nCurrent Location Detected\n");
             NSLog(@"placemark %@",placemark);
             NSString *locatedAt = [[placemark.addressDictionary valueForKey:@"FormattedAddressLines"] componentsJoinedByString:@", "];
             NSString *Address = [[NSString alloc]initWithString:locatedAt];
             NSString *Area = [[NSString alloc]initWithString:placemark.locality];
             NSString *Country = [[NSString alloc]initWithString:placemark.country];
             NSString *CountryArea = [NSString stringWithFormat:@"%@, %@", Area,Country];
             NSLog(@"%@",CountryArea);
         }
         else
         {
             NSLog(@"Geocode failed with error %@", error);
             NSLog(@"\nCurrent Location Not Detected\n");
             //return;
             CountryArea = NULL;
         }
         /*---- For more results 
         placemark.region);
         placemark.country);
         placemark.locality); 
         placemark.name);
         placemark.ocean);
         placemark.postalCode);
         placemark.subLocality);
         placemark.location);
          ------*/
     }];
}

14

En Swift (para iOS 8+).

Info.plist

Lo primero es lo primero. Debe agregar su cadena descriptiva en el archivo info.plist para las claves NSLocationWhenInUseUsageDescriptiono NSLocationAlwaysUsageDescriptionsegún el tipo de servicio que solicite

Código

import Foundation
import CoreLocation

class LocationManager: NSObject, CLLocationManagerDelegate {
    
    let manager: CLLocationManager
    var locationManagerClosures: [((userLocation: CLLocation) -> ())] = []
    
    override init() {
        self.manager = CLLocationManager()
        super.init()
        self.manager.delegate = self
    }
    
    //This is the main method for getting the users location and will pass back the usersLocation when it is available
    func getlocationForUser(userLocationClosure: ((userLocation: CLLocation) -> ())) {
        
        self.locationManagerClosures.append(userLocationClosure)
        
        //First need to check if the apple device has location services availabel. (i.e. Some iTouch's don't have this enabled)
        if CLLocationManager.locationServicesEnabled() {
            //Then check whether the user has granted you permission to get his location
            if CLLocationManager.authorizationStatus() == .NotDetermined {
                //Request permission
                //Note: you can also ask for .requestWhenInUseAuthorization
                manager.requestWhenInUseAuthorization()
            } else if CLLocationManager.authorizationStatus() == .Restricted || CLLocationManager.authorizationStatus() == .Denied {
                //... Sorry for you. You can huff and puff but you are not getting any location
            } else if CLLocationManager.authorizationStatus() == .AuthorizedWhenInUse {
                // This will trigger the locationManager:didUpdateLocation delegate method to get called when the next available location of the user is available
                manager.startUpdatingLocation()
            }
        }
        
    }
    
    //MARK: CLLocationManager Delegate methods
    
    @objc func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
        if status == .AuthorizedAlways || status == .AuthorizedWhenInUse {
            manager.startUpdatingLocation()
        }
    }
    
    func locationManager(manager: CLLocationManager, didUpdateToLocation newLocation: CLLocation, fromLocation oldLocation: CLLocation) {
        //Because multiple methods might have called getlocationForUser: method there might me multiple methods that need the users location.
        //These userLocation closures will have been stored in the locationManagerClosures array so now that we have the users location we can pass the users location into all of them and then reset the array.
        let tempClosures = self.locationManagerClosures
        for closure in tempClosures {
            closure(userLocation: newLocation)
        }
        self.locationManagerClosures = []
    }
}

Uso

self.locationManager = LocationManager()
self.locationManager.getlocationForUser { (userLocation: CLLocation) -> () in
            print(userLocation)
        }

8
Creo que hay un cambio () rápido para casos como este: ^)
Anton Tropashko

self.locationManager = LocationManager()use esta línea en el método viewDidLoad para que ARC no elimine la instancia y la ventana emergente de ubicación desaparezca demasiado rápido.
Kunal Gupta


2

iOS 11.x Swift 4.0 Info.plist necesita estas dos propiedades

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>We're watching you</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Watch Out</string>

Y este código ... asegurándose de que, por supuesto, sea un CLLocationManagerDelegate

let locationManager = CLLocationManager()

// MARK location Manager delegate code + more

func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    switch status {
    case .notDetermined:
        print("User still thinking")
    case .denied:
        print("User hates you")
    case .authorizedWhenInUse:
            locationManager.stopUpdatingLocation()
    case .authorizedAlways:
            locationManager.startUpdatingLocation()
    case .restricted:
        print("User dislikes you")
    }

Y, por supuesto, también este código que puede poner en viewDidLoad ().

locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestLocation()

Y estos dos para el requestLocation para ponerlo en marcha, es decir, evitar que tenga que levantarse de su asiento :)

func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
    print(error)
}

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

1

Puede usar este servicio que escribí para manejar todo por usted.

Este servicio solicitará los permisos y se encargará de tratar con CLLocationManager para que no tenga que hacerlo.

Usar así:

LocationService.getCurrentLocationOnSuccess({ (latitude, longitude) -> () in
    //Do something with Latitude and Longitude

    }, onFailure: { (error) -> () in

      //See what went wrong
      print(error)
})

0

Para Swift 5, aquí hay una breve clase rápida para obtener la ubicación:

class MyLocationManager: NSObject, CLLocationManagerDelegate {
    let manager: CLLocationManager

    override init() {
        manager = CLLocationManager()
        super.init()
        manager.delegate = self
        manager.distanceFilter = kCLDistanceFilterNone
        manager.desiredAccuracy = kCLLocationAccuracyBest
        manager.requestWhenInUseAuthorization()
        manager.startUpdatingLocation()
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        // do something with locations
    }
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.