For iOS SDK 8.0 and later, we need to set NSLocationWhenInUseUsageDescription
and ‘NSLocationAlwaysUsageDescription’ in info.plist file. A sample case is:
1 <key>NSLocationWhenInUseUsageDescription</key>
2 <string>Do you allow the app to use your location?</string>
3 <key>NSLocationAlwaysUsageDescription</key>
4 <string>Are you willing to allow the app to use your location?</string>
The string
will appear in the popup dialog. You can leave it as empty, and only the system message will appear in the popup.
We ask for the authorization by an instance of CLLocationManager
.
CoreLocation/CoreLocation.h
class, and define a location manager locationManager
in the map view controller. 1 if ([CLLocationManager locationServicesEnabled] ) { // check if the location service is enabled for the device
2 if (self.locationManager == nil ) {
3 self.locationManager = [[CLLocationManager alloc] init];
4 self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
5 self.locationManager.distanceFilter = kCLDistanceFilterNone;
6 }
7 // Check for iOS 8. Without this guard the code will crash with "unknown selector" on iOS 7.
8 if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]){
9 CLAuthorizationStatus locationAuthorizationStatus = [CLLocationManager authorizationStatus];
10 if (locationAuthorizationStatus == kCLAuthorizationStatusNotDetermined && ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)] || [self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])) {
11 // choose one request according to your business.
12 if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"]){
13 [self.locationManager requestAlwaysAuthorization];
14 } else if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"]) {
15 [self.locationManager requestWhenInUseAuthorization];
16 } else {
17 NSLog(@"Info.plist does not contain NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription");
18 }
19 }
20 }
21 }
For iOS SDK 8.0 and later, we have two ways to get user current location:
showsUserLocation
to YES
for map view.startUpdatingLocation
to CLLocationManager
instance.For this way, after we set showsUserLocation
to YES
,
mapView:didUpdateUserLocation:
. 1 - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
2 {
3 // Center the map the first time we get a real location change.
4 static dispatch_once_t centerMapFirstTime;
5
6 if ((userLocation.coordinate.latitude != 0.0) && (userLocation.coordinate.longitude != 0.0)) {
7 dispatch_once(¢erMapFirstTime, ^{
8 [self.mapView setCenterCoordinate:userLocation.coordinate animated:YES];
9 });
10 }
11
12 }
mapView:viewForAnnotation:
. If nil
is returned, a default blue circle with white boundary is use. The circle has breathing effect. For this purpose, we need to identify the annotation (which is an id
type) type: if it is a MKUserLocation
type, return a current location annotation view or nil. Question: How to define whether an id
type object is a MKUserLocation
type object?Before implementing the above two methods, we should set the map view’s delegate comfirm with MapViewDelegate
protoco.
startUpdateingLocation
to CLLocationManager
InstaanceFor this way, after we send the method,
locationManager:didUpdateLocations:
. The newest location is the lastObject
of locations
. 1 - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
2 {
3 self.currentLocation = [locations lastObject];
4 CLLocationCoordinate2D currentCoordinate = self.currentLocation.coordinate;
5
6 if (self.currentLocationAnnotation) {
7 [self.mapView removeAnnotation:self.currentLocationAnnotation];
8 }
9 self.currentLocationAnnotation = [[CurrentLocationAnnotation alloc] initWithCoordinate:currentCoordinate];
10 [self.mapView addAnnotation:self.currentLocationAnnotation];
11 }
When you add the current location annotation to map view, you can set the current location annotation view in mapView:viewForAnnotation: method. If nil
is returned, a red pin will be use as the annotation view. Question: How can we use the default blue circle as the annotation view, just as we set showsUserLocation
to YES
?
You can also get erroe message when app fails to get the location in locationManager:didFailWithError:
method.
1 - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
2 {
3 NSLog(@"didFailWithError: %@", error);
4 UIAlertView *errorAlert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Failed to Get Your Location" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
5 [errorAlert show];
6 }
Before implementing the above methods, set the CLLocationManager
’s delegate confirm with CLLocationManagerDelegate
protoco.