0

How can I get permission from the user to access location service from a non UI class (iOS 8 and above)? No matter what I do - requestWhenInUseAuthorization doesn't alert the user. I'm using objective c.

I have added the key in the plist file as well.

LocationController.h

@interface LocationController : NSObject <CLLocationManagerDelegate>{
    BOOL _debug;
}

@property (strong, nonatomic) CLLocationManager *locationManager;

@property (strong, nonatomic) CLLocation *location;

- (id)initWithDebug:(BOOL)debug_flag;

@end

LocationController.m

@implementation LocationController  {
}

@synthesize debug, locationManager, location;

#define IOS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)

- (id)initWithDebug:(BOOL)debug_flag {
    self = [super init];
   if (self) {
    [self findLocation];
   }
   return self;
}


-(void) findLocation{
    self.locationManager = [[CLLocationManager  alloc] init];
    self.locationManager.delegate = self;
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    self.locationManager.distanceFilter = kCLDistanceFilterNone;
    [self checkLocationPermissions];
    self.location = self.locationManager.location;
}

-(void)checkLocationPermissions {
    if ([CLLocationManager locationServicesEnabled]) {
        if (IOS_8_OR_LATER) {
            [self.locationManager requestWhenInUseAuthorization];
        } else {
            [self.locationManager startUpdatingLocation];
        }
    }
}

#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager*)manager    didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    switch (status) {
        case kCLAuthorizationStatusNotDetermined: {
            [self.locationManager startUpdatingLocation];
        } break;
        case kCLAuthorizationStatusDenied: {
            [self.locationManager stopUpdatingLocation];
        } break;
        case kCLAuthorizationStatusAuthorizedWhenInUse:
        case kCLAuthorizationStatusAuthorizedAlways: {
            [self.locationManager startUpdatingLocation];
        } break;
        default:
            break;
    }
}

@end

EDIT: The code reaches till [self.locationManager requestWhenInUseAuthorization]; but never shows the alert.

This code is called from a blockOperation in a SDK. The SDK is initialised as singleton

armor--
  • 45
  • 8

3 Answers3

0

Apparently in iOS 8 SDK, requestAlwaysAuthorization (for background location) or requestWhenInUseAuthorization (location only when foreground) call on CLLocationManager is needed before starting location updates.

There also needs to be NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription key in Info.plist with a message to be displayed in the prompt. Adding these solved my problem.

try this one

    #define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)

   //In ViewDidLoad
   if(IS_OS_8_OR_LATER) {
         [self.locationManager requestAlwaysAuthorization];
   }

   [self.locationManager startUpdatingLocation];

More detail refer this link -----> http://nevan.net/2014/09/core-location-manager-changes-in-ios-8/

Vijay Kachhadiya
  • 366
  • 2
  • 11
  • I have everything in place. It is just that I am not using this code in a UIViewController class, rest everything I have added as required. I don't see the alert at all :( – armor-- May 20 '16 at 05:28
  • did you refer this link ---> http://nevan.net/2014/09/core-location-manager-changes-in-ios-8/ – Vijay Kachhadiya May 20 '16 at 05:41
  • yes I did.. I will post the code in a couple of mins – armor-- May 20 '16 at 05:45
  • I have updated the code. I call LocationController from a ViewController class – armor-- May 20 '16 at 05:53
  • please replace this in find location method locationManager = [[CLLocationManager alloc] init]; locationManager.delegate = self; locationManager.distanceFilter = kCLDistanceFilterNone; //whenever we move locationManager.desiredAccuracy = kCLLocationAccuracyBest; [locationManager startUpdatingLocation]; [locationManager requestWhenInUseAuthorization]; // Add This Line – Vijay Kachhadiya May 20 '16 at 05:58
  • delete your app in simulator or iphone and run again – Vijay Kachhadiya May 20 '16 at 06:07
  • I also have this in my plist file. NSLocationWhenInUseUsageDescription test – armor-- May 20 '16 at 06:19
  • can you please check it on iphone? – Vijay Kachhadiya May 20 '16 at 06:21
  • This code is being used in an objective c library and not in an app directly. I am sorry but I forgot to mention it. – armor-- May 20 '16 at 06:25
0

Add this in your .m file:

 #define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)


#import "ViewController.h"
 @interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];




// Do any additional setup after loading the view, typically from a nib.



