Requirement: I want to send location details to the server after every 2 min. for that I have used a timer of 2 min to send the location to the server. I am fetching current location from location manager and sending coordinates to the server.
Below is the code to get background location and handle background app refresh
//Background location update
self.shareModel = [LocationShareModel sharedModel];
self.shareModel.afterResume = NO;
UIAlertView * alert;
//We have to make sure that the Background App Refresh is enable for the Location updates to work in the background.
if([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusDenied){
alert = [[UIAlertView alloc]initWithTitle:@""
message:@"The app doesn't work without the Background App Refresh enabled. To turn it on, go to Settings > General > Background App Refresh"
delegate:nil
cancelButtonTitle:@"Ok"
otherButtonTitles:nil, nil];
[alert show];
}else if([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusRestricted){
alert = [[UIAlertView alloc]initWithTitle:@""
message:@"The functions of this app are limited because the Background App Refresh is disable."
delegate:nil
cancelButtonTitle:@"Ok"
otherButtonTitles:nil, nil];
[alert show];
} else{
// When there is a significant change of the location,
// The key UIApplicationLaunchOptionsLocationKey will be returned from didFinishLaunchingWithOptions
// When the app is receiving the key, it must reinitiate the locationManager and get
// the latest location updates
// This UIApplicationLaunchOptionsLocationKey key enables the location update even when
// the app has been killed/terminated (Not in th background) by iOS or the user.
if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {
DebugLog(@"UIApplicationLaunchOptionsLocationKey");
// This "afterResume" flag is just to show that he receiving location updates
// are actually from the key "UIApplicationLaunchOptionsLocationKey"
self.shareModel.afterResume = YES;
self.shareModel.anotherLocationManager = [[CLLocationManager alloc]init];
self.shareModel.anotherLocationManager.delegate = self;
self.shareModel.anotherLocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
self.shareModel.anotherLocationManager.activityType = CLActivityTypeOtherNavigation;
if([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
[self.shareModel.anotherLocationManager requestAlwaysAuthorization];
}
[self.shareModel.anotherLocationManager startMonitoringSignificantLocationChanges];
}
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
// NSLog(@"locationManager didUpdateLocations: %@",locations);
for(int i=0;i<locations.count;i++){
CLLocation * newLocation = [locations objectAtIndex:i];
CLLocationCoordinate2D theLocation = newLocation.coordinate;
CLLocationAccuracy theAccuracy = newLocation.horizontalAccuracy;
self.myLocation = theLocation;
self.myLocationAccuracy = theAccuracy;
self.myLoc = newLocation;
}
// self.shareModel.bgTask = [BackgroundTaskManager sharedBackgroundTaskManager];
// [self.shareModel.bgTask beginNewBackgroundTask];
}
-(CLLocation *)getCurrentLocation
{
if(locationManager.location)
{
return locationManager.location;
}
else if(currentLoaction)
{
return currentLoaction;
}
// return locationManager.location;
return self.myLoc;
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
firstDate=[NSDate date];
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
[ud setValue:firstDate forKey:@"FirstDate"];
[ud synchronize];
// 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.
DebugLog(@"applicationDidEnterBackground");
[self.shareModel.anotherLocationManager stopMonitoringSignificantLocationChanges];
if([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
[self.shareModel.anotherLocationManager requestAlwaysAuthorization];
}
[self.shareModel.anotherLocationManager startMonitoringSignificantLocationChanges];
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
[[UIApplication sharedApplication] ignoreSnapshotOnNextApplicationLaunch];
DebugLog(@"applicationDidBecomeActive");
//Remove the "afterResume" Flag after the app is active again.
self.shareModel.afterResume = NO;
if(self.shareModel.anotherLocationManager)
[self.shareModel.anotherLocationManager stopMonitoringSignificantLocationChanges];
self.shareModel.anotherLocationManager = [[CLLocationManager alloc]init];
self.shareModel.anotherLocationManager.delegate = self;
self.shareModel.anotherLocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
self.shareModel.anotherLocationManager.activityType = CLActivityTypeOtherNavigation;
if([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
[self.shareModel.anotherLocationManager requestAlwaysAuthorization];
}
[self.shareModel.anotherLocationManager startMonitoringSignificantLocationChanges];
}
and here is the code to send the location to the server
#pragma pingDriver Location webservice call
-(void)pingdriverLocation
{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
CLLocation *currentLocation = [appDelegate getCurrentLocation];
if (appDelegate.internetStatus==0)
{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *driverLocationUpdatesInfo;
if([userDefaults valueForKey:@"driverLocationInfo"]){
driverLocationUpdatesInfo = [[NSMutableArray alloc]initWithArray:[CommonUtility fetchArrayFrompListWithKey:@"driverLocationInfo" keyToStoreArrayInDict:@"LocationData"]];
}else{
driverLocationUpdatesInfo = [[NSMutableArray alloc]init];
}
if(currentLocation){
[driverLocationUpdatesInfo addObject:currentLocation];
}
[CommonUtility storeArrayInpListWithKey:@"driverLocationInfo" keyToStoreArrayInDict:@"LocationData" array:driverLocationUpdatesInfo];
}
else
{
offlineDriverLocationDataUpload = NO;
objDriverPing = [[pingDriverLocationwebService alloc]init];
objDriverPing.delegate = self;
[objDriverPing pingDriverLocationWebService:self latitude:[NSString stringWithFormat:@"%f",currentLocation.coordinate.latitude] longitude:[NSString stringWithFormat:@"%f",currentLocation.coordinate.longitude]];
}
}
#pragma mark - ping driver location web service response
-(void)serverResponseForPingDriverLocationWebSerivce:(BOOL)proceed responseDict:(NSDictionary *)responseDict
{
DebugLog(@"%@",responseDict);
if(proceed)
{
if(offlineDriverLocationDataUpload)
{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
if([userDefaults valueForKey:@"driverLocationInfo"])
{
NSMutableArray *driverLocationUpdatesInfo = [[NSMutableArray alloc]initWithArray:[CommonUtility fetchArrayFrompListWithKey:@"driverLocationInfo" keyToStoreArrayInDict:@"LocationData"]];
NSArray *tempArray = [[NSArray alloc]initWithArray:driverLocationUpdatesInfo];
//to remove object of currentOfflineLocation
for(CLLocation *location in tempArray)
{
if(location.coordinate.latitude == currentOfflineLocation.coordinate.latitude && location.coordinate.longitude == currentOfflineLocation.coordinate.longitude)
{
[driverLocationUpdatesInfo removeObject:location];
break;
}
}
currentOfflineLocation = nil;
[CommonUtility storeArrayInpListWithKey:@"driverLocationInfo" keyToStoreArrayInDict:@"LocationData" array:driverLocationUpdatesInfo];
if(driverLocationUpdatesInfo.count > 0)
{
[self uploadOfflineDriverLocationData];
}
else
{
[userDefaults removeObjectForKey:@"driverLocationInfo"];
[userDefaults synchronize];
[self pingdriverLocation];
}
}
}
else
{
if([[responseDict valueForKey:@"Next"] integerValue] > 0)
{
if([[responseDict valueForKey:@"Notification"] isEqualToString:@"Y"])
{
[[[UIAlertView alloc]initWithTitle:@"Alert" message:[responseDict valueForKey:@"Message"] delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil] show];
}
if (self.locationUpdateTimer) {
[self.locationUpdateTimer invalidate];
}
if([[responseDict valueForKey:@"Next"] integerValue] != 0)
{
self.locationUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:2 * 60 target:self selector:@selector(updateLocation) userInfo:nil repeats:YES];
}
}
}
}
}
currently, when the app is in foreground state it able to send the location to the server after every two min. and when an internet connection is not there then I am storing location coordinate and upload them to the server once I get the connection back again.
Problem: consider that I started ping service and after 30 min my app went to background state and the connection is lost in that state it stores location in a plist and when my came to foreground it upload all the data to the server but after that it not start sending location again.
Please help me as I am going out of solutions now.
I have also followed this tutorial
My guess is you need to fire again the timer in applicationDidBecomeActive:
because your timer is not resumed. BTW, remember to invalidate your timer first:
[self.locationUpdateTimer invalidate];
self.locationUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:2 * 60 target:self selector:@selector(updateLocation) userInfo:nil repeats:YES];