我正在构建一个在后台工作的iOS应用程序,并且每3分钟将用户的位置发布到服务器上(因为这是iOS 7上最大的后台执行时间)。然而,有一个问题,后台服务在随机时间终止。所以有时它可以在后台运行2小时,有时运行7小时,然后3小时随机地运行等等。
下面的代码会产生错误。我已经能够检测到它何时会终止,也就是当UIApplication sharedApplication.backgroundTimeRemaining小于10秒时。有谁能指出某个方向,或者解释它为什么要终止呢?我猜self.locationManager startUpdatingLocation不是100 %安全的吗?(以及使UIApplication sharedApplication.backgroundTimeRemaining无限的方法?)
这是我每3分钟在服务器上收到的“正常”日志;
iPhone 5: 21:06:45 backgroundTimeRemaining startUpdatingLocation: 11.014648
iPhone 5: 21:06:45 backgroundTimeRemaining startUpdatingLocation: 999.000000
iPhone 5: 21:06:48 backgroundTimeRemaining stopUpdatingLocation: 999.000000
iPhone 5: 21:06:48 backgroundTimeRemaining stopUpdatingLocation: 999.000000
守则:
#import "BetaLocationController.h"
#import "AppDelegate.h"
#import <Parse/Parse.h>
#import "CommunicationController.h"
@interface BetaLocationController () <CLLocationManagerDelegate>
@property UIBackgroundTaskIdentifier bgTask;
@property (strong, nonatomic) CLLocationManager *locationManager;
@property BOOL locationStarted;
@property (strong, nonatomic) CLLocation *myLocation;
@end
@implementation BetaLocationController
- (id)init
{
self = [super init];
if (self) {
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.pausesLocationUpdatesAutomatically = NO;
self.locationManager.activityType = CLActivityTypeOther;
self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation* location = [locations lastObject];
self.myLocation = location;
// NSLog(@"Location: %f, %f", location.coordinate.longitude, location.coordinate.latitude);
}
- (void)didEnterBackground:(NSNotification *) notification
{
[self runBackgroundTask:10];
}
-(void)runBackgroundTask: (int) time{
//check if application is in background mode
if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
//create UIBackgroundTaskIdentifier and create tackground task, which starts after time
__block UIBackgroundTaskIdentifier bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
// [self runBackgroundTask:5];
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSTimer *t = [NSTimer scheduledTimerWithTimeInterval:time target:self selector:@selector(startTrackingBg) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:t forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
});
}
}
-(void)startTrackingBg{
[[UIApplication sharedApplication] cancelAllLocalNotifications];
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
NSDate *now = [NSDate date];
localNotification.fireDate = now;
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"HHmm"];
int timeofDay = [[formatter stringFromDate:[NSDate date]] intValue];
localNotification.applicationIconBadgeNumber = timeofDay;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
//set default time
int time = 170;
//if locationManager is ON
if (self.locationStarted == TRUE ) {
//Here I can detect the error
if([UIApplication sharedApplication].backgroundTimeRemaining < 10){
[CommunicationController logToParse:[NSString stringWithFormat:@"%@ : Detected error, trying to restart locationservice", [UIDevice currentDevice].name]];
}
//log
[CommunicationController logToParse:[NSString stringWithFormat:@"%@: %@ bgTime before stopUpdatingLocation: %f", [UIDevice currentDevice].name, [NSDate date], [self getBackgroundTime]]];
[self.locationManager stopUpdatingLocation];
self.locationStarted = FALSE;
//log
[CommunicationController logToParse:[NSString stringWithFormat:@"%@: %@ bgTime after stopUpdatingLocation: %f", [UIDevice currentDevice].name, [NSDate date], [self getBackgroundTime]]];
}else{
//start updating location
//log
[CommunicationController logToParse:[NSString stringWithFormat:@"%@: %@ bgTime before startUpdatingLocation: %f", [UIDevice currentDevice].name, [NSDate date], [self getBackgroundTime]]];
[self.locationManager startUpdatingLocation];
self.locationStarted = TRUE;
//Time how long the application will update your location
time = 3;
//log
[CommunicationController logToParse:[NSString stringWithFormat:@"%@: %@ bgTime after startUpdatingLocation: %f", [UIDevice currentDevice].name, [NSDate date], [self getBackgroundTime]]];
}
[self runBackgroundTask:time];
}
-(float)getBackgroundTime{
float bgTime = [[UIApplication sharedApplication] backgroundTimeRemaining];
//If bgtime is over 180, it returns unlimited. In iOS 7, only 3 minutes backgroundtime is available
return bgTime > 180 ? 999 : bgTime;
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
[CommunicationController logToParse:[NSString stringWithFormat:@"%@: %@ LocationManagerDidFail %@: %f", [UIDevice currentDevice].name, [NSDate date], error, [[UIApplication sharedApplication] backgroundTimeRemaining]]];
NSLog(@"Error in locationManager. It Failed: %@", error);
}
-(void)dealloc {
[CommunicationController logToParse:[NSString stringWithFormat:@"%@: %@ got dealloc'ed", [UIDevice currentDevice].name, [NSDate date]]];
NSLog(@"Dealloc in location manager is called");
}
@end发布于 2014-02-07 12:35:28
一般情况下,你不能确定你的应用程序是否还能继续运行。用户可能希望主动终止它,或者系统可能需要您的应用程序正在使用的资源,从而终止它。我想您正在经历这个问题,因为资源的限制。
您可以通过使用在Background fetch中引入的iOS7来绕过它。操作系统将以正常的间隔允许您的应用程序再次启动。
试着阅读这篇描述特性的优秀文档:http://devstreaming.apple.com/videos/wwdc/2013/204xex2xvpdncz9kdb17lmfooh/204/204.pdf
但是,你不能阻止用户强迫你的应用程序关闭。
发布于 2014-05-06 22:52:26
不能在iOS7的后台启动位置服务。这就是它不一致的原因。你需要启动它,而应用程序在前台,并保持它。
发布于 2016-01-13 11:29:37
按照以下步骤获取处于后台模式的位置:

if(self.location==nil){
self.locationManager = [[CLLocationManager alloc] init];
}
[self.locationManager setDelegate:self];
if( [self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
{
[self.locationManager requestAlwaysAuthorization];
}
self.locationManager.distanceFilter = 10.0f;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.pausesLocationUpdatesAutomatically=NO;
self.locationManager.activityType=CLActivityTypeAutomotiveNavigation;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8) {
[self.locationManager requestAlwaysAuthorization];
}
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9) {
self.locationManager.allowsBackgroundLocationUpdates = YES;
}
[self.locationManager startUpdatingLocation];
https://stackoverflow.com/questions/21626504
复制相似问题