Continuous location details when app is killed/Terminated - ios

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.

Related

iOS app background location access using a timer

I am looking for a solution to access/stop location services while app is in the background. My app takes continuous location when it's sent to background (It has access to continuous location) . It's necessary for the app functionality.
So I would like to know few things:
How long my app can take continuous location while it's still in the background? (before OS kills the background process or something like that)
If I want to add a timer say after 60 minutes app will stop taking the location, what would be the correct approach?
Background location updation can be done using following code:
In Appdelegate class:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if ([launchOptions objectForKey: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 startMonitoringLocation];
}
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
[self.shareModel stopContinuosLocationUpdate];
[self.shareModel restartMonitoringLocation];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
//Remove the "afterResume" Flag after the app is active again.
self.shareModel.afterResume = NO;
[self.shareModel startContinuosLocationUpdate];
}
In Location update class, say LocationManager.m:
#import <CoreLocation/CoreLocation.h>
#property (nonatomic) CLLocationManager * anotherLocationManager;
- (void)startContinuosLocationUpdate
{
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
if (status == kCLAuthorizationStatusDenied)
{
NSLog(#"Location services are disabled in settings.");
}
else
{
// for iOS 8
if ([self.anotherLocationManager respondsToSelector:#selector(requestAlwaysAuthorization)])
{
[self.anotherLocationManager requestAlwaysAuthorization];
}
// for iOS 9
if ([self.anotherLocationManager respondsToSelector:#selector(setAllowsBackgroundLocationUpdates:)])
{
[self.anotherLocationManager setAllowsBackgroundLocationUpdates:YES];
}
[self.anotherLocationManager startUpdatingLocation];
}
}
- (void)stopContinuosLocationUpdate
{
[self.anotherLocationManager stopUpdatingLocation];
}
- (void)startMonitoringLocation
{
if (_anotherLocationManager)
[_anotherLocationManager stopMonitoringSignificantLocationChanges];
self.anotherLocationManager = [[CLLocationManager alloc]init];
_anotherLocationManager.delegate = self;
_anotherLocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
_anotherLocationManager.activityType = CLActivityTypeOtherNavigation;
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"9.0")) {
[_anotherLocationManager setAllowsBackgroundLocationUpdates:YES];
}
else if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0")) {
[_anotherLocationManager requestAlwaysAuthorization];
}
[_anotherLocationManager startMonitoringSignificantLocationChanges];
}
- (void)restartMonitoringLocation
{
[_anotherLocationManager stopMonitoringSignificantLocationChanges];
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"9.0")) {
[_anotherLocationManager setAllowsBackgroundLocationUpdates:YES];
}
else if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0")) {
[_anotherLocationManager requestAlwaysAuthorization];
}
[_anotherLocationManager startMonitoringSignificantLocationChanges];
}
#pragma mark - CLLocationManager Delegate
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
if(_dictLocation && [_dictLocation isKindOfClass:[NSDictionary class]])
{
float latitudeValue = [[RVCommon validateDataForNumber:_dictLocation[#"lat"]] floatValue];
float longitudeValue = [[RVCommon validateDataForNumber:_dictLocation[#"lng"]] floatValue];
CLLocation *facilityLocation = [[CLLocation alloc] initWithLatitude:latitudeValue longitude:longitudeValue];
CLLocation *mostRecentLocation = locations.lastObject;
CLLocationDistance distanceInMeters = [mostRecentLocation distanceFromLocation:facilityLocation];
if (distanceInMeters <= 500.0)
{
//Here I am informing the server when user is within 500mts of the coordinate.
}
}
NSLog(#"locationManager didUpdateLocations: %#",locations);
}

iOS Location Updates not trigerred consistently in background mode

Requirement:
To Trigger Location update Callback after every second when the app is in background.
Problem:
Location Callbacks are not triggered after every second. Instead we get them inconsistently sometimes after 1 second, sometimes after 4 second and even with gap of 40-50 seconds.
Current Implementation:
setActivityType = CLActivityTypeOther
setAllowsBackgroundLocationUpdates = YES
setDesiredAccuracy = kCLLocationAccuracyBestForNavigation
setDistanceFilter = kCLDistanceFilterNone
setPausesLocationUpdatesAutomatically = false
plist configuration also done for background location updates.
Please suggest what more can be done to achieve solution for this problem?
Try out below code for background location updation when a significant location change is occured:
#pragma mark - CLLocationManager
- (void)startContinuosLocationUpdate
{
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
if (status == kCLAuthorizationStatusDenied)
{
NSLog(#"Location services are disabled in settings.");
}
else
{
// for iOS 8
if ([self.anotherLocationManager respondsToSelector:#selector(requestAlwaysAuthorization)])
{
[self.anotherLocationManager requestAlwaysAuthorization];
}
// for iOS 9
if ([self.anotherLocationManager respondsToSelector:#selector(setAllowsBackgroundLocationUpdates:)])
{
[self.anotherLocationManager setAllowsBackgroundLocationUpdates:YES];
}
[self.anotherLocationManager startUpdatingLocation];
}
}
- (void)stopContinuosLocationUpdate
{
[self.anotherLocationManager stopUpdatingLocation];
}
- (void)startMonitoringLocation
{
if (_anotherLocationManager)
[_anotherLocationManager stopMonitoringSignificantLocationChanges];
self.anotherLocationManager = [[CLLocationManager alloc]init];
_anotherLocationManager.delegate = self;
_anotherLocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
_anotherLocationManager.activityType = CLActivityTypeOtherNavigation;
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"9.0")) {
[_anotherLocationManager setAllowsBackgroundLocationUpdates:YES];
}
else if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0")) {
[_anotherLocationManager requestAlwaysAuthorization];
}
[_anotherLocationManager startMonitoringSignificantLocationChanges];
}
- (void)restartMonitoringLocation
{
[_anotherLocationManager stopMonitoringSignificantLocationChanges];
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"9.0")) {
[_anotherLocationManager setAllowsBackgroundLocationUpdates:YES];
}
else if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0")) {
[_anotherLocationManager requestAlwaysAuthorization];
}
[_anotherLocationManager startMonitoringSignificantLocationChanges];
}

How to get location for one time in ios

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];

iOS GPS Location Tracking

I am programming in Objective C on Xcode and seem to be having a problem when my app goes into the background. I have a GPS tracking app and it works fine when the user has the app running but when it goes in the background the GPS doesn't follow the user location step by step. It pauses and then when the app re-opens, it automatically finds the location but I want the GPS to be running all the time so it won't "go off road"1 like I have in the picture attached.
I have location updates and background fetch turned on already in background modes.
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations: (NSArray *)locations
{
if (!self.timerPause) {
for (CLLocation *newLocation in locations) {
NSDate *eventDate = newLocation.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if (fabs(howRecent) < 10.0 && newLocation.horizontalAccuracy < 20)
other code
if (self.locationManager == nil) {
self.locationManager = [[CLLocationManager alloc] init];
}
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.activityType = CLActivityTypeAutomotiveNavigation;
self.locationManager.distanceFilter = 10; // meters
if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[self.locationManager requestWhenInUseAuthorization];
}
[self.locationManager startUpdatingLocation];
locationManager.allowsBackgroundLocationUpdates = YES;
Add this where you have set up the location manager. It should work :)

iOS 8 : Mapkit error throws an : Must call -[CLLocationManager requestWhenInUseAuthorization]

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.

Resources