Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I found the problem/solution. When it is time to start location service and stop background task, background task should be stopped with a delay (I used 1 second). Otherwise location service wont start. Also Location Service should be left ON for a couple of seconds (in my example it is 3 seconds).</p> <p>Another important notice, max background time in iOS 7 is now 3 minutes instead of 10 minutes. </p> <p><strong>Updated on October 29 '16</strong> </p> <p>There is a cocoapod <a href="https://github.com/paleksandrs/APScheduledLocationManager" rel="nofollow">APScheduledLocationManager</a> that allows to get background location updates every <em>n</em> seconds with desired location accuracy.</p> <pre><code>let manager = APScheduledLocationManager(delegate: self) manager.startUpdatingLocation(interval: 170, acceptableLocationAccuracy: 100) </code></pre> <p>The repository also contains an example app written in Swift 3.</p> <p><strong>Updated on May 27 '14</strong> </p> <p>Objective-C example:</p> <p>1) In ".plist" file set <code>UIBackgroundModes</code> to "location".</p> <p>2) Create instance of <code>ScheduledLocationManager</code> anywhere you want.</p> <pre><code>@property (strong, nonatomic) ScheduledLocationManager *slm; </code></pre> <p>3) Set it up</p> <pre><code>self.slm = [[ScheduledLocationManager alloc]init]; self.slm.delegate = self; [self.slm getUserLocationWithInterval:60]; // replace this value with what you want, but it can not be higher than kMaxBGTime </code></pre> <p>4) Implement delegate methods</p> <pre><code>-(void)scheduledLocationManageDidFailWithError:(NSError *)error { NSLog(@"Error %@",error); } -(void)scheduledLocationManageDidUpdateLocations:(NSArray *)locations { // You will receive location updates every 60 seconds (value what you set with getUserLocationWithInterval) // and you will continue to receive location updates for 3 seconds (value of kTimeToGetLocations). // You can gather and pick most accurate location NSLog(@"Locations %@",locations); } </code></pre> <p>Here is implementation of ScheduledLocationManager:</p> <p><strong>ScheduledLocationManager.h</strong></p> <pre><code>#import &lt;Foundation/Foundation.h&gt; #import &lt;CoreLocation/CoreLocation.h&gt; @protocol ScheduledLocationManagerDelegate &lt;NSObject&gt; -(void)scheduledLocationManageDidFailWithError:(NSError*)error; -(void)scheduledLocationManageDidUpdateLocations:(NSArray*)locations; @end @interface ScheduledLocationManager : NSObject &lt;CLLocationManagerDelegate&gt; -(void)getUserLocationWithInterval:(int)interval; @end </code></pre> <p><strong>ScheduledLocationManager.m</strong></p> <pre><code>#import "ScheduledLocationManager.h" int const kMaxBGTime = 170; // 3 min - 10 seconds (as bg task is killed faster) int const kTimeToGetLocations = 3; // time to wait for locations @implementation ScheduledLocationManager { UIBackgroundTaskIdentifier bgTask; CLLocationManager *locationManager; NSTimer *checkLocationTimer; int checkLocationInterval; NSTimer *waitForLocationUpdatesTimer; } - (id)init { self = [super init]; if (self) { locationManager = [[CLLocationManager alloc] init]; locationManager.delegate = self; locationManager.desiredAccuracy = kCLLocationAccuracyBest; locationManager.distanceFilter = kCLDistanceFilterNone; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil]; } return self; } -(void)getUserLocationWithInterval:(int)interval { checkLocationInterval = (interval &gt; kMaxBGTime)? kMaxBGTime : interval; [locationManager startUpdatingLocation]; } - (void)timerEvent:(NSTimer*)theTimer { [self stopCheckLocationTimer]; [locationManager startUpdatingLocation]; // in iOS 7 we need to stop background task with delay, otherwise location service won't start [self performSelector:@selector(stopBackgroundTask) withObject:nil afterDelay:1]; } -(void)startCheckLocationTimer { [self stopCheckLocationTimer]; checkLocationTimer = [NSTimer scheduledTimerWithTimeInterval:checkLocationInterval target:self selector:@selector(timerEvent:) userInfo:NULL repeats:NO]; } -(void)stopCheckLocationTimer { if(checkLocationTimer){ [checkLocationTimer invalidate]; checkLocationTimer=nil; } } -(void)startBackgroundTask { [self stopBackgroundTask]; bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ //in case bg task is killed faster than expected, try to start Location Service [self timerEvent:checkLocationTimer]; }]; } -(void)stopBackgroundTask { if(bgTask!=UIBackgroundTaskInvalid){ [[UIApplication sharedApplication] endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; } } -(void)stopWaitForLocationUpdatesTimer { if(waitForLocationUpdatesTimer){ [waitForLocationUpdatesTimer invalidate]; waitForLocationUpdatesTimer =nil; } } -(void)startWaitForLocationUpdatesTimer { [self stopWaitForLocationUpdatesTimer]; waitForLocationUpdatesTimer = [NSTimer scheduledTimerWithTimeInterval:kTimeToGetLocations target:self selector:@selector(waitForLoactions:) userInfo:NULL repeats:NO]; } - (void)waitForLoactions:(NSTimer*)theTimer { [self stopWaitForLocationUpdatesTimer]; if(([[UIApplication sharedApplication ]applicationState]==UIApplicationStateBackground || [[UIApplication sharedApplication ]applicationState]==UIApplicationStateInactive) &amp;&amp; bgTask==UIBackgroundTaskInvalid){ [self startBackgroundTask]; } [self startCheckLocationTimer]; [locationManager stopUpdatingLocation]; } #pragma mark - CLLocationManagerDelegate methods - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { if(checkLocationTimer){ //sometimes it happens that location manager does not stop even after stopUpdationLocations return; } if (self.delegate &amp;&amp; [self.delegate respondsToSelector:@selector(scheduledLocationManageDidUpdateLocations:)]) { [self.delegate scheduledLocationManageDidUpdateLocations:locations]; } if(waitForLocationUpdatesTimer==nil){ [self startWaitForLocationUpdatesTimer]; } } - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { if (self.delegate &amp;&amp; [self.delegate respondsToSelector:@selector(scheduledLocationManageDidFailWithError:)]) { [self.delegate scheduledLocationManageDidFailWithError:error]; } } #pragma mark - UIAplicatin notifications - (void)applicationDidEnterBackground:(NSNotification *) notification { if([self isLocationServiceAvailable]==YES){ [self startBackgroundTask]; } } - (void)applicationDidBecomeActive:(NSNotification *) notification { [self stopBackgroundTask]; if([self isLocationServiceAvailable]==NO){ NSError *error = [NSError errorWithDomain:@"your.domain" code:1 userInfo:[NSDictionary dictionaryWithObject:@"Authorization status denied" forKey:NSLocalizedDescriptionKey]]; if (self.delegate &amp;&amp; [self.delegate respondsToSelector:@selector(scheduledLocationManageDidFailWithError:)]) { [self.delegate scheduledLocationManageDidFailWithError:error]; } } } #pragma mark - Helpers -(BOOL)isLocationServiceAvailable { if([CLLocationManager locationServicesEnabled]==NO || [CLLocationManager authorizationStatus]==kCLAuthorizationStatusDenied || [CLLocationManager authorizationStatus]==kCLAuthorizationStatusRestricted){ return NO; }else{ return YES; } } @end </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload