ios 应用程序进入后台后每 n 分钟获取一次用户位置
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10235203/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Getting user location every n minutes after app goes to background
提问by scurioni
I am trying to implement the suggestions given in this post.
我正在尝试实施这篇文章中给出的建议。
Unfortunately the steps are not clear to me. I tried implementing those suggestions, but the backgroundTimeRemaining continues to decrease even after I start and stop locationServices. This is how I developed it:
不幸的是,我不清楚这些步骤。我尝试实施这些建议,但即使在我启动和停止 locationServices 之后,backgroundTimeRemaining 仍在继续减少。我是这样开发的:
- (void)applicationDidEnterBackground:(UIApplication *)application {
UIApplication* app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task.
self.timer = nil;
[self initTimer];
});
}
initTimer:
初始化定时器:
- (void)initTimer {
// Create the location manager if this object does not
// already have one.
if (nil == self.locationManager)
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self.locationManager startMonitoringSignificantLocationChanges];
if (self.timer == nil) {
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.3
target:self
selector:@selector(checkUpdates:)
userInfo:nil
repeats:YES];
}
}
checkUpdates:
检查更新:
- (void)checkUpdates:(NSTimer *)timer{
UIApplication* app = [UIApplication sharedApplication];
double remaining = app.backgroundTimeRemaining;
if(remaining < 580.0) {
[self.locationManager startUpdatingLocation];
[self.locationManager stopUpdatingLocation];
[self.locationManager startMonitoringSignificantLocationChanges];
}
DbgLog(@"Reminaing %f", app.backgroundTimeRemaining);
}
Does anyone have a suggestion on what might be wrong in my code? Both initTimer and checkUpdates are being called, but only during for the background execution time (+- 10 Mins). I want the app to update the location every n minutes "forever".
有没有人对我的代码中可能有什么问题提出建议?initTimer 和 checkUpdates 都被调用,但仅限于后台执行时间(+- 10 分钟)。我希望应用程序“永远”每 n 分钟更新一次位置。
My app's UIBackgroundModes is set to location.
我的应用程序的 UIBackgroundModes 设置为位置。
UPDATE:
更新:
I am now resetting the timer on didUpdateToLocation and didFailWithError. But still the backgroundTimeRemaining keeps decreasing:
我现在正在重置 didUpdateToLocation 和 didFailWithError 上的计时器。但 backgroundTimeRemaining 仍然不断减少:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
NSLog(@"Did Update Location = %f / %f", [newLocation coordinate].latitude, [newLocation coordinate].longitude);
UIApplication* app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task.
[self initTimer];
});
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
[self.locationManager stopUpdatingLocation];
UIApplication* app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
[self initTimer];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task.
});
}
I am also invalidating the timer:
我也使计时器无效:
- (void)checkUpdates:(NSTimer *)timer{
UIApplication* app = [UIApplication sharedApplication];
double remaining = app.backgroundTimeRemaining;
if(remaining < 580.0 && remaining > 570.0) {
[self.timer invalidate];
self.timer = nil;
[self.locationManager startUpdatingLocation];
[self.locationManager stopUpdatingLocation];
}
DbgLog(@"*************************Checking for updates!!!!!!!!!!! Reminaing %f", app.backgroundTimeRemaining);
}
采纳答案by scurioni
After some days trying all possible solutions I was finally able to make it work. Here is what was wrong in my solution:
经过几天尝试所有可能的解决方案,我终于能够使它工作。这是我的解决方案中的错误:
- I need to setup 2UIBackgroundTaskIdentifiers, one for the timer, and another one for the locationManager
- 我需要设置2 个UIBackgroundTaskIdentifiers,一个用于计时器,另一个用于 locationManager
On my solution, just add:
在我的解决方案中,只需添加:
UIApplication *app = [UIApplication sharedApplication];
bgTask2 = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask2];
bgTask2 = UIBackgroundTaskInvalid; }];
self.locationManager.delegate = self;
[self.locationManager startUpdatingLocation];
回答by HelmiB
To anyone else having a nightmare of a time trying to figure this one out, I have a simple solution.
对于那些在尝试解决这个问题时做噩梦的人,我有一个简单的解决方案。
- Study the example from raywenderlich.com. The sample code works perfectly, but unfortunately there's no timer during background location. This will run indefinitely.
Add timer by using this code snippet:
-(void)applicationDidEnterBackground { [self.locationManager stopUpdatingLocation]; UIApplication* app = [UIApplication sharedApplication]; bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ [app endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }]; self.timer = [NSTimer scheduledTimerWithTimeInterval:intervalBackgroundUpdate target:self.locationManager selector:@selector(startUpdatingLocation) userInfo:nil repeats:YES]; }
Just don't forget to add "App registers for location updates" in info.plist.
- 研究来自raywenderlich.com的示例。示例代码运行良好,但不幸的是在后台定位期间没有计时器。这将无限期运行。
使用以下代码片段添加计时器:
-(void)applicationDidEnterBackground { [self.locationManager stopUpdatingLocation]; UIApplication* app = [UIApplication sharedApplication]; bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ [app endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }]; self.timer = [NSTimer scheduledTimerWithTimeInterval:intervalBackgroundUpdate target:self.locationManager selector:@selector(startUpdatingLocation) userInfo:nil repeats:YES]; }
只是不要忘记在 info.plist 中添加“应用程序注册位置更新”。
回答by jsd
Once you're in the background you can only have 10 minutes of additional time. There is no way to extend that. You should use the location background services instead.
进入后台后,您只能有 10 分钟的额外时间。没有办法扩展它。您应该改用位置后台服务。
回答by Hari R Krishna
Working Code(Entire Stepwise Code)Modified scurioni's code
工作代码(Entire Stepwise Code)修改了 scurioni 的代码
Step 1
第1步
- Go to project -> Capabilities -> Background Modes -> select Location updates.
- Go to Project -> Info -> add a key NSLocationAlwaysUsageDescription with an optional string.
- 转到项目 -> 功能 -> 背景模式 -> 选择位置更新。
- 转到 Project -> Info -> 使用可选字符串添加键 NSLocationAlwaysUsageDescription。
Step 2
第2步
Add this code to AppDelegate.m
将此代码添加到 AppDelegate.m
@interface AppDelegate ()<CLLocationManagerDelegate>
@property (strong, nonatomic) CLLocationManager *locationManager;
@property (strong, nonatomic) NSTimer *timer;
@end
Step 3Add This Code in to applicationDidEnterBackgroundmethod in AppDelegate.m
步骤 3将此代码添加到AppDelegate.m 中的applicationDidEnterBackground方法中
- (void)applicationDidEnterBackground:(UIApplication *)application {
UIApplication *app = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier bgTaskId =
[app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTaskId];
bgTaskId = UIBackgroundTaskInvalid;
}];
dispatch_async( dispatch_get_main_queue(), ^{
self.timer = nil;
[self initTimer];
[app endBackgroundTask:bgTaskId];
bgTaskId = UIBackgroundTaskInvalid;
});
}
- (void)initTimer {
if (nil == self.locationManager)
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self.locationManager requestAlwaysAuthorization];
[self.locationManager startMonitoringSignificantLocationChanges];
if (self.timer == nil) {
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.3
target:self
selector:@selector(checkUpdates:)
userInfo:nil
repeats:YES];
}
}
- (void)checkUpdates:(NSTimer *)timer{
UIApplication *app = [UIApplication sharedApplication];
double remaining = app.backgroundTimeRemaining;
if(remaining < 580.0) {
[self.locationManager startUpdatingLocation];
[self.locationManager stopUpdatingLocation];
[self.locationManager startMonitoringSignificantLocationChanges];
}
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
NSLog(@"Did Update Location = %f / %f", [newLocation coordinate].latitude, [newLocation coordinate].longitude);
[self updateLocationWithLatitude:[newLocation coordinate].latitude andLongitude:[newLocation coordinate].longitude];
UIApplication* app = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier bgTask =
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self initTimer];
});
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
[self.locationManager stopUpdatingLocation];
UIApplication *app = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier bgTask =
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
[self initTimer];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task
});
}
-(void)updateLocationWithLatitude:(CLLocationDegrees)latitude
andLongitude:(CLLocationDegrees)longitude{
//Here you can update your web service or back end with new latitude and longitude
}