[iOS][Background][CLLocationManager]Bad map accuracy - ios

I am working on an application which aims to display on a map the position of the iPhone during an activity (adding annotations and drawing line between them).
To do this, I use a Location Manager which get new positions and notify the MapDisplayViewController. When using with the simulator I got good results as you can see here http://www.youtube.com/watch?v=ESLIYSU_Mqw but with an iPhone I got weird result such 200 meters wrong.
I also use a MKMapView to display the device position. with these settings (next code block) I got that http://grab.by/mgUU.
If I show the user location I got different results, it is normal ?
- (void)setupMap {
self.mapView.delegate = self;
[self.mapView setUserTrackingMode:MKUserTrackingModeFollow animated:YES];
[self.mapView setUserInteractionEnabled:NO];
[self.mapView setShowsUserLocation:NO];
[self.mapView setZoomEnabled:NO];
[self.waitingView start];
}
Here screenshots with a real device:
background: http://grab.by/mgN2
no background: http://grab.by/mgNc
edit: the difference come froms I used for these 2 cases, 2 different ways of getting current location of the device are used:
the handle from the mapView when the app is active
the handle from the Location Manager when the app is in background
Does it a good idea to mix both locations system ?
I also test this solution CLLocationManager and accuracy issues - any experiences? but I got the same result.
Thanks ;)
Setup of Location Manager:
- (void)setup {
self.locationManager = [CLLocationManager new];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.isUpdatingLocation = NO;
}
Notification: when adding location in background:
- (void)doUpdateWithLocation:(CLLocation *)location {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self beginBackgroundUpdateTask];
NSLog(#"%s do update in background %#", __PRETTY_FUNCTION__, location);
if (self.userLocationFound == NO && self.isUpdatingLocation == YES) {
self.startCoordinate = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude);
self.userLocationFound = YES;
}
else if (self.isUpdatingLocation) {
static int distance;
ABGPSPosition *position = [[ABGPSPosition alloc] init];
position.startPoint = MKMapPointForCoordinate(self.startCoordinate);
position.endPoint = MKMapPointForCoordinate(location.coordinate);
//INFO: Get the distance between this new point and the previous point.
CLLocationDistance metersApart = MKMetersBetweenMapPoints(position.startPoint, position.endPoint);
if (metersApart > MINIMUM_DELTA_METERS) {
MKMapPoint points[2] = {position.startPoint, position.endPoint};
distance += metersApart;
NSLog(#"%s - %d", __PRETTY_FUNCTION__, distance);
NSInteger count = [self.measurementArray count];
[self willChange:NSKeyValueChangeInsertion
valuesAtIndexes:[NSIndexSet indexSetWithIndex:count] forKey: #"measurementArray"];
[self.measurementArray insertObject:location atIndex:count];
[self didChange:NSKeyValueChangeInsertion
valuesAtIndexes:[NSIndexSet indexSetWithIndex:count] forKey: #"measurementArray"];
self.startCoordinate = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude);
}
}
[self endBackgroundUpdateTask];
});
}
MapDisplayViewController get the new location:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:keyPathMeasurementArray]) {
if ([change[NSKeyValueChangeKindKey] intValue] == NSKeyValueChangeInsertion) {
NSIndexSet *insertedIndexSet = change[NSKeyValueChangeIndexesKey];
[insertedIndexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
CLLocation *location = self.locationManager.measurementArray[idx];
MKUserLocation *userLocation = [[MKUserLocation alloc] init];
[userLocation setCoordinate:location.coordinate];
NSLog(#"%s - didUpdateUserLocation", __PRETTY_FUNCTION__);
[self.locationBackgroundList addObject:userLocation];
NSLog(#"%s | %#", __PRETTY_FUNCTION__, self.locationBackgroundList);
}];
}
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
MapDisplayViewController adding Annotation the new map view:
- (void)handleAddLocations {
NSLog(#"%s | %#", __PRETTY_FUNCTION__, self.locationBackgroundList);
if ([self.locationBackgroundList count] > 0) {
for (MKUserLocation *backgroundUserLocation in self.locationBackgroundList) {
{
LocAnnotation* annotation = [[LocAnnotation alloc] initWithCoordinate:backgroundUserLocation.coordinate];
NSLog(#"%s %#", __PRETTY_FUNCTION__, [backgroundUserLocation description]);
[self.mapView addAnnotation:annotation];
}
[self mapView:self.mapView didUpdateUserLocation:backgroundUserLocation];
}
NSString *message = [NSString stringWithFormat:#"%s | Annotation number: %d", __PRETTY_FUNCTION__, [self.locationBackgroundList count]];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Debug" message:message delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil];
[alert show];
[self.locationBackgroundList removeAllObjects];
self.locationBackgroundList = [[NSMutableArray alloc] init];
}
}

Fixed you have to use only one way to locate your device with the CLLocationManager or the MapView. ;)

Related

Google place picker interrupts the background location updates in iPhone

I'm developing a location-based mobile application. My app updates the server with user's current location even when the app is killed/terminated. My app was working fine before integrating google place picker API. After installing google place picker API for ios, my app updates the location for about 5 to 10 minutes only and then it stops updating location.
//My code :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Initialize Location Manager
sLocationManager;
//the system automatically relaunches the application into the background if a new event arrives.
// The options dictionary passed to the application:didFinishLaunchingWithOptions: method of your application delegate contains the key UIApplicationLaunchOptionsLocationKey to indicate that your application was launched because of a location event
if (launchOptions[UIApplicationLaunchOptionsLocationKey]) {
NSLog(#"---UIApplicationLaunchOptionsLocationKey");
sLocationManager.locationUpdatedInBackground = ^(NSArray<CLLocation *> *locations) {
NSLog(#"---setLocationUpdatedInBackground");
[sLocationModule saveNewLocations];
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:300];
notification.alertBody = #"Your location was changed. Please run application for tracking your geoposition with best accuracy.";
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
[sLocationManager startMonitoringSignificantLocationChanges];
};
}else {
sLocationManager.locationUpdatedInForeground = ^(NSArray<CLLocation *> *locations) {
NSLog(#"---setLocationUpdatedInForeground");
[sLocationModule saveNewLocations];
};
sLocationManager.locationUpdatedInBackground = ^(NSArray<CLLocation *> *locations) {
NSLog(#"---setLocationUpdatedInBackground");
[sLocationModule saveNewLocations];
[sLocationManager startDeferredLocationUpdates];
};
// Notifications
[application cancelAllLocalNotifications];
}
return YES;
//location manager
#pragma mark - CLLocationManager Delegate
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)aLocations {
NSString *infoMessage = [NSString stringWithFormat:#"%#", aLocations];
NSLog(#"%#", infoMessage);
locations = [#[] mutableCopy];
NSLog(#"locations=%#",locations);
[aLocations enumerateObjectsUsingBlock:^(CLLocation * _Nonnull location, NSUInteger idx, BOOL * _Nonnull stop) {
// Check for location errors (speed -1.00 mps / course -1.00)
// if (location.speed >= 0 &&
// location.course >= 0) {
if (locations.count > 0) {
if ([location.timestamp timeIntervalSinceDate:[locations lastObject].timestamp] > dLocationManagerDistanceFilter ||
[location distanceFromLocation:[locations lastObject]] > dLocationUpdatesUntilTimeout) {
[locations addObject:location];
NSLog(#"location.timestamp>dLocationManagerDistanceFilter**** locations=%#",locations);
}
} else
[locations addObject:location];
NSLog(#"else***locations=%#",locations);
//save location in userdefaults
NSString *latitudeValue = [NSString stringWithFormat:#"%f", location.coordinate.latitude];
NSString *longitudeValue = [NSString stringWithFormat:#"%f",location.coordinate.longitude];
NSLog(#"new location is recieved Lat : %# Long : %#",latitudeValue,longitudeValue);
[User setUserLat:latitudeValue];
[User setUserLon:longitudeValue];
// }
}];
if ([self isInBackground]) {
NSLog(#"app is in background***");
if (self.locationUpdatedInBackground) {
backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler: ^{
[[UIApplication sharedApplication] endBackgroundTask:backgroundTaskIdentifier];
}];
self.locationUpdatedInBackground(locations);
[delegate locationManagerDidUpdateLocationInBackground];
[[NSNotificationCenter defaultCenter] postNotificationName:nLocationManagerDidUpdateLocationInBackgroundNotification
object:nil
userInfo:nil];
[self endBackgroundTask];
}
} else {
if (self.locationUpdatedInForeground) {
if([[NSUserDefaults standardUserDefaults]objectForKey:#"userIdKey"]){
self.locationUpdatedInForeground(locations);
[delegate locationManagerDidUpdateLocationInForeground];
[[NSNotificationCenter defaultCenter] postNotificationName:nLocationManagerDidUpdateLocationInForegroundNotification
object:nil
userInfo:nil];
}
}
}
}
code for adding place picker
#pragma mark - Place picker delegate methods
- (IBAction)pickPlace:(id)sender {
//dismiss the keyboard
[tfLocation resignFirstResponder];
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(locationManager.location.coordinate.latitude, locationManager.location.coordinate.longitude);
CLLocationCoordinate2D northEast = CLLocationCoordinate2DMake(center.latitude + 0.001, center.longitude + 0.001);
CLLocationCoordinate2D southWest = CLLocationCoordinate2DMake(center.latitude - 0.001, center.longitude - 0.001);
GMSCoordinateBounds *viewport = [[GMSCoordinateBounds alloc] initWithCoordinate:northEast
coordinate:southWest];
GMSPlacePickerConfig *config = [[GMSPlacePickerConfig alloc] initWithViewport:viewport];
_placePicker = [[GMSPlacePicker alloc] initWithConfig:config];
[_placePicker pickPlaceWithCallback:^(GMSPlace *place, NSError *error) {
if (error != nil) {
NSLog(#"Pick Place error %#", [error localizedDescription]);
return;
}
if (place != nil) {
NSLog(#"Place name %#", place.name);
NSLog(#"Place address %#", place.formattedAddress);
NSLog(#"Place attributions %#", place.attributions.string);
// NSString *latitudeValue = [NSString stringWithFormat:#"%f", locationManager.location.coordinate.latitude];
// NSString *longitudeValue = [NSString stringWithFormat:#"%f",locationManager.location.coordinate.longitude];
tfLocation.text=place.formattedAddress;
locationPoint=[NSString stringWithFormat:#"%f,%f", place.coordinate.latitude,place.coordinate.longitude];
} else {
NSLog(#"No place selected");
}
}];
}
// Add a UIButton in Interface Builder, and connect the action to this function.
- (IBAction)getCurrentPlace:(UIButton *)sender {
[_placesClient currentPlaceWithCallback:^(GMSPlaceLikelihoodList *placeLikelihoodList, NSError *error){
if (error != nil) {
NSLog(#"Pick Place error %#", [error localizedDescription]);
return;
}
self.nameLabel.text = #"No current place";
self.addressLabel.text = #"";
if (placeLikelihoodList != nil) {
GMSPlace *place = [[[placeLikelihoodList likelihoods] firstObject] place];
if (place != nil) {
self.nameLabel.text = place.name;
self.addressLabel.text = [[place.formattedAddress componentsSeparatedByString:#", "]
componentsJoinedByString:#"\n"];
}
}
}];
}
// Present the autocomplete view controller when the button is pressed.
- (IBAction)onLaunchClicked:(id)sender {
GMSAutocompleteViewController *acController = [[GMSAutocompleteViewController alloc] init];
acController.delegate = self;
[self presentViewController:acController animated:YES completion:nil];
}
// Handle the user's selection.
- (void)viewController:(GMSAutocompleteViewController *)viewController
didAutocompleteWithPlace:(GMSPlace *)place {
[self dismissViewControllerAnimated:YES completion:nil];
// Do something with the selected place.
NSLog(#"Place name %#", place.name);
NSLog(#"Place address %#", place.formattedAddress);
NSLog(#"Place attributions %#", place.attributions.string);
}
- (void)viewController:(GMSAutocompleteViewController *)viewController
didFailAutocompleteWithError:(NSError *)error {
[self dismissViewControllerAnimated:YES completion:nil];
// TODO: handle the error.
NSLog(#"Error: %#", [error description]);
}
// User canceled the operation.
- (void)wasCancelled:(GMSAutocompleteViewController *)viewController {
[self dismissViewControllerAnimated:YES completion:nil];
}
// Turn the network activity indicator on and off again.
- (void)didRequestAutocompletePredictions:(GMSAutocompleteViewController *)viewController {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}
- (void)didUpdateAutocompletePredictions:(GMSAutocompleteViewController *)viewController {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
Can anyone tell, what am I doing wrong here? What is the best to use place picker without affecting background location updates or is there any other way to pick place/location just like google place picker in ios?
Please help me out or tell me the other solution.
thank you!

Unable to detect ibeacon on iphone 6

Hi i have below code which works fine on iPod touch 5, but same code is not working on iPhone 6, i done research on same issue but i have not found anything useful. both devices have latest iOS.
Both devices have iOS 8
// MapViewController.m
// SidebarDemo
//
// Created by Simon on 30/6/13.
// Copyright (c) 2013 Appcoda. All rights reserved.
//
#import "PetFinderViewController.h"
#import "SWRevealViewController.h"
#interface PetFinderViewController ()
#end
#implementation PetFinderViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithRed:(51/255.0) green:(51/255.0) blue:(51/255.0) alpha:1] ;
self.title = #"Pet Finder";
// Change button color
//_sidebarButton.tintColor = [UIColor colorWithWhite:0.96f alpha:0.2f];
// Set the side bar button action. When it's tapped, it'll show up the sidebar.
_sidebarButton.target = self.revealViewController;
_sidebarButton.action = #selector(revealToggle:);
// Set the gesture
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
// Check if beacon monitoring is available for this device
if (![CLLocationManager isMonitoringAvailableForClass:[CLBeaconRegion class]]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Monitoring not available" message:nil delegate:nil cancelButtonTitle:#"OK" otherButtonTitles: nil]; [alert show]; return;
}
else
{
// Initialize location manager and set ourselves as the delegate
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
// Create a NSUUID
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:#"ebefd083-70a2-47c8-9837-e7b5634df524"];
// Setup a new region AND start monitoring
str_beaconIdentifier = #"in.appstute.marketing";
self.myBeaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid major:1 minor:1 identifier:str_beaconIdentifier];
self.myBeaconRegion.notifyEntryStateOnDisplay = YES;
self.myBeaconRegion.notifyOnEntry = YES;
self.myBeaconRegion.notifyOnExit = YES;
[self.locationManager startMonitoringForRegion:self.myBeaconRegion];
self.lbl_rangeStatus.text = #"Finding Your Pet";
self.lbl_regionStatus.text = #"";
self.lbl_distance.text = #"";
}
}
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
if (![CLLocationManager locationServicesEnabled]) {
NSLog(#"Couldn't turn on ranging: Location services are not enabled.");
}
if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorized) {
NSLog(#"Couldn't turn on monitoring: Location services not authorised.");
[self.locationManager requestAlwaysAuthorization];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Core Location Delegate methods
- (void)locationManager:(CLLocationManager*)manager didEnterRegion:(CLRegion *)region
{
UILocalNotification *notify = [[UILocalNotification alloc] init];
notify.alertBody = #"You are near your Pet's region.";
notify.soundName = UILocalNotificationDefaultSoundName;
[[UIApplication sharedApplication] presentLocalNotificationNow:notify];
// We entered a region, now start looking for our target beacons!
//self.statusLabel.text = #"Finding beacons.";
self.lbl_rangeStatus.text = #"Pet Found";
self.lbl_regionStatus.text = #"Status : Entered Region";
[self.locationManager startRangingBeaconsInRegion:self.myBeaconRegion];
//Opening camera
/*if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
UIImagePickerController *imagePicker = [[UIImagePickerController alloc]init];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePicker.allowsEditing = YES;
//[self presentModalViewController:imagePicker animated:YES];
[self presentViewController:imagePicker animated:YES completion:nil];
}
else
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Camera Unavailable"
message:#"Unable to find a camera on your device."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[alert show];
alert = nil;
}*/
}
-(void)locationManager:(CLLocationManager*)manager didExitRegion:(CLRegion *)region
{
UILocalNotification *notify = [[UILocalNotification alloc] init];
notify.alertBody = #"You are far away from your Pet's region.";
notify.soundName = UILocalNotificationDefaultSoundName;
[[UIApplication sharedApplication] presentLocalNotificationNow:notify];
// Exited the region
//self.statusLabel.text = #"None found.";
self.lbl_rangeStatus.text = #"Pet Not Found";
self.lbl_regionStatus.text = #"Status : Exited Region";
[self.locationManager stopRangingBeaconsInRegion:self.myBeaconRegion];
}
-(void)locationManager:(CLLocationManager*)manager didRangeBeacons:(NSArray*)beacons inRegion:(CLBeaconRegion*)region
{
CLBeacon *foundBeacon = [beacons firstObject];
// Retrieve the beacon data from its properties
NSString *uuid = foundBeacon.proximityUUID.UUIDString;
NSString *major = [NSString stringWithFormat:#"%#", foundBeacon.major];
NSString *minor = [NSString stringWithFormat:#"%#", foundBeacon.minor];
NSLog(#"uuid=%#, major=%#, minor=%#",uuid, major, minor);
self.lbl_regionStatus.text = #"Status : Entered Region";
if(foundBeacon.proximity==CLProximityImmediate)
{
NSLog(#"Immediate");
//self.Lb_proxomity.text = #"Immediate";
}
else if (foundBeacon.proximity==CLProximityNear)
{
NSLog(#"Near");
//self.Lb_proxomity.text = #"Near";
}
else if(foundBeacon.proximity==CLProximityFar)
{
NSLog(#"Far");
//self.Lb_proxomity.text = #"Far";
}
else if(foundBeacon.proximity==CLProximityUnknown)
{
NSLog(#"Unknown");
//self.Lb_proxomity.text = #"Unknown";
}
float actualDistance = foundBeacon.accuracy/10;
NSLog(#"Distance = %f",actualDistance);
if(actualDistance >= 0.0)
{
self.lbl_distance.text = [NSString stringWithFormat:#"Distance : %.2f m",actualDistance];
}
//self.Lb_meter.text = [NSString stringWithFormat:#"%.2f",foundBeacon.accuracy];
//self.Lb_centimeter.text = [NSString stringWithFormat:#"%.2f",(foundBeacon.accuracy*100)];
//[self presentExhibitInfoWithMajorValue:foundBeacon.major.integerValue];
//Calling this method to display strength for distance between user and the pet
[self fn_showStrengthForDistanceBetweenUserAndPet:actualDistance];
}
#pragma mark - Check Background App Refresh status
-(BOOL)CanDeviceSupportAppBackgroundRefresh
{
// Override point for customization after application launch.
if ([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusAvailable) {
NSLog(#"Background updates are available for the app.");
return YES;
}else if([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusDenied)
{
NSLog(#"The user explicitly disabled background behavior for this app or for the whole system.");
return NO;
}else if([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusRestricted)
{
NSLog(#"Background updates are unavailable and the user cannot enable them again. For example, this status can occur when parental controls are in effect for the current user.");
return NO;
}
return NO;
}
#pragma mark - Check if monitoring region failed
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error
{
NSLog(#"monitoringDidFailForRegion - error: %#", [error localizedDescription]);
}
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLBeaconRegion *)region{
if (state == CLRegionStateInside) {
//Start Ranging
[manager startRangingBeaconsInRegion:region];
}
else{
//Stop Ranging
[manager stopRangingBeaconsInRegion:region];
}
}
#end
I suspect you are having authorization issues on your iPhone. Set a breakpoint or add NSLog statements to make sure this line is getting called:
[self.locationManager requestAlwaysAuthorization];
Do you get prompted? If not, uninstall and reinstall.
Also, check in setting that Bluetooth and Location services are enabled on the phone, and check settings on your app to see that location services are actually enabled for it.
You need to set one of
NSLocationAlwaysUsageDescription
or
NSLocationWhenInUseUsageDescription when requesting location updates (even with iBeacons).
If you don't, in iOS 8, this will fail silently.

iOS Map Marker and current location not showing

I have a MapViewController that imports SWRevealViewController and I honestly didn't code this lines below. I tried to run the app but unfortunately the map is not showing the current location and even the location service does not get turn on the phone even the app is granted permission to access GPS. Since i'm not a expect in iOS development I need someone to look the code and explain what is missing in this code. I looked at similar question but they seem straight forward even for someone learning objective-c. The problem with this code i assume is the SWRevealViewController imported here, which I think is a library or something i don't know.
#import "MapViewController.h"
#import "SWRevealViewController.h"
// New York
#define NY_LATITUDE 40.754445
#define NY_LONGITUDE -73.977364
// Span and distance
#define SPAN_VALUE 1.0f
#define DISTANCE 500
#interface MapViewController ()
- (void)startLocationServices;
- (void)stopLocationServices;
#end
#implementation MapViewController
#synthesize locationManager;
#synthesize gpsDisplay;
#synthesize mapk;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (IBAction)sendRequest:(id)sender {
[self alertStatus:#"An assistance request has been sent, you will be contacted shortly." :#"Send assistance request" :0];
[self performSegueWithIdentifier:#"sendRequest" sender:nil];
}
- (void) alertStatus:(NSString *)msg :(NSString *)title :(int) tag
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title
message:msg
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil, nil];
alertView.tag = tag;
[alertView show];
}
-(void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex: (NSInteger)buttonIndex
{
if(buttonIndex==0)
{
//NSLog(#"OK Clicked");
// [self alertStatus:#"An assistance request has been sent, you will be contacted shortly. " :#"I just had an accident" :0];
// [self performSegueWithIdentifier:#"checkProgress" sender:nil];
}}
- (void)viewDidLoad
{
[super viewDidLoad];
[self startLocationServices];
if ([CLLocationManager locationServicesEnabled]) {
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self.locationManager startUpdatingLocation];
} else {
NSLog(#"Location services are not enabled");
}
// Set a timer to stop the Location services
//[NSTimer scheduledTimerWithTimeInterval:100.0 target:self selector:#selector(stopLocationServices) userInfo:nil repeats:NO];
_sidebarButton.tintColor = [UIColor colorWithWhite:0.1f alpha:0.9f];
// Set the side bar button action. When it's tapped, it'll show up the sidebar.
_sidebarButton.target = self.revealViewController;
_sidebarButton.action = #selector(revealToggle:);
// Set the gesture
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
// CLLocationManager *cllocationManager = [[CLLocationManager alloc] init];
// cllocationManager.delegate = self;
// cllocationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
// cllocationManager.distanceFilter = 20.0f;
//
// if ([CLLocationManager locationServicesEnabled])
// {
// [cllocationManager startUpdatingLocation];
// }
// else
// {
// UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Turn On Location Services to find your location"
// message:nil delegate:nil
// cancelButtonTitle:#"OK"
// otherButtonTitles:nil];
// [alert show];
// // [alert release];
// }
}
- (IBAction)mapChanger:(id)sender {
switch (((UISegmentedControl *) sender).selectedSegmentIndex) {
case 0:
self.mapk.mapType = MKMapTypeStandard;
break;
case 1:
self.mapk.mapType = MKMapTypeSatellite;
break;
case 2:
self.mapk.mapType = MKMapTypeHybrid;
break;
default:
break;
}
}
- (void)startLocationServices
{
// create the Location Manager
if (self.locationManager == nil) {
self.locationManager = [CLLocationManager new];
}
// settings
[self.locationManager setDelegate:self];
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[self.locationManager setDistanceFilter:kCLDistanceFilterNone];
// start services
[self.locationManager startUpdatingLocation];
self.gpsDisplay.text = #"Location Service started.";
}
- (void)stopLocationServices
{
// stop services
[self.locationManager stopUpdatingLocation];
[self.locationManager setDelegate:nil];
self.gpsDisplay.text = #"Location Services stopped.";
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
CLLocationCoordinate2D loc = [userLocation coordinate];
// CLLocationDistance in meters (1 meter = 3.3 feet)
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(loc, DISTANCE, DISTANCE);
[mapView setRegion:region animated:YES];
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
NSString *coords =#"lat";
coords = [coords stringByAppendingString:[NSString stringWithFormat:#"%f", newLocation.coordinate.latitude]];
coords = [coords stringByAppendingString:#"lon"];
coords = [coords stringByAppendingString:[NSString stringWithFormat:#"%f", newLocation.coordinate.longitude]];
self.gpsDisplay.text = coords;
MKCoordinateRegion region;
region.center.latitude = newLocation.coordinate.latitude;
region.center.longitude = newLocation.coordinate.longitude;
region.span.latitudeDelta = SPAN_VALUE;
region.span.longitudeDelta = SPAN_VALUE;
[self.mapk setRegion:region animated:YES];
}
- (void)viewDidUnload {
//[self setUpdates:nil];
[super viewDidUnload];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
In addition to the previous answer, note that you have to specify the reason for accessing the user's location information adding the relative key (NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription) to your project's Info.plist
for example:
<key>NSLocationWhenInUseUsageDescription</key>
<string>Location is required to find out jobs around you are</string>
On iOS 8, they changed how you ask for location permission. Instead of just being able to call startUpdatingLocation you need to now call either requestWhenInUseAuthorization or requestAlwaysAuthorization.

Getting location updates when app is inactive stops after 2 updates

I'm trying to get location updates while my app is inactive (user closed the app).
After 2 location updates, the location updates stops launching my app.
Indicator for this is the gray arrow in my app in location services settings.
What I'm trying is combination of startMonitoringSignificantLocationChanges & regionMonitoring.
I tested on iPhone 4 iOS 7.1.1 and location updates stops after 2 updates.
I tested in iPad mini WiFi+Cellular iOS 7.1.1 and location updates stops after 1 update and region monitoring send only 1 location.
Where I'm wrong?
My code:
AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
[RegionMonitoringService sharedInstance].launchOptions = launchOptions;
[[RegionMonitoringService sharedInstance] stopMonitoringAllRegions];
if ( [CLLocationManager significantLocationChangeMonitoringAvailable] ) {
[[RegionMonitoringService sharedInstance] startMonitoringSignificantLocationChanges];
} else {
NSLog(#"Significant location change service not available.");
}
if (launchOptions[UIApplicationLaunchOptionsLocationKey]) {
[self application:application handleNewLocationEvet:launchOptions]; // Handle new location event
UIViewController *controller = [[UIViewController alloc] init];
controller.view.frame = [UIScreen mainScreen].bounds;
UINavigationController *nvc = [[UINavigationController alloc] initWithRootViewController:controller];
dispatch_async(dispatch_get_main_queue(), ^{
appDelegate.window.rootViewController = nvc;
[appDelegate.window makeKeyAndVisible];
});
}
else {
// ...
}
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[defaults synchronize];
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
if ([RegionMonitoringService sharedInstance].launchOptions[UIApplicationLaunchOptionsLocationKey]) {
return;
}
}
- (void)application:(UIApplication *)application handleNewLocationEvet:(NSDictionary *)launchOptions
{
NSLog(#"%s, launchOptions: %#", __PRETTY_FUNCTION__, launchOptions);
if (![launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) return;
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) return;
SendLocalPushNotification(#"handleNewLocationEvet");
}
RegionMonitoringService.h:
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import "ServerApiManager.h"
#interface RegionMonitoringService : NSObject
#property (strong, nonatomic) CLLocationManager *locationManager;
#property (strong, nonatomic) NSDictionary *launchOptions;
#property (strong, nonatomic) NSDate *oldDate;
#property (strong, nonatomic) CLLocation *oldLocation;
+ (RegionMonitoringService *)sharedInstance;
- (void)startMonitoringForRegion:(CLRegion *)region;
- (void)startMonitoringRegionWithCoordinate:(CLLocationCoordinate2D)coordinate andRadius:(CLLocationDirection)radius;
- (void)stopMonitoringAllRegions;
- (void)startMonitoringSignificantLocationChanges;
- (void)stopMonitoringSignificantLocationChanges;
FOUNDATION_EXPORT NSString *NSStringFromCLRegionState(CLRegionState state);
#end
RegionMonitoringService.m:
#import "RegionMonitoringService.h"
static CLLocationDistance const kFixedRadius = 250.0;
#interface RegionMonitoringService () <CLLocationManagerDelegate>
- (NSString *)identifierForCoordinate:(CLLocationCoordinate2D)coordinate;
- (CLLocationDistance)getFixRadius:(CLLocationDistance)radius;
- (void)sortLastLocation:(CLLocation *)lastLocation;
#end
#implementation RegionMonitoringService
+ (RegionMonitoringService *)sharedInstance
{
static RegionMonitoringService *_sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedInstance = [[self alloc] init];
});
return _sharedInstance;
}
- (instancetype)init
{
self = [super init];
if (!self) {
return nil;
}
_locationManager = [[CLLocationManager alloc] init];
_locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
_locationManager.distanceFilter = kCLDistanceFilterNone;
// _locationManager.activityType = CLActivityTypeFitness;
_locationManager.delegate = self;
return self;
}
- (void)startMonitoringForRegion:(CLRegion *)region
{
NSLog(#"%s", __PRETTY_FUNCTION__);
[_locationManager startMonitoringForRegion:region];
}
- (void)startMonitoringRegionWithCoordinate:(CLLocationCoordinate2D)coordinate andRadius:(CLLocationDirection)radius
{
NSLog(#"%s", __PRETTY_FUNCTION__);
if (![CLLocationManager regionMonitoringAvailable]) {
NSLog(#"Warning: Region monitoring not supported on this device.");
return;
}
if (__iOS_6_And_Heigher) {
CLRegion *region = [[CLRegion alloc] initCircularRegionWithCenter:coordinate
radius:radius
identifier:[self identifierForCoordinate:coordinate]];
[_locationManager startMonitoringForRegion:region];
}
else {
CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:coordinate
radius:radius
identifier:[self identifierForCoordinate:coordinate]];
[_locationManager startMonitoringForRegion:region];
}
SendLocalPushNotification([NSString stringWithFormat:#"StartMonitor: {%f, %f}", coordinate.latitude, coordinate.longitude]);
}
- (void)stopMonitoringAllRegions
{
NSLog(#"%s", __PRETTY_FUNCTION__);
if (_locationManager.monitoredRegions.allObjects.count > 1) {
for (int i=0; i<_locationManager.monitoredRegions.allObjects.count; i++) {
if (i == 0) {
NSLog(#"stop monitor region at index %d", i);
CLRegion *region = (CLRegion *)_locationManager.monitoredRegions.allObjects[i];
[_locationManager stopMonitoringForRegion:region];
}
}
}
}
- (void)startMonitoringSignificantLocationChanges
{
NSLog(#"%s", __PRETTY_FUNCTION__);
[_locationManager startMonitoringSignificantLocationChanges];
}
- (void)stopMonitoringSignificantLocationChanges
{
NSLog(#"%s", __PRETTY_FUNCTION__);
[_locationManager stopMonitoringSignificantLocationChanges];
}
- (NSString *)identifierForCoordinate:(CLLocationCoordinate2D)coordinate
{
NSLog(#"%s", __PRETTY_FUNCTION__);
return [NSString stringWithFormat:#"{%f, %f}", coordinate.latitude, coordinate.longitude];
}
FOUNDATION_EXPORT NSString *NSStringFromCLRegionState(CLRegionState state)
{
NSLog(#"%s", __PRETTY_FUNCTION__);
if (__iOS_6_And_Heigher) {
return #"Support only iOS 7 and later.";
}
if (state == CLRegionStateUnknown) {
return #"CLRegionStateUnknown";
} else if (state == CLRegionStateInside) {
return #"CLRegionStateInside";
} else if (state == CLRegionStateOutside) {
return #"CLRegionStateOutside";
} else {
return [NSString stringWithFormat:#"Undeterminded CLRegionState"];
}
}
- (CLLocationDistance)getFixRadius:(CLLocationDistance)radius
{
if (radius > _locationManager.maximumRegionMonitoringDistance) {
radius = _locationManager.maximumRegionMonitoringDistance;
}
return radius;
}
- (void)sortLastLocation:(CLLocation *)lastLocation
{
NSLog(#"%s, %#", __PRETTY_FUNCTION__, lastLocation);
self.oldDate = lastLocation.timestamp; // Get new date
NSTimeInterval seconds = fabs([self.oldLocation.timestamp timeIntervalSinceDate:self.oldDate]); // Calculate how seconds passed
NSInteger minutes = seconds * 60; // Calculate how minutes passed
if (lastLocation && self.oldLocation) { // New & old location are good
if ([lastLocation distanceFromLocation:self.oldLocation] >= 200 || minutes >= 30) { // Distance > 200 or 30 minutes passed
[[ServerApiManager sharedInstance] saveLocation:lastLocation]; // Send location to server
}
}
else { // We just starting location updates
[[ServerApiManager sharedInstance] saveLocation:lastLocation]; // Send new location to server
}
self.oldLocation = lastLocation; // Set old location
}
#pragma mark - CLLocationManagerDelegate Methods
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(#"%s, %#", __PRETTY_FUNCTION__, locations);
CLLocation *lastLocation = (CLLocation *)locations.lastObject;
CLLocationCoordinate2D coordinate = lastLocation.coordinate;
if (lastLocation == nil || coordinate.latitude == 0.0 || coordinate.longitude == 0.0) {
return;
}
[self startMonitoringRegionWithCoordinate:coordinate andRadius:[self getFixRadius:kFixedRadius]];
[self sortLastLocation:lastLocation];
}
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
NSLog(#"%s, currentLocation: %#, regionState: %#, region: %#",
__PRETTY_FUNCTION__, manager.location, NSStringFromCLRegionState(state), region);
}
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region
{
NSLog(#"%s, REGION: %#", __PRETTY_FUNCTION__, region);
[manager requestStateForRegion:region];
}
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
NSLog(#"%s, REGION: %#", __PRETTY_FUNCTION__, region);
[self stopMonitoringAllRegions];
[self startMonitoringRegionWithCoordinate:manager.location.coordinate andRadius:[self getFixRadius:kFixedRadius]];
CLLocation *lastLocation = manager.location;
CLLocationCoordinate2D coordinate = lastLocation.coordinate;
if (lastLocation == nil || coordinate.latitude == 0.0 || coordinate.longitude == 0.0) {
return;
}
[self sortLastLocation:manager.location];
}
#end
EDIT 1:
I did a a lot of real time tests with car with several devices (iPhone 5s, iPad mini, iPhone 4) after several tests I came to this:
In one case, iPad mini & iPhone 4 stops updating location after several minutes when app is not running and the little arrow become gray.
When WiFi was off, the accuracy was terrible and locations updated rarely.
EDIT 2:
OK, after a lot of driving and walking around and testing it it works like a charm so far.
I managed to make it work, combining significantLocationChanges & region monitoring, always register a geofence around my current location and always starting significant location changes when new UIApplicationLaunchOptionsLocationKey come.
Note that turning off wifi make accuracy very low and even sometimes not working.
Any bugs in my code?
From the Apple docs it can be seen that updates are not sent more frequently than every 5 minutes and for 500 meters of location change:
Apps can expect a notification as soon as the device moves 500 meters or more from its previous notification. It should not expect notifications more frequently than once every five minutes. If the device is able to retrieve data from the network, the location manager is much more likely to deliver notifications in a timely manner.
You are going to receive the updates even when the app is inactive. Another hint for you might be that oyu can test the location in the simulator instead using a real device, this way you don't have to go outside for testing and can still check your logs too. In the simulator menu, chose Debug --> Location.

Showing current location in my iphone

I am implementing the route directions from my current location to some destination location.
When I enter in a specific page, my application crashes. But if I run the app again, it shows the route directions.
I found out the problem is that the first time, current location is showing as 0.00000,0.00000 coordinates. The second time I launch the app, current location is showing up correctly.
What is going wrong?
I want to get my current position correctly at first time.
I am writing the code on below. Once please check it out and let me know the where is the problem in my code
#import "MapWithRoutesViewController.h"
#import "TFSViewController.h"
#implementation MapWithRoutesViewController
#synthesize locationManager,lat,lon;
- (void) updateCurrentLabel {
NSObject *latitude = [NSString stringWithFormat:#"%f", locationManager.location.coordinate.latitude];
NSObject *longitude = [NSString stringWithFormat:#"%f", locationManager.location.coordinate.longitude];
locationlable.text = [NSString stringWithFormat: #"Current Location: %#,%#", latitude, longitude];
}
- (void)viewDidLoad {
[self getCurrentLocation];
[super viewDidLoad];
}
-(void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
[self updateCurrentLabel];
}
-(void) getCurrentLocation {
MapView* mapView = [[[MapView alloc] initWithFrame:
CGRectMake(0, 90, self.view.frame.size.width, self.view.frame.size.height)] autorelease]; [self.view
addSubview:mapView];
Place* home = [[[Place alloc] init] autorelease];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
if (locationManager==NO) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Location Service Disabled"
message:#"To re-enable, please go to Settings and turn on Location Service for
this app."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
} else {
// if (locationManager==NO)
// [mapView.lo addObserver:self forKeyPath:#"location"
// options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld)
// context:nil];
}
locationManager.pausesLocationUpdatesAutomatically = NO;
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
[locationManager setPausesLocationUpdatesAutomatically:YES];
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
locationManager.distanceFilter = kCLDistanceFilterNone;
[locationManager startUpdatingLocation];
CLLocation *Loc = [locationManager location];
CLLocationCoordinate2D coordinate = [Loc coordinate];
NSObject *latitude = [NSString stringWithFormat:#"%f", locationManager.location.coordinate.latitude];
NSObject *longitude = [NSString stringWithFormat:#"%f", locationManager.location.coordinate.longitude];
NSLog(#"lat,lon %#%#",latitude,longitude);
home.name = #"";
home.description = #"";
home.latitude = coordinate.latitude;
home.longitude = coordinate.longitude;
Place* office = [[[Place alloc] init] autorelease];
office.name = #"";
office.description = #"";
office.latitude = 22.0000;
office.longitude = 88.0008;
[mapView showRouteFrom:home to:office];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(IBAction)back:(id)sender{
[self dismissViewControllerAnimated:YES completion:nil];
}
-(IBAction)tfs:(id)sender{
TFSViewController *tfs = [[TFSViewController alloc]initWithNibName:#"TFSViewController" bundle:nil];
[self presentViewController:tfs animated:YES completion:nil];
}
#end
The trouble is you're making the location manager and then expecting it to have a location a few micro seconds later. You should be setting the location manager's delegate and then waiting for it to be called. When LM has a location it will call didUpdateLocation and you can use that to call updateCurrentLabel
You should use delegate method -locationManager:didUpdateLocations: to get the locations. CLLocationManager takes few seconds to establish a GPS connection and determine the current location.
http://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManagerDelegate_Protocol/CLLocationManagerDelegate/CLLocationManagerDelegate.html#//apple_ref/occ/intfm/CLLocationManagerDelegate/locationManager:didUpdateLocations:
You could also use CLLocation's horizontalAccuracy property to check the accuracy of the location to determine if you want to use the value or discard it.
http://developer.apple.com/library/ios/#documentation/CoreLocation/Reference/CLLocation_Class/CLLocation/CLLocation.html#//apple_ref/occ/cl/CLLocation

Resources