当前位置: 首页 > 知识库问答 >
问题:

iOS 7后台位置服务停止

孙绍辉
2023-03-14

我正在构建一个在后台工作的iOS应用程序,并每3分钟将用户的位置发布到服务器上(因为这是iOS 7上的最长后台执行时间)。但是,有一个问题,后台服务在随机时间终止。所以有时候它可以在后台运行2个小时,有时候7个小时,然后3个小时,然后是随机的,依此类推。

下面的代码产生错误。我已经能够检测到它何时终止,也就是[UIApplication sharedApplication]何时终止。剩余的背景时间低于10秒。有人能指出某个方向,或解释它为什么终止吗?我猜[self.locationManager startUpdatingLocation]不是100%安全的?(以及使[UIApplication sharedApplication].BackgroundTime保持不受限制的方法?)

这是我每3分钟在服务器上收到的“正常”日志;

iPhone5: 21:06:45背景时间启动前剩余更新位置: 11.014648

iPhone 5:21:06:45背景启动后剩余时间日期位置:999.000000

iPhone 5:21:06:48背景停止更新前剩余时间位置:999.000000

iPhone5: 21:06:48背景时间停止后剩余更新位置: 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

共有3个答案

百里京
2023-03-14

按照以下步骤在后台模式下获取位置:

编辑/添加您的代码:

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];
施同
2023-03-14

无法在iOS7中在后台启动位置服务。这就是为什么它是不一致的。你需要在应用程序处于前台时启动它,然后保持打开状态。

颜修为
2023-03-14

一般来说,你无法确定你的应用程序是否会保持活动状态。用户可能希望主动终止应用程序,或者系统可能需要您的应用程序正在使用的资源,因此终止应用程序。我猜您正遇到这个问题,因为资源有限。

您可以通过使用iOS7中引入的后台获取来绕过它。操作系统将定期允许您的应用程序再次启动。

试着阅读这篇描述功能的优秀文档:http://devstreaming.apple.com/videos/wwdc/2013/204xex2xvpdncz9kdb17lmfooh/204/204.pdf

但是,您不能阻止用户强制关闭您的应用程序

 类似资料:
  • 我的背景粘性服务是杀死奥利奥和更高的设备,任何解决方案,以获得位置的背景服务时,活动是在后台

  • 问题内容: 哪种方法更好,直接像这样执行 或通常在类内部声明? 问题答案: 在第二段代码中,必须在调用接口的方法之前先调用属性。 在第一段代码中,您可以直接访问接口方法。 因此,如果您知道每个方法调用都会花费cpu时间,则直接在类中实现它而不是将其作为属性将是有益的。 在这种情况下,您有1个引用,可以使用该引用访问LocationListener的方法 在这种情况下,您有2个引用,一个是 Back

  • 我正在努力为我的问题找到解决办法。问题是我试图在奥利奥中启动后台服务,以便检索位置。我看到了这一点:https://developer.android.com/about/versions/oreo/background-location-limits但我正在努力寻找解决办法。 当我启动Foreground服务时,我看到:(IllegalStateException:不允许启动服务)异常,因为我试

  • 为了创建一个位置跟踪系统(基于fusedlocationprovider),该系统必须跟踪一个人在特定时间段内的位置。 在特定的时间间隔内,需要广播位置,即使应用程序关闭,也不应终止服务。 我应该使用前台还是后台服务,或者两者结合使用,再加上一个解释会很有帮助。

  • 我想创建一个小应用程序,在后台记录数据。所以我试着用绑定服务。这很好,但如果我关闭应用程序,服务也会停止。< br >那么,我的问题是:使用即时服务来执行这一操作是不是一个好方法?当应用程序关闭时,我如何保持服务在后台运行(我也想在启动后启动它)?

  • 我目前正在编写一个应用程序,它依赖于位置跟踪,并将有关位置的数据发送到服务器。然而,问题是它必须24/7运行,目前我正在经历每2-3天发生一次的随机崩溃。为了让应用程序在后台持续运行,我在beginBackgroundTaskWithExpirationHandler方法的右边放置了一个NSTimer,它位于ApplicationIdentinterBackground方法的后面。计时器每分钟执行