我正在寻找一种方法来获得背景位置更新每n分钟在我的iOS应用程序。我使用的是iOS 4.3,解决方案应该适用于未越狱的iphone。

我尝试/考虑了以下选项:

CLLocationManager startUpdatingLocation/startMonitoringSignificantLocationChanges: This works in the background as expected, based on the configured properties, but it seems not possible to force it to update the location every n minutes NSTimer: Does work when the app is running in the foreground but doesn't seem to be designed for background tasks Local notifications: Local notifications can be scheduled every n minutes, but it's not possible to execute some code to get the current location (without the user having to launch the app via the notification). This approach also doesn't seem to be a clean approach as this is not what notifications should be used for. UIApplication:beginBackgroundTaskWithExpirationHandler: As far as I understand, this should be used to finish some work in the background (also limited in time) when an app is moved to the background rather than implementing "long-running" background processes.

如何实现这些定期的后台位置更新?


当前回答

在苹果开发者论坛的帮助下,我找到了一个解决方案:

指定位置背景模式 在后台用UIApplication:beginBackgroundTaskWithExpirationHandler创建一个NSTimer: 当n小于UIApplication: backgroundtimerremain时,它会正常工作。当n较大时,应该在没有剩余时间之前再次启用(并禁用)位置管理器,以避免后台任务被终止。

这是因为位置是三种允许的后台执行类型之一。

注意:我在模拟器中测试了一些时间,在那里它不起作用。不过,它在我的手机上运行得很好。

其他回答

if ([self.locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) {
    [self.locationManager setAllowsBackgroundLocationUpdates:YES];
}

自iOS 9以来,这是后台位置跟踪所需要的。

在iOS 9和watchOS 2.0中,CLLocationManager上有一个新方法,可以让你请求当前位置:CLLocationManager:requestLocation()。这立即完成,然后将位置返回给CLLocationManager委托。

你现在可以使用NSTimer每分钟用这个方法请求一个位置,而不必使用startUpdatingLocation和stopUpdatingLocation方法。

然而,如果你想要根据上次位置X米的变化来捕获位置,只需要设置CLLocationManger的distanceFilter属性并调用startUpdatingLocation()。

I did this in an application I'm developing. The timers don't work when the app is in the background but the app is constantly receiving the location updates. I read somewhere in the documentation (i can't seem to find it now, i'll post an update when i do) that a method can be called only on an active run loop when the app is in the background. The app delegate has an active run loop even in the bg so you dont need to create your own to make this work. [Im not sure if this is the correct explanation but thats how I understood from what i read]

首先,在应用的info.plist中添加关键UIBackgroundModes的location对象。现在,你需要做的是启动位置更新在你的应用程序的任何地方:

    CLLocationManager locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self;//or whatever class you have for managing location
    [locationManager startUpdatingLocation];

Next, write a method to handle the location updates, say -(void)didUpdateToLocation:(CLLocation*)location, in the app delegate. Then implement the method locationManager:didUpdateLocation:fromLocation of CLLocationManagerDelegate in the class in which you started the location manager (since we set the location manager delegate to 'self'). Inside this method you need to check if the time interval after which you have to handle the location updates has elapsed. You can do this by saving the current time every time. If that time has elapsed, call the method UpdateLocation from your app delegate:

NSDate *newLocationTimestamp = newLocation.timestamp;
NSDate *lastLocationUpdateTiemstamp;

int locationUpdateInterval = 300;//5 mins

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
if (userDefaults) {

        lastLocationUpdateTiemstamp = [userDefaults objectForKey:kLastLocationUpdateTimestamp];

        if (!([newLocationTimestamp timeIntervalSinceDate:lastLocationUpdateTiemstamp] < locationUpdateInterval)) {
            //NSLog(@"New Location: %@", newLocation);
            [(AppDelegate*)[UIApplication sharedApplication].delegate didUpdateToLocation:newLocation];
            [userDefaults setObject:newLocationTimestamp forKey:kLastLocationUpdateTimestamp];
        }
    }
}

这将每5分钟调用你的方法,即使你的应用程序是在后台。 Imp:这个实现耗尽电池,如果你的位置数据的准确性不是关键,你应该使用[locationManager startMonitoringSignificantLocationChanges]

在将此添加到应用程序之前,请阅读位置感知编程指南

我确实写了一个使用位置服务的应用程序,应用程序必须每10秒发送位置。 而且效果很好。

只需使用“allowdeferredlocationupdatesuntiltravelled:timeout”方法,遵循苹果的文档。

我所做的是:

必需:注册后台模式更新位置。

1. 创建LocationManger和startUpdatingLocation,精度和filteredDistance为任何你想要的:

-(void) initLocationManager    
{
    // Create the manager object
    self.locationManager = [[[CLLocationManager alloc] init] autorelease];
    _locationManager.delegate = self;
    // This is the most important property to set for the manager. It ultimately determines how the manager will
    // attempt to acquire location and thus, the amount of power that will be consumed.
    _locationManager.desiredAccuracy = 45;
    _locationManager.distanceFilter = 100;
    // Once configured, the location manager must be "started".
    [_locationManager startUpdatingLocation];
}

2. 在后台使用allowdeferredlocationupdatesuntilmoved:timeout方法让应用永远运行,当应用移到后台时,你必须用新参数重新启动updatingLocation,就像这样:

- (void)applicationWillResignActive:(UIApplication *)application {
     _isBackgroundMode = YES;

    [_locationManager stopUpdatingLocation];
    [_locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
    [_locationManager setDistanceFilter:kCLDistanceFilterNone];
    _locationManager.pausesLocationUpdatesAutomatically = NO;
    _locationManager.activityType = CLActivityTypeAutomotiveNavigation;
    [_locationManager startUpdatingLocation];
 }

3.应用程序获得updatedLocations正常与locationManager:didUpdateLocations: callback:

-(void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
//  store data
    CLLocation *newLocation = [locations lastObject];
    self.userLocation = newLocation;

   //tell the centralManager that you want to deferred this updatedLocation
    if (_isBackgroundMode && !_deferringUpdates)
    {
        _deferringUpdates = YES;
        [self.locationManager allowDeferredLocationUpdatesUntilTraveled:CLLocationDistanceMax timeout:10];
    }
}

4. 但是你应该在locationManager:didFinishDeferredUpdatesWithError: callback中处理数据

- (void) locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error {

     _deferringUpdates = NO;

     //do something 
}

5. 注意:我认为每次应用程序在后台/前台模式之间切换时,我们应该重置LocationManager的参数。

在苹果开发者论坛的帮助下,我找到了一个解决方案:

指定位置背景模式 在后台用UIApplication:beginBackgroundTaskWithExpirationHandler创建一个NSTimer: 当n小于UIApplication: backgroundtimerremain时,它会正常工作。当n较大时,应该在没有剩余时间之前再次启用(并禁用)位置管理器,以避免后台任务被终止。

这是因为位置是三种允许的后台执行类型之一。

注意:我在模拟器中测试了一些时间,在那里它不起作用。不过,它在我的手机上运行得很好。