cllocationmanager not asking for user permission ios8 - objective-c

Here is my code :
if (!_locationManager)
{
_locationManager = [[CLLocationManager alloc] init];
[_locationManager setDelegate:self];
}
[_locationManager startUpdatingLocation];
please help if someone knows.. Thanks

You need to add a call to requestWhenInUseAuthorization when using location services for iOS-8.0 and above. Find the sample code below.
locationManager = [[CLLocationManager alloc]init];
locationManager.delegate = self;
// this check is required for iOS 8+
// selector 'requestWhenInUseAuthorization' is first introduced in iOS 8
if ([locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[locationManager requestWhenInUseAuthorization];
}
[locationManager startUpdatingLocation];
For more information see this blog.
Hope this helps.

Add [locationManager requestAlwaysAuthorization]; to your code and add the entry NSLocationAlwaysUsageDescription to your .plist with the value being some sort of message that you want to ask the user for their permission.

Related

CLLocationManager updateLocation never called while app is in background

I've read so many question here at stackoverflow and I am still having issues with CLLocationManager.I have already added keys in info.plist (NSLocationAlwaysAndWhenInUseUsageDescription,NSLocationWhenInUseUsageDescription,NSLocationAlwaysAndWhenInUseUsageDescription). My app supports ios 9.0 to 11.x.
Update:- I'm testing on iphone6 ios 11.0.3 physical device
My Approach -
1. Start updating location after while using the app permission.
2. When app goes into background stop location manager to remove Blue Banner (Banner Of Shame)
3.Fire a periodic timer of 30 seconds and start location manager again.
This time I never got the delegate callback didUpdateLocation
I have a singleton class called LocationManager.
Here is my code from LocationManager and AppDelegate
LocationManager
- (void)startLocatingUser {
//Locate User
_locationMeasurements = [NSMutableArray array];
self.geocoder = [[CLGeocoder alloc] init];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.pausesLocationUpdatesAutomatically = NO;
self.locationManager.activityType = CLActivityTypeAutomotiveNavigation;
if ([self.locationManager respondsToSelector:#selector(setAllowsBackgroundLocationUpdates:)]) {
[self.locationManager setAllowsBackgroundLocationUpdates:YES];
}
if(IS_OS_8_OR_LATER) {
if ([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
}
}
if (#available(iOS 11.0, *)) {
self.locationManager.showsBackgroundLocationIndicator = NO;
}
[self.locationManager startUpdatingLocation];
}
- (void)stopLocatingUser {
if(self.locationManager) {
[self.locationManager stopUpdatingLocation];
}
}
AppDelegateCode
- (void)applicationWillResignActive:(UIApplication *)application {
_isBackgroundMode = YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
LocationManager* locationManager = [LocationManager sharedLocationManager];
[locationManager stopLocatingUser];
__block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
self.bgTimer = [NSTimer scheduledTimerWithTimeInterval:30.0
target:self
selector:#selector(startTrackingBg)
userInfo:nil
repeats:YES];
}
-(void)startTrackingBg {
dispatch_async(dispatch_get_main_queue(), ^{
LocationManager* locationManager = [LocationManager sharedLocationManager];
[locationManager startLocatingUser];
});
NSLog(#"App is running in background");
}
I am never getting this delegate callback in background once I stop and start location manager again.
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
What I simply want is whenever user puts the app in background. I want to hide the banner of shame and then I need periodic location updates in background and send them to server.

iOS 8 Error when requesting Authorization

I am having much trouble trying with requesting the location services authorization. I know there are other posts on this forum, but I did not solve my problem with their solution.
This is the error popping up in xCode:
Trying to start MapKit location updates without prompting for location authorization. Must call -[CLLocationManager requestWhenInUseAuthorization] or -[CLLocationManager requestAlwaysAuthorization] first.
I have added both the required keys for the Plist.
Another important point is that when I start it in the simulator, I can go into the setting manually and enable location services and then the App does work. However, when I restart the App it does not work and I get the same message above.
I want to prompt the user with the option to enable location services.
Unfortunately, this code does not prompt the authorization for location services.
Please help I have been pulling my hair out for hours.
1
- (void)viewDidLoad {
[super viewDidLoad];
self.locationManager = [[CLLocationManager alloc]init];
self.locationManager.delegate = self;
if ([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)])
{
[self.locationManager requestAlwaysAuthorization];
}
[self.locationManager startUpdatingLocation];
//Initialize the map and specifiy bounds
self.myMapView =[[MKMapView alloc]initWithFrame:self.view.bounds];
//specifcy resizing
self.myMapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
//show the User's location and set tracking mode
self.myMapView.showsUserLocation = YES;
self.myMapView.userTrackingMode = MKUserTrackingModeFollow;
//add the VIEW!!
[self.view addSubview:self.myMapView];
}
And here is the Function I want to call
- (void)requestAlwaysAuthorization
{
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
// If the status is denied or only granted for when in use, display an alert
if (status == kCLAuthorizationStatusAuthorizedWhenInUse || status == kCLAuthorizationStatusDenied) {
NSString *title;
title = (status == kCLAuthorizationStatusDenied) ? #"Location services are off" : #"Background location is not enabled";
NSString *message = #"To use background location you must turn on 'Always' in the Location Services Settings";
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title
message:message
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Settings", nil];
[alertView show];
}
// The user has not enabled any location services. Request background authorization.
else if (status == kCLAuthorizationStatusNotDetermined) {
[self.locationManager requestAlwaysAuthorization];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1) {
// Send the user to the Settings for this app
NSURL *settingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
[[UIApplication sharedApplication] openURL:settingsURL];
}
}
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
This is the delegate method about location service
You can get your AuthorizationStatus from status.Such as kCLAuthorizationStatusDenied
You simply call
[self.locationManager requestAlwaysAuthorization];in viewdid load,and monitor AuthorizationStatus in delegate method above,if user deny your location service,show a alertview

CLLocationManager not getting current location all the times

In my iOS 7 app, I have to get current location every time the app launches. I have kept the
following code.
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
[locationManager startUpdatingLocation];
I have Added CLLocationManagerDelegate in .h I am getting current location in this delegate
method but not all the times.
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
What could be the problem? Why some times this delegate method was not called? Any suggestions will be appreciated. Thank you

Can we show user location in offline in MKMapview

Can we get current user location "That blue ball which is animating" when our device is offline.when i tried to get current user location and log it i'm getting 0.00000 for both longitude and latitude here is the code that i used to get current user location.I'm using ipad mini to test it.I have also added CLLocationManagerDelegate in .h file.
- (void)viewDidLoad {
[self getUserLocation];
self.myMapView.showsUserLocation = YES;
}
-(void)getUserLocation{
if ([CLLocationManager locationServicesEnabled]) {
locationManager = [[[CLLocationManager alloc] init] autorelease];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
[locationManager startUpdatingLocation];
}else{
NSLog(#"User location Disabled");
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
CLLocation *currentGPSLocation = newLocation;
if (currentGPSLocation != nil) {
currentLocation.latitude = self.myMapView.userLocation.coordinate.latitude;
currentLocation.longitude = self.myMapView.userLocation.coordinate.longitude;
currentLocationWalk.latitude=self.myMapView.userLocation.coordinate.latitude;
currentLocationWalk.longitude=self.myMapView.userLocation.coordinate.longitude;
NSLog(#"didUpdateToLocation: %f,%f", self.myMapView.userLocation.coordinate.latitude,self.myMapView.userLocation.coordinate.longitude);
statusLabel.textColor = [UIColor blackColor];
statusLabel.text = [NSString stringWithFormat:#"%f",self.myMapView.userLocation.coordinate.latitude];
statusLabel1.text = [NSString stringWithFormat:#"%f",self.myMapView.userLocation.coordinate.longitude];
}
}
You are not using ARC (I strongly suggest using it, it avoid most of the memory management errors!).
Therefore it might be that "locationManager" is a instance variable that is not retained (maybe you did not declare it as a retained property).
In this case, it might have been released already when your code returns to the main run loop, where the autorelease pool is drained.
This line
locationManager = [[[CLLocationManager alloc] init] autorelease];
is not a good idea.
define the locationManager as a property,
init the locationManager in viewDidLoad(), but remove the autorelease!
and relase the locationManager only when the viewController is unloaded (there where you release the other properties)

didUpdateToLocation called multiple

i have an iOS application witch uses the current location of the user. I am doing like this :
-(void)startGeoloc{
NSLog(#"start geoloc");
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy=kCLLocationAccuracyHundredMeters;
[locationManager startUpdatingLocation];
}
#pragma mark - CLLocationManagerDelegate methods
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
[locationManager stopUpdatingLocation];
AppDelegate *apDelegate =(AppDelegate *)[UIApplication sharedApplication].delegate;
apDelegate.modeGeoloc = YES;
[self callWebService:locationManager.location];
}
The problem of this, is that my method callWebService:locationManager.location is called twice and i would like to call it just one time. how i can i do this ? thanks for your answers
To ensure locationManager only calls the "didUpdate..." method once, use a BOOL to reference if the location has been found yet.
Create the ivar BOOL:
#property BOOL didFindLocation;
Before locationManager startUpdatingLocation, set the new BOOL to NO. That way you can call for a new location update at will.
-(void) startFindingLocation {
self.didFindLocation = NO; // like this
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self]
[locationManager setDesiredAccuracy:kCLLocationAccuracyHundredMeters];
[locationManager startUpdatingLocation];
}
In "didUpdateLocations", check for it.
- (void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
if (!self.didFindLocation) {
self.didFindLocation = YES;
[locationManager stopUpdatingLocation];
// do the rest of your stuff
}
}
If possible, do not set didFindLocation anywhere else in your code to avoid confusion.
locationManager delegate methods can be called very frequently (they didUpdateToLocation all the time, right? :)
One way would be to have your callWebService have state, know whether it is currently executing a request and ignore concurrent requests if one is still going. Another way would be to keep a timestamp and only allow it through if 2 minutes has passed since the previous one.
Had the same problem.
I think the easiest solution is setting the CLLocationManager to null.
locationManager = nil;
after calling
[locationManager stopUpdatingLocation];
locationManager.startUpdatingLocation() fetch location continuously and didUpdateLocations method calls several times,
Just set the value for locationManager.distanceFilter value before calling locationManager.startUpdatingLocation().
As I set 100 meters(you can change as your requirement) working fine, and will work for you.
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = 100
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()