I have an application that makes the location trace in background. As soon as I get WhatsApp or the phone my location stops and resumes after seeing the image. Would anyone have information on this problem?
Image
- (void) startUpdatingLocationFonction
{
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[self.locationManager setDistanceFilter:kCLDistanceFilterNone];
[self.locationManager startUpdatingLocation];
self.locationManagerStartDate = [NSDate date];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
[AppDelegate sharedInstance].latitude=newLocation.coordinate.latitude;
[AppDelegate sharedInstance].longitude=newLocation.coordinate.longitude;
if (![[FoncGlobal sharedFoncGlobal] isValidLocation:(CLLocation *)newLocation withOldLocation:(CLLocation *)oldLocation])
return;
if ((oldLocation.coordinate.longitude != newLocation.coordinate.longitude)
|| (oldLocation.coordinate.latitude != newLocation.coordinate.latitude))
{
[[FoncGlobal sharedFoncGlobal] upDateTraceUser: [NSString stringWithFormat:#"%.8lf",newLocation.coordinate.latitude]: [NSString stringWithFormat:#"%.8lf",newLocation.coordinate.longitude] :[NSString stringWithFormat:#"%.8lf",newLocation.altitude]:[NSString stringWithFormat:#"%.8lf",newLocation.speed]:0];
}
}
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
if (_inBackground) {
[self extendBackgroundRunningTime];
}
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[self extendBackgroundRunningTime];
_inBackground = YES;
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
_inBackground = NO;
}
- (void)extendBackgroundRunningTime {
if (bgTask != UIBackgroundTaskInvalid) {
return;
}
NSLog(#"Attempting to extend background running time");
__block Boolean self_terminate = NO;
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithName:#"DummyTask" expirationHandler:^{
NSLog(#"Background task expired by iOS");
if (self_terminate) {
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (true) {
if ([AppDelegate sharedInstance].startTrack)
[self startUpdatingLocationFonction];
[NSThread sleepForTimeInterval:3];
}
});
}
Related
After receive a push notification I am trying to get the current localization.
However when I start the code bellow the corelocation fails (didFailWithError) when the app is at background :(
Only works in foreground.
Why?
I already did the .plist for background configuration
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler{
__block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
NSLog(#" Finalizado background...");
}];
[self handleStartMonitoringLocation];
NSLog(#"Main Thread proceeding...");
}
-(void)handleStartMonitoringLocation{
// location
if (!self.shareModel) {
self.shareModel = [LocationManager sharedManager];
self.shareModel.afterResume = NO;
[self.shareModel addApplicationStatusToPList:#"didFinishLaunchingWithOptions"];
}
[self.shareModel addApplicationStatusToPList:#"applicationDidBecomeActive"];
//Remove the "afterResume" Flag after the app is active again.
self.shareModel.afterResume = NO;
// [self.shareModel startMonitoringLocation];
[self.shareModel startBackgroundLocationUpdates];
}
-(void)startBackgroundLocationUpdates {
// Create a location manager object
self.anotherLocationManager = [[CLLocationManager alloc] init];
// Set the delegate
self.anotherLocationManager.delegate = self;
// Request location authorization
[self.anotherLocationManager requestWhenInUseAuthorization];
// Set an accuracy level. The higher, the better for energy.
self.anotherLocationManager.desiredAccuracy = kCLLocationAccuracyBest;
// Enable automatic pausing
self.anotherLocationManager.pausesLocationUpdatesAutomatically = YES;
// Specify the type of activity your app is currently performing
self.anotherLocationManager.activityType = CLActivityTypeFitness;
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"9.0")){
// Enable background location updates
self.anotherLocationManager.allowsBackgroundLocationUpdates = YES;
[self.anotherLocationManager requestLocation];
}
else{
// Start location updates
[self.anotherLocationManager startUpdatingLocation];
}
}
#pragma mark - CLLocationManager Delegate
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(#"locationManager error: %#",error);
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
NSLog(#"locationManager didUpdateLocations: %#",locations);
}
I have created multiple geo-fence to monitor region entry/exit events.
I have created a location manager in AppDelegate.h file.
#interface AppDelegate : UIResponder <UIApplicationDelegate, CLLocationManagerDelegate>
#property (strong, nonatomic) UIWindow *window;
#property(nonatomic,retain)CLLocationManager *locationManager;
#property(nonatomic,retain)CLLocation *currentLocation;
+(AppDelegate *)sharedDelegate;
AppDelegate.m file
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (notification) {
NSLog(#"AppDelegate didFinishLaunchingWithOptions");
application.applicationIconBadgeNumber = 0;
}
if ([application respondsToSelector:#selector(registerUserNotificationSettings:)])
{
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge|UIUserNotificationTypeAlert|UIUserNotificationTypeSound) categories:nil];
[application registerUserNotificationSettings:settings];
}
else // iOS 7 or earlier
{
UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
[application registerForRemoteNotificationTypes:myTypes];
}
if (!self.locationManager)
{
self.locationManager = [[CLLocationManager alloc] init];
}
self.locationManager.delegate = self;
//locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
self.locationManager.distanceFilter = 2.0f;
self.locationManager.activityType = CLActivityTypeAutomotiveNavigation;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
{
[self.locationManager requestAlwaysAuthorization];
}
if ([self.locationManager respondsToSelector:#selector(allowsBackgroundLocationUpdates)])
{
self.locationManager.allowsBackgroundLocationUpdates = YES;
}
if ([self.locationManager respondsToSelector:#selector(pausesLocationUpdatesAutomatically)])
{
self.locationManager.pausesLocationUpdatesAutomatically= NO;
}
[self.locationManager stopMonitoringSignificantLocationChanges];
if ([CLLocationManager locationServicesEnabled] && [CLLocationManager authorizationStatus] != kCLAuthorizationStatusDenied)
{
[self.locationManager startUpdatingLocation];
}
// Override point for customization after application launch.
return YES;
}
-(void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region
{
NSLog(#"Started monitoring %# region",region.identifier);
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
NSLog(#"%#",[locations description]);
}
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
dispatch_async(dispatch_get_main_queue(), ^{
if ([[UIApplication sharedApplication] applicationState]==UIApplicationStateBackground || [[UIApplication sharedApplication] applicationState]==UIApplicationStateInactive)
{
UILocalNotification *localnotification = [[UILocalNotification alloc]init];
localnotification.fireDate=[NSDate dateWithTimeIntervalSinceNow:1];
localnotification.alertBody=#"You are enter in region.";
localnotification.timeZone=[NSTimeZone defaultTimeZone];
localnotification.repeatInterval = 0;
localnotification.hasAction=YES;
[[UIApplication sharedApplication]scheduleLocalNotification:localnotification];
}
else
{
[[[UIAlertView alloc]initWithTitle:#"message" message:#"Enter into region." delegate:self cancelButtonTitle:nil otherButtonTitles:#"Ok ", nil] show];
}
});
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
dispatch_async(dispatch_get_main_queue(), ^{
if ([[UIApplication sharedApplication] applicationState]==UIApplicationStateBackground || [[UIApplication sharedApplication] applicationState]==UIApplicationStateInactive)
{
UILocalNotification *localnotificationExit = [[UILocalNotification alloc]init];
localnotificationExit.fireDate=[NSDate dateWithTimeIntervalSinceNow:1];
localnotificationExit.alertBody=#"You are exit from region.";
NSLog(#"Exit from region.");
localnotificationExit.timeZone=[NSTimeZone defaultTimeZone];
localnotificationExit.repeatInterval = 0;
localnotificationExit.hasAction=YES;
[[UIApplication sharedApplication]scheduleLocalNotification:localnotificationExit];
}
else
{
[[[UIAlertView alloc]initWithTitle:#"message" message:#"Exit from region." delegate:self cancelButtonTitle:nil otherButtonTitles:#"Ok ", nil] show];
}
});
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
[[[UIAlertView alloc] initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
}
This things are to manage the region monitoring.
Now my view controller are adding the regions for monitoring.
-(void)AddRegionsInGeoFence
{
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
//----1
CLLocationCoordinate2D centerCoordinate1 = CLLocationCoordinate2DMake(23.046518, 72.543337);
CLCircularRegion *region1 =[[CLCircularRegion alloc] initWithCenter:centerCoordinate1 radius:200 identifier:#"Location First"];
NSLog(#"%#",[region1 description]);
region1.notifyOnEntry=YES;
region1.notifyOnExit=YES;
if (![standardDefaults boolForKey:#"EnterRegion"])
{
[[AppDelegate sharedDelegate].locationManager startMonitoringForRegion:region1];
NSLog(#"Started Monitoring- %#", [region1 description]);
}
[self.mapview setShowsUserLocation:YES];
[self.mapview setUserTrackingMode:MKUserTrackingModeFollow animated:YES];
//----2
CLLocationCoordinate2D centercoordinate2=CLLocationCoordinate2DMake(23.064381, 72.531181);
CLCircularRegion *region2=[[CLCircularRegion alloc]initWithCenter:centercoordinate2 radius:200 identifier:#"Location Second"];
NSLog(#"%#",[region2 description]);
region2.notifyOnEntry=YES;
region2.notifyOnExit=YES;
if (![standardDefaults boolForKey:#"EnterRegion"])
{
[[AppDelegate sharedDelegate].locationManager startMonitoringForRegion:region2];
NSLog(#"Started Monitoring- %#", [region2 description]);
}
//----3
CLLocationCoordinate2D centercoordinate3=CLLocationCoordinate2DMake(23.083583,72.546441);
CLCircularRegion *region3=[[CLCircularRegion alloc]initWithCenter:centercoordinate3 radius:200 identifier:#"Location Third"];
NSLog(#"%#",[region3 description]);
region3.notifyOnEntry=YES;
region3.notifyOnExit=YES;
if (![standardDefaults boolForKey:#"EnterRegion"])
{
[[AppDelegate sharedDelegate].locationManager startMonitoringForRegion:region3];
NSLog(#"Started Monitoring- %#", [region3 description]);
}
//4
CLLocationCoordinate2D centercoordinate4=CLLocationCoordinate2DMake(23.122255, 72.584499);
CLCircularRegion *region4=[[CLCircularRegion alloc]initWithCenter:centercoordinate4 radius:500 identifier:#"Location Fourth"];
NSLog(#"%#",[region4 description]);
region4.notifyOnEntry=YES;
region4.notifyOnExit=YES;
if (![standardDefaults boolForKey:#"EnterRegion"])
{
[[AppDelegate sharedDelegate].locationManager startMonitoringForRegion:region4];
NSLog(#"Started Monitoring- %#", [region4 description]);
[standardDefaults setBool:YES forKey:#"EnterRegion"];
[standardDefaults synchronize];
}
}
My Problem is region monitoring methods are called multiple times even if I am not moving in side the region itself. Everything else is working fine, Accuracy buffer is around 50-80 meters that is fine for me.
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
Also if I am turning off Wi-Fi then it's calling up these methods back to back saying exit from region and enter in to region. As far as I know GPS accuracy is depends on Wi-Fi.
Any help would be highly appreciated.
a Possible workaround in the interim while the apple bug gets fixed is to rate limit the callback; thereby not acting on all the callbacks but limiting the rate at which the callbacks can get processed.
Callback execution portions that happen before the time period expires get ignored.
Here is and example code that could assist, not tested:
The rate is limited to 2 seconds.
-(void)methodRateLimit {
#synchronized(self) {
// rate limit begin
static NSDate *lastTimeExit = nil;
if (!lastTimeExit) {
lastTimeExit = [NSDate distantPast]; // way back in time
}
NSDate *now = [NSDate date];
if ([now timeIntervalSinceDate:lastTimeExit] > 2) {
// do work here
NSLog(#"Executing");
lastTimeExit = now;
} else {
NSLog(#"Limiting");
}
}
}
Im building a simple ios app with IBeacon, Im using startMonitoringForRegion for detect beacons.
Thats working ok.
I also want to check the users location when the app is background or closed, for that purpose im using startMonitoringSignificantLocationChanges. In background modes works ok, but when the app is closed the didUpdateLocations: callback is not fired.
My code (from AppDelegate.m) is below:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {
[self.locationManager startMonitoringSignificantLocationChanges];
NSString *message = #"UIApplicationLaunchOptionsLocationKey";
[self sendLocalNotificationWithMessage:message];
}
UILocalNotification *localNotif =
[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotif)
{
NSString *idN = [localNotif.userInfo objectForKey:#"id_notif"];
[self sendToDetail:idN];
}
if ([UIApplication instancesRespondToSelector:#selector(registerUserNotificationSettings:)]) {
NSLog(#"RESPONDS!!!!!");
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeSound|UIUserNotificationTypeBadge categories:nil]];
}
[self resetBadge];
// Override point for customization after application launch.
NSUUID *beaconUUID = [[NSUUID alloc] initWithUUIDString:#"B9407F30-F5F8-466E-AFF9-25556B57FE6A"];
NSString *regionIdentifier = #"iBeacons region 1";
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID: beaconUUID identifier: regionIdentifier ];
beaconRegion.notifyEntryStateOnDisplay = YES;
self.locationManager = [[CLLocationManager alloc]init];
if([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]){
[self.locationManager requestAlwaysAuthorization];
}
self.locationManager.delegate = self;
//self.locationManager.pausesLocationUpdatesAutomatically = NO;
[self.locationManager startMonitoringForRegion:beaconRegion];
return YES;
}
- (void) locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region{
[manager startRangingBeaconsInRegion:(CLBeaconRegion*) region];
NSLog(#"didEnterRegion");
}
- (void) locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region{
[manager stopRangingBeaconsInRegion:(CLBeaconRegion*) region];
NSLog(#"didExitRegion");
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSLog(#"startMonitoringSignificantLocationChanges");
[self.locationManager startMonitoringSignificantLocationChanges];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
NSLog(#"stopMonitoringSignificantLocationChanges");
[self.locationManager stopMonitoringSignificantLocationChanges];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
NSString *message = #"didUpdateLocations";
[self sendLocalNotificationWithMessage:message];
CLLocation *currentLocation = locations[0];
if (currentLocation != nil) {
NSString *longitude = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
NSString *latitude = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
NSString *message = [NSString stringWithFormat:#"longitud: %# latitud: %#", longitude,latitude ];
[self sendLocalNotificationWithMessage:message];
}
}
Any idea?
Thanks
In my app I want to fetch and upload location on server in regular intervals. for foreground it works fine but for background it has issue as described below. One thing to mention here I use different class for foreground and separate code for background.
To fetch location in background I do the following. It does upload location for about 24 - 40 hours but get stopped after 24-40 hours. I did not get "willTerminate" event. I have also written code to capture global execption so that I could log SigKill if user kill my app but it too does not get logged reason could be we can't catch SigKill.
Now I am stuck don't know what to do to keep my app alive in background to upload location in regular intervals.
//////////////////////////////// didfinish lauch ///////////////////////////////
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
return YES;
}
////////// **did enter background**
- (void) applicationDidEnterBackground:(UIApplication *)application
{
self.bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
}];
timer = [[NSTimer scheduledTimerWithTimeInterval:8*60
target:self
selector:#selector(changeAccuracy)
userInfo:nil
repeats:YES] retain];
[self.locationManager startUpdatingLocation];
}
- (void) changeAccuracy
{
self.bCallbackStarted = NO;
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[self.locationManager setDistanceFilter:100];
}
///////// **did enter fore ground**
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[self.locationManager stopUpdatingLocation];
}
////////// **did update location**
-(void)locationManager:(CLLocationManager *)lm didUpdateLocations:(NSArray *)locations
{
if (self.bCallbackStarted == YES) {
NSString* logStr = [NSString stringWithFormat:#"URLFilteringAppDelegate::didUpdateLocations not uploading location because self.bCallbackStarted == YES"];
LOGI(logStr)
return;
}
self.bCallbackStarted = YES;
[[AppUtility sharedInstance] setLocationStatus:YES];
CLLocation *location = [locations lastObject];
if(location.coordinate.latitude == 0 && location.coordinate.longitude == 0)
{
[UserSettings sharedInstance].Latitude = [NSString stringWithFormat:#"%#", #"Unavailable"];
[UserSettings sharedInstance].Longitude = [NSString stringWithFormat:#"%#", #"Unavailable"];
}
else
{
[UserSettings sharedInstance].Latitude = [NSString stringWithFormat:#"%.8f", location.coordinate.latitude];
[UserSettings sharedInstance].Longitude = [NSString stringWithFormat:#"%.8f", location.coordinate.longitude];
}
[[LocationManager sharedInstance] sendLocation];
/// this is set to save battery
[lm setDesiredAccuracy:kCLLocationAccuracyThreeKilometers];
[lm setDistanceFilter:99999];
}
I have a small issue with the startMonitoringSignificantLocationChanges, it doesn't seem to work. the location icon is shown, but my delegate function is never triggered
I have made a class for it here it is:
header file:
#interface geolocation : NSObject < CLLocationManagerDelegate > {
CLLocationManager *locationManager;
}
- (void) significantChange;
- (void) stopSignificantChange;
- (void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation;
- (void) locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error;
#end
m file:
#implementation geolocation
- (void) significantChange
{
if (nil == locationManager)
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[locationManager startMonitoringSignificantLocationChanges];
}
- (void) stopSignificantChange
{
[locationManager stopMonitoringSignificantLocationChanges];
}
- (void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
UIBackgroundTaskIdentifier bgTask = [[UIApplication sharedApplication]
beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UILocalNotification* alarm = [[UILocalNotification alloc] init];
if (alarm)
{
alarm.fireDate = [NSDate dateWithTimeIntervalSinceNow:10];
alarm.timeZone = [NSTimeZone defaultTimeZone];
alarm.repeatInterval = 0;
alarm.alertBody = #"Time to wake up!";
alarm.applicationIconBadgeNumber = 1;
[[UIApplication sharedApplication] scheduleLocalNotification:alarm];
}
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
});
}
- (void) locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
}
- (void) dealloc
{
locationManager.delegate = nil;
locationManager = nil;
}
#end
in AppDelegate I call it:
- (void) applicationDidEnterBackground:(UIApplication *)application
{
[UIApplication sharedApplication].applicationIconBadgeNumber = 1;
[geo significantChange];
return [super applicationDidEnterBackground:application];
}
In my case "significant" means 11 callbacks in more than 60 km. So you might just be at the limit.
Edit: That is driving straight south. If you are just driving round and round it is very reasonable that nothing happens.