In iOS 8.3 with xCode 6.3.2, when I'm launching Map, it throws the following error:
Trying to start MapKit location updates without prompting for location authorization. Must call -[CLLocationManager requestWhenInUseAuthorization] or -[CLLocationManager requestAlwaysAuthorization] first.
I have done everything and follow every step to launch a map in ios8 app, here is my code for this:
//viewcontroller default function set mapview and a function to find user current location.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[[self otlMapView] setShowsUserLocation:YES];
self.otlMapView.delegate = self;
[self updateUserCurrentLocation];
}
//this function is used to fine the user current location.
-(void)updateUserCurrentLocation
{
// Create a location manager
self.locationManager = [[CLLocationManager alloc] init];
// Set a delegate to receive location callbacks
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)])
{
[self.locationManager requestWhenInUseAuthorization];
}
// Start the location manager
[self.locationManager startUpdatingLocation];
[self.locationManager requestWhenInUseAuthorization];
}
#pragma mark Location Callback Method
// Wait for location callbacks
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(#"Current Location%#", [locations lastObject]);
}
What am I doing wrong?
You should make sure to call
[self.locationManager requestWhenInUseAuthorization];
before calling
[self.locationManager startUpdatingLocation];
Also, have you set up your Info.plist?
I assume you've correctly set up your Info.plist already. Then try something like this:
- (void)viewDidLoad {
[self updateUserCurrentLocation];
}
- (void)updateUserCurrentLocation {
if (nil == locationManager) {
locationManager = [[CLLocationManager alloc] init];
}
locationManager.delegate = self;
// This part was added due to a location authorization issue on iOS8
// See more at: http://nevan.net/2014/09/core-location-manager-changes-in-ios-8/
if ([self._locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[self._locationManager requestWhenInUseAuthorization];
}
self.mapView.showsUserLocation = YES;
[locationManager startUpdatingLocation];
CLLocation *currentLocation = locationManager.location;
if (currentLocation) {
PAWAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
appDelegate.currentLocation = currentLocation;
}
}
Check if you have this key in your info.plist,
"Privacy - Location Usage Description",
if yes remove this and retain the "When in use" key. it should then work.
Related
How to get continuous location details when app is killed/Terminated ? startMonitoringSignificantLocationChanges method firing the didUpdateLocations delegate method after 500 meters. But i want location updates in kill mode for every 10 meters. Or i want to relaunch the application in background automatically and start the location updates in background.Currently i have the working code in background.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {
[[LocationManager sharedLocarionManager] updateAccuracy:YES];
[[LocationManager sharedLocarionManager].locationManager requestAlwaysAuthorization];
[[LocationManager sharedLocarionManager].locationManager stopUpdatingLocation];
[[LocationManager sharedLocarionManager].locationManager startUpdatingLocation];
[[LocationManager sharedLocarionManager].locationManager stopMonitoringSignificantLocationChanges];
[[LocationManager sharedLocarionManager].locationManager startMonitoringSignificantLocationChanges];
}
return YES;
}
LocationManager.m
- (id)init {
self = [super init];
if(self != nil) {
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
self.locationManager.distanceFilter = 100; // meters
self.locationManager.delegate = self;
}
return self;
}
-(void)updateAccuracy:(BOOL)trackingAccuracy {
if (trackingAccuracy) {
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = 10.0 ; // meters
self.locationManager.allowsBackgroundLocationUpdates = YES;
} else {
self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
self.locationManager.distanceFilter = 100; // meters
}
[ self.locationManager startUpdatingLocation];
[self.locationManager startMonitoringSignificantLocationChanges];
}
There is a work around. Though you cannot get continuous location when your app is killed but you can send silent push notification via server to your user to get the update about its location. You will get 30 second window when the app receives silent push notification. In that short time span, you have to perform your task.
How to fetch the location for only one time in ios app.
After getting your location, stop update location manager and also release locationManager because you don't need locationManager anymore.
[self.locationManager stopUpdatingLocation];
self.locationManager.delegate = nil;
self.locationManager = nil;
In ios 9 and above we have a method [locationManagerInstance requestLocation]. But this will take almost ten secs to call back the delegate methods since the location is latest and best.
In another way (for earlier ios9 versions), you could still use the old method [locationManagerInstance startUpdatingLocation] to get the immediate location and also you could validate the timestamp for the best accuracy.
Here is the code that I'm using for getting the location. Create a global reference for locationManager instance.
#interface ViewController ()
{
CLLocationManager *locationManager;
}
Implement these utility methods in your.m file
-(BOOL)canUseLocationManager{
if(([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse) || ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedAlways)){
return YES;
}
return NO;
}
-(void) getCurrentLocation {
locationManager.delegate = self;
// ios 9 and above versions only
//[locationManager requestLocation]; // This may take more time when compare to alternate method
// ios 2 and later versions can use this method
[locationManager startUpdatingLocation];
}
-(void) stopGettingCurrentLocation {
[locationManager stopUpdatingLocation];
}
Implement location service delegates
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{
if([CLLocationManager authorizationStatus] != kCLAuthorizationStatusNotDetermined){
[self doneCheckingAccessStatusForLocation];
}
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
[manager stopUpdatingLocation];
locationManager.delegate = nil;
/* Clean the locationManager instance if you don't need*/
//locationManager = nil;
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
[manager stopUpdatingLocation];
locationManager.delegate = nil;
CLLocation* location = [locations lastObject];
NSDate* eventDate = location.timestamp;
/* Implement your business logics here */
/* Clean the locationManager instance if you don't need*/
//locationManager = nil;
}
Final methods to create the location manager instance and initiate fetching location
-(void)checkForLocationService{
if(!locationManager){
locationManager = [[CLLocationManager alloc] init];
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
}
locationManager.delegate = self;
if([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined){
[locationManager requestWhenInUseAuthorization];
}else{
[self doneCheckingAccessStatusForLocation];
}
}
-(void)doneCheckingAccessStatusForLocation{
if([self canUseLocationManager]){
[self getCurrentLocation];
}
}
call the checkForLocationService method and implement your logics on the success and failure delegate methods.
[self checkForLocationService];
location services within my app are not working the first time you run it. The second time, and any time after that though, it works fine. Here's my code:
- (void)viewDidLoad {
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.allowsBackgroundLocationUpdates = true;
[locationManager requestAlwaysAuthorization];
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedAlways ||
[CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse) {
[locationManager startUpdatingLocation];
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
latitude = locationManager.location.coordinate.latitude;
longitude = locationManager.location.coordinate.longitude;
NSLog(#"New Location. Lat: %f, Long: %f", latitude, longitude);
}
The issue is that requestAlwaysAuthorization runs asynchronously, so your code which checks authorization and calls startUpdatingLocation will execute before authorization has been given by the user. That's why it'll work the second time, because they gave the permission the first time. What you can do is implement locationManager:didChangeAuthorizationStatus: on the delegate and call startUpdatingLocation in there too (if status changed to authorized).
From Apple docs
When the current authorization status is
kCLAuthorizationStatusNotDetermined, this method runs asynchronously
and prompts the user to grant permission to the app to use location
services
I have a simple objective C app with UIWebView. This is loading an URL in viewDidLoad method and I need to localize this URL BEFORE the loadRequest but my CLLocationManager is calling the didUpdateToLocation method AFTER the loadRequest.
My viewDidLoad method:
- (void)viewDidLoad {
// execute super method
[super viewDidLoad];
// put gray background color
self.view.backgroundColor = [UIColor lightGrayColor];
// define itself as UIWebView delegate
self.webView.delegate = self;
// define itself as CLLocationManager delegate
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
NSLog(#"LOCALIZED????%#",[self getCustomURL:homeURL]);
[self.webView loadRequest:[[NSURLRequest alloc] initWithURL:[NSURL URLWithString:[self getCustomURL:homeURL]]]];
}
I'm always getting (null) when calling loadRequest, but just after i'm getting the correct location.
I've tried to separate in a new thread the startUpdatingLocation
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[locationManager startUpdatingLocation];
});
Or waiting till getting a correct location:
while (longitude == nil) {
[locationManager startUpdatingLocation];
}
Any idea how can I get the location before the loadRequest to have the url
CLLocationManager is an async task. To execute the loadRequest after the location, you need to implement the delegate for the CLLocationManager and then call the loadRequest on the webview
You can use loadRequest in method from CLLocationManagerDelegate:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
……
……
[self.webView loadRequest:[[NSURLRequest alloc] initWithURL:[NSURL URLWithString:[self getCustomURL:homeURL]]]];
……
……
}
Also, in iOS8, you need to do couple things to get location:
1) Call requestWhenInUseAuthorization method before startUpdatingLocation:
if ([locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[locationManager requestWhenInUseAuthorization];
}
[locationManager startUpdatingLocation];
2) add NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription key to Info.plist.
I have an app which uses location services.
in my appdelegate i am initializing my location manager property
if(self.locationManager == nil)
{
self.locationManager = [[[CLLocationManager alloc] init] autorelease]; // allocate cllocationmanager property
self.locationManager.delegate = self; // confirm the delegate
[self.locationManager startUpdatingLocation]; // start updating for location
}
and the location manager delegate is made nil in dealloc method
- (void)dealloc
{
[_window release];
[_viewController release];
// [locationManager release];
self.locationManager.delegate = nil;
[super dealloc];
}
the app crashes 1 out of 10 times when i toggle location services from settings
After debugging in instruments , this is the error displayed
Kindly suggest the fix for the same .
create a instance variable if you already haven't that is the same name as your cllocationmanager property and only call self.locationmanager when you are setting as shown here
if (nil == locationManager){
self.locationManager = [[CLLocationManager alloc] init];
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.delegate = self;
[locationManager startUpdatingLocation];
startLocation = nil;
}
this is written for arc so add your autorelease if needed.
You've not told the locationManager to stopUpdatingLocation - Apple docs