Reputation: 3147
I have been having trouble with location services in iOS 11 for both "Allow while Use" and "Always Allow". Works without issue in iOS < 11. Followed this thread in trying to fix but still doesn't work. What am I missing? Thank you in advance.
UITabViewController
in my app and a UINavigationController
inside each tab.viewWillAppear
to receive location updates and removing in viewWillDisappear
.startUpdatingLocation
I'm not receiving the location update in my UIVIewController.I have added all three location authorization description in my Info.plist file.
Info.Plist:
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Blah Blah Blah</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Blah Blah Blah</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Blah Blah Blah</string>
LocationController.m:
#import "LocationController.h"
//static int LOCATION_ACCESS_DENIED = 1;
//static int LOCATION_NETWORK_ISSUE = 2;
//static int LOCATION_UNKNOWN_ISSUE = 3;
enum {
LOCATION_ACCESS_DENIED = 1,
LOCATION_NETWORK_ISSUE = 2,
LOCATION_UNKNOWN_ISSUE = 3
};
static LocationController* sharedCLDelegate = nil;
@implementation LocationController
int distanceThreshold = 10.0; // in meters
@synthesize locationManager, currentLocation, locationObservers;
- (id)init
{
self = [super init];
if (self != nil) {
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = distanceThreshold;
self.locationManager.pausesLocationUpdatesAutomatically = NO;
[self.locationManager startMonitoringSignificantLocationChanges];
self.locationManager.delegate = (id)self;
if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
[self.locationManager requestWhenInUseAuthorization]; //I tried both commenting this line and uncommenting this line. Didn't make any difference
}
if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
{
[self.locationManager requestAlwaysAuthorization];
}
[self.locationManager startUpdatingLocation];
[self.locationManager startUpdatingHeading];
locationObservers = [[NSMutableArray alloc] init];
}
return self;
}
#pragma mark -
#pragma mark CLLocationManagerDelegate Methods
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(@"locationManager didUpdateLocations = %@",locations);
CLLocation *newLocation = [locations lastObject];
if (newLocation.horizontalAccuracy < 0) {
return;
}
currentLocation = newLocation;
for(id<LocationControllerDelegate> observer in self.locationObservers) {
if (observer) {
// CLLocation *newLocation = [locations lastObject];
// if (newLocation.horizontalAccuracy < 0) {
// return;
// }
// currentLocation = newLocation;
NSTimeInterval interval = [currentLocation.timestamp timeIntervalSinceNow];
//check against absolute value of the interval
if (fabs(interval)<30) {
[observer locationUpdate:currentLocation];
}
}
}
}
- (void)locationManager:(CLLocationManager*)manager
didFailWithError:(NSError*)error
{
NSLog(@"locationManager didFailWithError: %@", error);
for(id<LocationControllerDelegate> observer in self.locationObservers) {
if (observer) {
[observer failedToGetLocation:error];
}
}
switch (error.code) {
case kCLErrorDenied:
{
break;
}
case kCLErrorNetwork:
{
break;
}
default:
break;
}
}
#pragma mark - Singleton implementation in ARC
+ (LocationController *)sharedLocationInstance
{
static LocationController *sharedLocationControllerInstance = nil;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
sharedLocationControllerInstance = [[self alloc] init];
});
return sharedLocationControllerInstance;
}
-(void) locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
NSLog(@"didChangeAuthorizationStatus = %i",status);
if (status == kCLAuthorizationStatusAuthorizedAlways || status == kCLAuthorizationStatusAuthorizedWhenInUse) {
[self.locationManager stopUpdatingLocation];
[self.locationManager startUpdatingLocation];
}
}
- (void) addLocationManagerDelegate:(id<LocationControllerDelegate>)delegate {
if (![self.locationObservers containsObject:delegate]) {
[self.locationObservers addObject:delegate];
}
[self.locationManager startUpdatingLocation];
}
- (void) removeLocationManagerDelegate:(id<LocationControllerDelegate>)delegate {
if ([self.locationObservers containsObject:delegate]) {
[self.locationObservers removeObject:delegate];
}
}
+ (id)allocWithZone:(NSZone *)zone {
@synchronized(self) {
if (sharedCLDelegate == nil) {
sharedCLDelegate = [super allocWithZone:zone];
return sharedCLDelegate; // assignment and return on first allocation
}
}
return nil; // on subsequent allocation attempts return nil
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
#pragma mark UIAlertViewDelegate Methods
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
switch (alertView.tag) {
case LOCATION_ACCESS_DENIED:
{
if (buttonIndex == 1) {
//[[UIApplication sharedApplication] openURL: [NSURL URLWithString: UIApplicationOpenSettingsURLString]];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"prefs:root=LOCATION_SERVICES"]];
}
}
break;
case LOCATION_NETWORK_ISSUE:
break;
case LOCATION_UNKNOWN_ISSUE:
break;
default:
break;
}
[alertView dismissWithClickedButtonIndex:buttonIndex animated:YES];
}
@end
LocationController.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <Foundation/Foundation.h>
// protocol for sending location updates to another view controller
@protocol LocationControllerDelegate
@required
- (void)locationUpdate:(CLLocation*)location;
- (void)failedToGetLocation:(NSError*)error;
@end
@interface LocationController : NSObject<CLLocationManagerDelegate,UIAlertViewDelegate>
@property (nonatomic, strong) CLLocationManager* locationManager;
@property (nonatomic, strong) CLLocation* currentLocation;
@property (strong, nonatomic) NSMutableArray *locationObservers;
+ (LocationController*)sharedLocationInstance; // Singleton method
- (void) addLocationManagerDelegate:(id<LocationControllerDelegate>) delegate;
- (void) removeLocationManagerDelegate:(id<LocationControllerDelegate>) delegate;
@end
ViewController.m
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(@"VC viewWillAppear");
[locationControllerInstance addLocationManagerDelegate:self];
}
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[LocationController sharedLocationInstance];
}
Upvotes: 0
Views: 1539
Reputation: 2614
I had one of the new devices reported this problem, as you know the the Location Manager usually calls this:
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
The bizarre thing is that the UserLocation object contains two coordinate objects:
1) userLocation.location.coordinate: This used to work fine, but for some reason it's returning NULL on IOS11 on some devices (it's unknown yet why or how this is behaving since IOS11).
2) userLocation.coordinate: This is another (same) object as you can see from the properties, it has the location data and continues to work fine with IOS11, this does not seem to be broken (yet).
So, with the example above, "I guess" that your:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
Might be having the same problem (i.e. the array might be returning a NULL somewhere in the location object, but not the coordinate object, the solution I did on my code which gets one location at a time, is now fixed by by replacing userLocation.location.coordinate with userLocation.coordinate, and the problem gone away.
I also paste my function below to assist you further, hopefully it would help you to resolve yours too, notice that I have two conditions for testing one for sourcing the location object and the other for sourcing the coordinate object, one works fine now, and the other seems to be broken in IOS11:
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
Log (4, @"MapView->DidUpdateUL - IN");
if (_OrderStartTrackingMode == enuUserMapTrackingMode_User)
{
if (userLocation)
{
if (userLocation.location)
{
if ( (userLocation.location.coordinate.latitude) && (userLocation.location.coordinate.longitude))
{
[_mapLocations setCenterCoordinate:userLocation.location.coordinate animated:YES];
} else {
if ( (userLocation.coordinate.latitude) && (userLocation.coordinate.longitude))
{
[self ShowRoutePointsOnMap:userLocation.coordinate];
}
}
}
}
} else if (_OrderStartTrackingMode == enuUserMapTrackingMode_Route) {
if (userLocation)
{
if ( (userLocation.coordinate.latitude) && (userLocation.coordinate.longitude))
{
[self ShowRoutePointsOnMap:userLocation.coordinate];
}
}
}
Log (4, @"MapView->DidUpdateUL - OUT");
}
Needless to say, have you checked your settings for the Map object, you should have at least "User Location" enabled:
P.S. The Log function on the code above is a wrapper to the NSLog function, as I use mine to write to files as well.
Good luck Uma, let me know how it goes.
Regards, Heider
Upvotes: 1