Jak mogę uzyskać aktualną lokalizację od użytkownika w iOS

Odpowiedzi:

336

Odpowiedź RedBlueThing działała dla mnie całkiem nieźle. Oto przykładowy kod pokazujący, jak to zrobiłem.

nagłówek

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

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

@end

MainFile

W metodzie init

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

Funkcja oddzwaniania

- (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

W iOS 6 funkcja delegata była przestarzała. Nowym delegatem jest

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

Dlatego, aby uzyskać nową pozycję, użyj

[locations lastObject]

iOS 8

W iOS 8 przed rozpoczęciem aktualizacji lokalizacji należy wyraźnie zapytać o pozwolenie

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];

Musisz także dodać ciąg dla kluczy NSLocationAlwaysUsageDescriptionlub NSLocationWhenInUseUsageDescriptiondo pliku Info.plist aplikacji. W przeciwnym razie wywołania do startUpdatingLocationbędą ignorowane, a Twój pełnomocnik nie otrzyma żadnego oddzwonienia.

I na koniec, gdy skończysz czytać lokalizację, zadzwoń do zatrzymania Aktualizowanie lokalizacji w odpowiednim miejscu.

[locationManager stopUpdatingLocation];
dplusm
źródło
4
+1 dzięki za opublikowanie prostego fragmentu kodu w celu uzupełnienia zaakceptowanej odpowiedzi
AngeloS
12
Uważaj na tym przykładzie, te wartości właściwości prowadzą do wyższego zużycia baterii.
DanSkeel
36
WAŻNE: Musisz także „stopUpdatingLocations”, w przeciwnym razie metoda delegata będzie wywoływana za każdym razem, gdy użytkownik zmieni swoją lokalizację. W związku z tym wspomniany powyżej problem z baterią, a także jeśli w tej metodzie delegata zostanie wyzwolona inna metoda, będzie ona nadal wywoływać. Happy Coding Guys !! Twoje zdrowie!!
Apple_iOS0304
5
Jesteś typem użytkownika, który sprawia, że ​​StackOverflow jest świetny. Fragmenty kodu są wzorowe i mam nadzieję, że więcej osób uwzględni je w swoich odpowiedziach.
Danny
26
W przypadku iOS 8.0+ musisz uwzględnić następujące klucze w Info.plist projektu: NSLocationAlwaysUsageDescriptionjeśli używasz [self.locationManager requestAlwaysAuthorization]lub NSLocationWhenInUseUsageDescriptionjeśli używasz [self.locationManager requestWhenInUseAuthorization]. Aby obsługiwać systemy iOS 6.0+ do iOS 7.0+, dołącz klucz NSLocationUsageDescriptionlub „Prywatność - Opis wykorzystania lokalizacji”. Więcej informacji pod linkiem: developer.apple.com/library/ios/documentation/General/Reference/…
Sihad Begovic
79

W iOS 6

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

jest przestarzałe.

Zamiast tego użyj następującego kodu

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

W przypadku iOS 6 ~ 8 powyższa metoda jest nadal konieczna, ale musisz obsłużyć autoryzację.

_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 
}

Jest to metoda delegata, która obsługuje autoryzację użytkownika

#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;
    }
}
Ryan Wu
źródło
10
nie powinno tak być [locations lastObject]?
Ian Dundas
1
Próbowałem dokładnie tych samych kroków, które wymieniono powyżej. Ale w konsoli wyświetla się komunikat „Użytkownik wciąż myśli”. Czy to oznacza, że ​​aplikacja nie ma uprawnień do korzystania z lokalizacji? Jeśli tak, jak zezwolić aplikacji na używanie lokalizacji. Proszę pomóż.
kirans_6891
31

Wypróbuj te proste kroki ....

UWAGA: Sprawdź szerokość i logitude lokalizacji urządzenia, jeśli używasz środków symulatora. Domyślnie jest to tylko none.

Krok 1: Importuj CoreLocationstrukturę w pliku .h

#import <CoreLocation/CoreLocation.h>

Krok 2: Dodaj delegata CLLocationManagerDelegate

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

Krok 3: Dodaj ten kod w pliku klasy

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

Krok 4: Metoda wykrywania aktualnej lokalizacji

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

Krok 5: Uzyskaj lokalizację za pomocą tej metody

- (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);
          ------*/
     }];
}
Rajesh Loganathan
źródło
14

W Swift (dla iOS 8+).

Info.plist

Po pierwsze. Musisz dodać swój opisowy ciąg w pliku info.plist dla kluczy NSLocationWhenInUseUsageDescriptionlub w NSLocationAlwaysUsageDescriptionzależności od rodzaju usługi, o którą prosisz

Kod

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 = []
    }
}

Stosowanie

self.locationManager = LocationManager()
self.locationManager.getlocationForUser { (userLocation: CLLocation) -> () in
            print(userLocation)
        }
villy393
źródło
8
wierzę, że w takich przypadkach jest szybki przełącznik (): ^)
Anton Tropashko,
self.locationManager = LocationManager()użyj tego wiersza w metodzie viewDidLoad, aby ARC nie usuwał instancji, a wyskakujące okienko lokalizacji zniknęło zbyt szybko.
Kunal Gupta,
2

iOS 11.x Swift 4.0 Info.plist potrzebuje tych dwóch właściwości

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

I ten kod ... upewniając się oczywiście, że jesteś 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")
    }

I oczywiście ten kod, który możesz umieścić w viewDidLoad ().

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

I te dwa na prośbęLokalizacja, abyś mógł iść, aka oszczędzając ci konieczności wstawania z miejsca :)

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

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    print(locations)
}
user3069232
źródło
1

Możesz skorzystać z tej usługi, którą napisałem, aby załatwić wszystko za Ciebie.

Ta usługa zażąda uprawnień i zajmie się obsługą CLLocationManager, więc nie musisz tego robić.

Użyj w ten sposób:

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

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

      //See what went wrong
      print(error)
})
William Falcon
źródło
0

Dla Swift 5, oto krótka krótka klasa, aby uzyskać lokalizację:

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
    }
}
Dave Elson
źródło