我正在構建一個在後臺工作的iOS應用程序,並且每隔3分鐘將用戶的位置發佈到服務器(因爲這是iOS 7的最大後臺執行時間)。 但是,有一個問題,後臺服務在隨機時間終止。所以有時它可以在後臺運行2小時,有時可以運行7小時,然後3小時,隨機運行。iOS 7的背景位置服務停止
下面的代碼會產生錯誤。 我已經能夠檢測到當它將終止,那就是當[UIApplication sharedApplication] .backgroundTimeRemaining低於10秒。 任何人都可以指向某個方向,或解釋爲什麼它終止?我的猜測是[self.locationManager startUpdatingLocation]不是100%安全的? (以及使[UIApplication sharedApplication] .backgroundTimeRemaining unlimited?)的方法?)
這是我每3分鐘在服務器上收到的「正常」日誌;
iPhone 5:startUpdatingLocation前21:06:45 backgroundTimeRemaining:11.014648
iPhone 5:startUpdatingLocation之後21:06:45 backgroundTimeRemaining:999.000000
iPhone 5:stopUpdatingLocation前21時06分48秒backgroundTimeRemaining: 999.000000
iPhone 5:stopUpdatingLocation後,21時06分48秒backgroundTimeRemaining: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
感謝您的回答!但是,我不認爲這是一個資源問題,因爲我正在使用兩臺只安裝了應用程序並正在運行的測試電話 - 沒有其他應用程序。 但是,我會嘗試後臺獲取,因爲我的理解我無法知道什麼時候會被喚醒,而這取決於我自己的應用程序的用法? – kbjeppesen
這是正確的。根據Apple的文檔,如果你開始使用少量的時間,你的應用程序可能會啓動得更多。您也可以在Xcode組織者中查找crashlog。 (連接iPhone,在Xcode中選擇窗口 - >管理器,在左側窗格中選擇您的設備,然後單擊設備日誌) – EsbenB
我現在已經實現了後臺抓取,它的工作原理非常好!功耗顯着提高 - 我幾乎無法檢測到應用程序在後臺運行!然而,正如我們已經討論的那樣,缺點是我無法控制什麼時候會喚醒並聯系我的服務器 - 但這是一個可以接受的折衷!感謝你的回答! – kbjeppesen