2014-02-07 3 views
0

백그라운드에서 작동하는 iOS 앱을 만들고 3 분마다 사용자 위치를 서버에 게시합니다 (iOS 7의 최대 백그라운드 실행 시간 임). 그러나 한 가지 문제가 있습니다. 배경 서비스가 무작위로 종료됩니다. 때로는 백그라운드에서 2 시간, 때로는 7 시간, 그 다음에는 3 시간 동안 무작위로 실행됩니다.iOS 7 backround 위치 서비스 중지

아래 코드는 오류를 생성합니다. 이 종료 될 때이 표시되면 을 감지 할 수 있습니다. 즉, [UIApplication sharedApplication] .backgroundTimeRemaining이 10 초 미만입니다. 누군가가 어떤 방향으로 향하게 할 수 있습니까? 아니면 그것이 끝나는 이유를 설명 할 수 있습니까? 내 생각 엔 [self.locationManager startUpdatingLocation]이 100 % 안전하지 않습니까? (및 UIApplication sharedApplication .backgroundTimeRemaining을 무제한으로 만드는 방법)

다음은 3 분마다 서버에서받는 "정상적인"로그입니다.

아이폰 5 : startUpdatingLocation 전에 21시 6분 45초 backgroundTimeRemaining : 11.014648

아이폰 5 : startUpdatingLocation 후 21시 6분 45초 backgroundTimeRemaining : 999.000000

아이폰 5 : stopUpdatingLocation 전에 21시 6분 48초 backgroundTimeRemaining : 999.000000

아이폰 5 : stopUpdatingLocation 후 21시 6분 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 

답변

0

당신은 일반적으로 앱이 살아 유지됩니다 확신 할 수 없다. 사용자가 앱을 적극적으로 종료하거나 시스템에서 앱이 사용하는 리소스가 필요하므로 앱을 종료 할 수 있습니다. 리소스 제약으로 인해이 문제가 발생하는 것 같습니다.

iOS7에서 소개 된 Background fetch을 사용하면 주위를 둘러 볼 수 있습니다. 운영 체제는 정기적 인 간격으로 앱을 다시 시작할 수 있습니다. 당신은, 그러나, 앱을 닫습니다 힘에서 사용자를 막을 수 없습니다 http://devstreaming.apple.com/videos/wwdc/2013/204xex2xvpdncz9kdb17lmfooh/204/204.pdf

:

는 기능을 설명하는이 훌륭한 문서를 읽어보십시오.

+0

답장을 보내 주셔서 감사합니다. 하지만 리소스 문제라고는 생각하지 않습니다. 앱을 설치하고 실행하는 테스트 용 전화 두 대를 사용하기 때문에 다른 앱은 없습니다. 하지만 배경을 가져 오려고 노력할 것입니다. 내 이해로 언제 깨울 지 알 수 없으며, 내 응용 프로그램의 사용법에 달려 있습니까? – kbjeppesen

+0

맞습니다. Apple 설명서에 따르면, 시작 시간이 소량이라면 앱이 시작될 확률이 높습니다. 또한 Xcode Organizer에서 crashlog를 찾을 수도 있습니다. (iPhone을 연결하고, Xcode에서 창 -> 구성 도우미를 선택하고, 왼쪽 창에서 장치를 선택하고 장치 로그를 클릭하십시오.) – EsbenB

+0

이제 백그라운드 가져 오기가 구현되었으며 훨씬 더 효과적입니다! 전력 소비가 크게 향상되었습니다. 앱이 백그라운드에서 실행되고 있음을 거의 감지 할 수 없습니다! 그러나 우리가 논의한 것처럼 서버가 깨어서 서버에 접속할 때 제어 할 수 없다는 단점이 있습니다. 답변 해주셔서 감사합니다! – kbjeppesen

0

iOS7의 백그라운드에서 위치 서비스를 시작할 수 없습니다. 그것이 모순 된 이유입니다. 앱이 포 그라운드에있는 동안 앱을 시작해야합니다.

0

는 백그라운드 모드에서 위치를 얻기 위해 다음 단계를 수행

  1. 는 문자열 정보의 "위치"키에 "UIBackgroundModes"를 추가합니다.앱에서 PLIST 파일 enter image description here

  2. 편집/당신의 코드를 추가

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];

0
앱을 사용하면 위치 이후를 얻을 수 있습니다 이유가 일시 중단 모드에 이동합니다

그. 아래 URL을 확인하십시오. 그것은 당신에게 18 분 이상 위치를 알려줄 것입니다. 앱도 일시 중지 모드입니다.

nice post related to background service