self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;

#ifdef __IPHONE_8_0

if(IS_OS_8_OR_LATER) {
    // Use one or the other, not both. Depending on what you put in info.plist
    [self.locationManager requestWhenInUseAuthorization];
    [self.locationManager requestAlwaysAuthorization];
}

#endif [self.locationManager startUpdatingLocation];

NSLog(@"latitude: %f, longitude: %f",self.locationManager.location.coordinate.latitude,self.locationManager.location.coordinate.longitude);

}

Suraj Sukale
  • 1,778
  • 1
  • 12
  • 19
  • @armor--...please check your info.plist once... and confirm that you add NSLocationWhenInUseUsageDescription or NSLocationAlwaysAuthorization in that..? – Suraj Sukale May 20 '16 at 09:37
  • I have NSLocationWhenInUseUsageDescription in my SDK plist file – armor-- May 20 '16 at 09:38
  • I am not facing any error. I just don't get the alert. – armor-- May 20 '16 at 09:42
  • check my updated answer bro..... add #define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) this in your .m file – Suraj Sukale May 20 '16 at 09:48
  • The problem is not with the code that I posted as this code works fine if I add it directly to an app. – armor-- May 20 '16 at 10:03
  • did you check it after adding #define IS_OS_8_OR_LATER([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) this line above in your .m file..?....coz this is working fine for me bro – Suraj Sukale May 20 '16 at 10:06
  • I already have that line. The code reaches till [self.locationManager requestWhenInUseAuthorization]; but never shows the alert. – armor-- May 20 '16 at 17:43
0

Add framework to your project and import to your viewcontroller: CoreLocation.framework

Add this delegate to you viewcontroller: CLLocationManagerDelegate

Add key-value in .plist file: NSLocationWhenInUseUsageDescription : "Your message"

EDIT

+ (YourNSObjectClasssName*)sharedInstance {

    @synchronized(self) {
        if (location == nil) {
            location = [[super allocWithZone:NULL] init] ;
        }
    }
    return location;
}

- (id)init
{
    self = [super init];
    if (self) {}
    return self;
}

#pragma mark - Start Location Updates

-(void)startLocationUpdate{

    CLLocationManager *locationManager = [[CLLocationManager alloc]init];
    locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
    locationManager.delegate = self;
    locationManager.distanceFilter = 10.0f;

    if(![CLLocationManager locationServicesEnabled] ||
       [CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied){

        UIAlertView* failedStatus=[[UIAlertView alloc]initWithTitle:APP_NAME
                                                            message:@"Would like to Use your location Please Enable Location Service in Setting"
                                                           delegate:self
                                                  cancelButtonTitle:@"Setting"
                                                  otherButtonTitles:@"Cancel", nil];
        [failedStatus show];
    }
    else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
        [locationManager requestWhenInUseAuthorization];
    }
    else{
        [locationManager startUpdatingLocation];
        [locationManager startMonitoringSignificantLocationChanges];
    }
}

And this how you will call startUpdate function from another classes

[[LocationTracker sharedInstance] startLocationUpdate];

Here I am not adding condition for < iOS 8.0. For that you can refer Vijay's answer. (Here distanceFilter = 10.0 is updating location if user moves more than 10 meters.)

If this code still not work then try below case:

  • Delete your application from iPhone and restart your device.
  • Change your iPhone date and date different should be more than 24 hours and again restart your iPhone.
  • Run your app It will ask you for permission.

Main reason behind this is apple will ask for any permission to access users privacy is more than 24 hours.

Hope this might help you.

Ajay Gabani
  • 1,168
  • 22
  • 38
  • I am working on a SDK which wants to get the location details. The SDK LocationController class is of type NSObject. I do not have a ViewController in the SDK – armor-- May 20 '16 at 09:20
  • I am also using NSObject class and I done all this thing in this class only. Do one thing, create one shared instance method and call your location update based on that. I am updating answer please check it. – Ajay Gabani May 20 '16 at 09:39
  • Don't forget to add delagate method to update location. :) And to stop location update, you can create method and can call same as startUpdate method. – Ajay Gabani May 20 '16 at 09:44
  • @armor-- Is this solution helpful to you? – Ajay Gabani May 20 '16 at 11:19
  • it is not working. I did not understand that why you are initializing location in the sharedInstance – armor-- May 20 '16 at 16:42