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

从后台任务启动iOS 7中的位置管理器

徐洋
2023-03-14

在iOS 7中,应用程序似乎无法再从后台任务启动位置管理器(通过调用startUpdatingLocation)。

在iOS 6中,我使用了下面描述的方法:https://stackoverflow.com/a/6465280每n分钟运行一次后台位置更新。其想法是使用计时器运行后台任务,并在计时器触发时启动位置管理器。之后,关闭位置管理器并启动另一个后台任务。

更新到iOS 7后,这种方法不再有效。启动Location Manager后,应用程序不会收到任何locationManager:didUpdateLocations。有什么想法吗?

共有3个答案

殷德本
2023-03-14

实现此功能的步骤如下:

>

  • 添加位置更新的应用程序寄存器在项目info.plist中的所需背景模式的第0项中。

    在应用程序未完成启动时编写以下代码。

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(startFetchingLocationsContinously) name:START_FETCH_LOCATION object:nil];
    

    从您希望开始跟踪的位置编写以下代码

    [[NSNotificationCenter defaultCenter] postNotificationName:START_FETCH_LOCATION object:nil];
    
    AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
                [appDelegate startUpdatingDataBase];
    

    将以下代码粘贴到App委托. m

    #pragma mark - Location Update
    -(void)startFetchingLocationsContinously{
        NSLog(@"start Fetching Locations");
        self.locationUtil = [[LocationUtil alloc] init];
        [self.locationUtil setDelegate:self];
        [self.locationUtil startLocationManager];
    }
    
    -(void)locationRecievedSuccesfullyWithNewLocation:(CLLocation*)newLocation oldLocation:(CLLocation*)oldLocation{
        NSLog(@"location received successfullly in app delegate for Laitude: %f and Longitude:%f, and Altitude:%f, and Vertical Accuracy: %f",newLocation.coordinate.latitude,newLocation.coordinate.longitude,newLocation.altitude,newLocation.verticalAccuracy);
    }
    
    -(void)startUpdatingDataBase{
        UIApplication*    app = [UIApplication sharedApplication];
    
        bgTask = UIBackgroundTaskInvalid;
    
        bgTask = [app beginBackgroundTaskWithExpirationHandler:^(void){
            [app endBackgroundTask:bgTask];
        }];
    
        SAVE_LOCATION_TIMER =  [NSTimer scheduledTimerWithTimeInterval:300
                                                                target:self selector:@selector(startFetchingLocationsContinously) userInfo:nil repeats:YES];
    }
    

    添加名为“LocationUtil”的类,并将以下代码粘贴到头文件中:

    #import <Foundation/Foundation.h>
    #import <CoreLocation/CoreLocation.h>
    @protocol LocationRecievedSuccessfully <NSObject>
    @optional
    -(void)locationRecievedSuccesfullyWithNewLocation:(CLLocation*)newLocation oldLocation:(CLLocation*)oldLocation;
    -(void)addressParsedSuccessfully:(id)address;
    
    @end
    @interface LocationUtil : NSObject <CLLocationManagerDelegate> {
    }
    
    //Properties
    @property (nonatomic,strong) id<LocationRecievedSuccessfully> delegate;
    -(void)startLocationManager;
    

    并将以下代码粘贴到LocationUtil中。M

    -(void)startLocationManager{
    
         locationManager = [[CLLocationManager alloc] init];
         locationManager.delegate = self;
         [locationManager setPausesLocationUpdatesAutomatically:YES]; //Utkarsh 20sep2013
         //[locationManager setActivityType:CLActivityTypeFitness];
         locationManager.distanceFilter = kCLDistanceFilterNone;
         locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
         [locationManager startUpdatingLocation];
    
         //Reverse Geocoding.
         geoCoder=[[CLGeocoder alloc] init];
    
        //set default values for reverse geo coding.
    }
    
    //for iOS<6
    - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
      //call delegate Method
      [delegate locationRecievedSuccesfullyWithNewLocation:newLocation oldLocation:oldLocation];
    
      NSLog(@"did Update Location");
    }
    
    //for iOS>=6.
    
    - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
    
      CLLocation *newLocation = [locations objectAtIndex:0];
      CLLocation *oldLocation = [locations objectAtIndex:0];
    
      [delegate locationRecievedSuccesfullyWithNewLocation:newLocation oldLocation:oldLocation];
      NSLog(@"did Update Locationsssssss");
    }
    

  • 戚均
    2023-03-14

    我试过你的方法,但对我来说不起作用。你能给我看看你的密码吗?

    我实际上在iOS7中找到了解决位置服务问题的解决方案。

    在iOS 7中,您无法在后台启动位置服务。如果你想让定位服务在后台继续运行,你必须在前台启动它,它将继续在后台运行。

    如果你像我一样,停止定位服务,并在后台使用计时器重新启动它,它将无法在iOS7工作。

    有关更多详细信息,您可以观看WWDC 2013的视频307的前8分钟:https://developer.apple.com/wwdc/videos/

    更新:定位服务也可以在后台工作。请查看未在iOS 7中运行的后台位置服务,以获取在Github上发布的完整解决方案的更新帖子以及解释详细信息的博客帖子。

    王才
    2023-03-14

    我找到了问题/解决办法。当该启动定位服务并停止后台任务时,后台任务应该延迟停止(我用了1秒)。否则定位服务将无法启动。此外,位置服务应该保持打开几秒钟(在我的例子中是3秒)。

    另一个重要的注意事项是,iOS 7的最大后台时间现在是3分钟,而不是10分钟。

    更新日期:2016年10月29日

    有一个cocoapod APScheduledLocationManager,它允许每隔n秒以所需的位置精度获取背景位置更新。

    let manager = APScheduledLocationManager(delegate: self)
    manager.startUpdatingLocation(interval: 170, acceptableLocationAccuracy: 100)
    

    存储库还包含一个用Swift 3编写的示例应用程序

    更新日期:2014年5月27日

    目标C示例:

    1)在. plist文件中,将UIBackground Modes设置为位置。

    2) 在需要的任何位置创建ScheduledLocationManager的实例。

    @property (strong, nonatomic) ScheduledLocationManager *slm;
    

    3) 设置它

    self.slm = [[ScheduledLocationManager alloc]init];
    self.slm.delegate = self;
    [self.slm getUserLocationWithInterval:60]; // replace this value with what you want, but it can not be higher than kMaxBGTime
    

    4) 实现委托方法

    -(void)scheduledLocationManageDidFailWithError:(NSError *)error
    {
        NSLog(@"Error %@",error);
    }
    
    -(void)scheduledLocationManageDidUpdateLocations:(NSArray *)locations
    {
        // You will receive location updates every 60 seconds (value what you set with getUserLocationWithInterval)
        // and you will continue to receive location updates for 3 seconds (value of kTimeToGetLocations).
        // You can gather and pick most accurate location
        NSLog(@"Locations %@",locations);
    }
    

    以下是ScheduledLocationManager的实现:

    #########################################################################################

    #import <Foundation/Foundation.h>
    #import <CoreLocation/CoreLocation.h>
    
    @protocol ScheduledLocationManagerDelegate <NSObject>
    
    -(void)scheduledLocationManageDidFailWithError:(NSError*)error;
    -(void)scheduledLocationManageDidUpdateLocations:(NSArray*)locations;
    
    @end
    
    @interface ScheduledLocationManager : NSObject <CLLocationManagerDelegate>
    
    -(void)getUserLocationWithInterval:(int)interval;
    
    @end
    

    下载位置管理器

    #import "ScheduledLocationManager.h"
    
    int const kMaxBGTime = 170; // 3 min - 10 seconds (as bg task is killed faster)
    int const kTimeToGetLocations = 3; // time to wait for locations
    
    @implementation ScheduledLocationManager
    {
        UIBackgroundTaskIdentifier bgTask;
        CLLocationManager *locationManager;
        NSTimer *checkLocationTimer;
        int checkLocationInterval;
        NSTimer *waitForLocationUpdatesTimer;
    }
    
    - (id)init
    {
        self = [super init];
        if (self) {
            locationManager = [[CLLocationManager alloc] init];
            locationManager.delegate = self;
            locationManager.desiredAccuracy = kCLLocationAccuracyBest;
            locationManager.distanceFilter = kCLDistanceFilterNone;
    
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
        }
        return self;
    }
    
    -(void)getUserLocationWithInterval:(int)interval
    {
        checkLocationInterval = (interval > kMaxBGTime)? kMaxBGTime : interval;
        [locationManager startUpdatingLocation];
    }
    
    - (void)timerEvent:(NSTimer*)theTimer
    {
        [self stopCheckLocationTimer];
        [locationManager startUpdatingLocation];
    
        // in iOS 7 we need to stop background task with delay, otherwise location service won't start
        [self performSelector:@selector(stopBackgroundTask) withObject:nil afterDelay:1];
    }
    
    -(void)startCheckLocationTimer
    {
        [self stopCheckLocationTimer];
        checkLocationTimer = [NSTimer scheduledTimerWithTimeInterval:checkLocationInterval target:self selector:@selector(timerEvent:) userInfo:NULL repeats:NO];
    }
    
    -(void)stopCheckLocationTimer
    {
        if(checkLocationTimer){
            [checkLocationTimer invalidate];
            checkLocationTimer=nil;
        }
    }
    
    -(void)startBackgroundTask
    {
        [self stopBackgroundTask];
        bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
            //in case bg task is killed faster than expected, try to start Location Service
            [self timerEvent:checkLocationTimer];
        }];
    }
    
    -(void)stopBackgroundTask
    {
        if(bgTask!=UIBackgroundTaskInvalid){
            [[UIApplication sharedApplication] endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        }
    }
    
    -(void)stopWaitForLocationUpdatesTimer
    {
        if(waitForLocationUpdatesTimer){
            [waitForLocationUpdatesTimer invalidate];
            waitForLocationUpdatesTimer =nil;
        }
    }
    
    -(void)startWaitForLocationUpdatesTimer
    {
        [self stopWaitForLocationUpdatesTimer];
        waitForLocationUpdatesTimer = [NSTimer scheduledTimerWithTimeInterval:kTimeToGetLocations target:self selector:@selector(waitForLoactions:) userInfo:NULL repeats:NO];
    }
    
    - (void)waitForLoactions:(NSTimer*)theTimer
    {
        [self stopWaitForLocationUpdatesTimer];
    
        if(([[UIApplication sharedApplication ]applicationState]==UIApplicationStateBackground ||
            [[UIApplication sharedApplication ]applicationState]==UIApplicationStateInactive) &&
           bgTask==UIBackgroundTaskInvalid){
            [self startBackgroundTask];
        }
    
        [self startCheckLocationTimer];
        [locationManager stopUpdatingLocation];
    }
    
    #pragma mark - CLLocationManagerDelegate methods
    
    - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
    {
        if(checkLocationTimer){
            //sometimes it happens that location manager does not stop even after stopUpdationLocations
            return;
        }
    
        if (self.delegate && [self.delegate respondsToSelector:@selector(scheduledLocationManageDidUpdateLocations:)]) {
            [self.delegate scheduledLocationManageDidUpdateLocations:locations];
        }
    
        if(waitForLocationUpdatesTimer==nil){
            [self startWaitForLocationUpdatesTimer];
        }
    }
    
    - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
    {
        if (self.delegate && [self.delegate respondsToSelector:@selector(scheduledLocationManageDidFailWithError:)]) {
            [self.delegate scheduledLocationManageDidFailWithError:error];
        }
    }
    
    #pragma mark - UIAplicatin notifications
    
    - (void)applicationDidEnterBackground:(NSNotification *) notification
    {
        if([self isLocationServiceAvailable]==YES){
            [self startBackgroundTask];
        }
    }
    
    - (void)applicationDidBecomeActive:(NSNotification *) notification
    {
        [self stopBackgroundTask];
        if([self isLocationServiceAvailable]==NO){
            NSError *error = [NSError errorWithDomain:@"your.domain" code:1 userInfo:[NSDictionary dictionaryWithObject:@"Authorization status denied" forKey:NSLocalizedDescriptionKey]];
    
            if (self.delegate && [self.delegate respondsToSelector:@selector(scheduledLocationManageDidFailWithError:)]) {
                [self.delegate scheduledLocationManageDidFailWithError:error];
            }
        }
    }
    
    #pragma mark - Helpers
    
    -(BOOL)isLocationServiceAvailable
    {
        if([CLLocationManager locationServicesEnabled]==NO ||
           [CLLocationManager authorizationStatus]==kCLAuthorizationStatusDenied ||
           [CLLocationManager authorizationStatus]==kCLAuthorizationStatusRestricted){
            return NO;
        }else{
            return YES;
        }
    }
    
    @end
    
     类似资料:
    • 这是我遇到的问题,与设计和实现相关: 我有一个接受 POST 请求的 REST Web 服务。没什么特别的。它当前以同步方式响应。 但是,此web服务将启动一个后台进程,这可能需要很长时间。 我不希望此服务在 30 分钟后响应。 相反,它应该立即向客户端返回一个ack响应,仅此而已(即使在30分钟后,也不会有更多的信息要发送)。 我如何在泽西实施这种行为? 我读了那一页https://jersey

    • 问题内容: 我有一个Django网站,并且一个页面上有一个按钮(或链接),单击该按钮将启动一个运行时间较长的任务。显然,我想将此任务作为后台任务启动,并立即将结果返回给用户。我想使用一种简单的方法来实现此目的,该方法不需要我安装和学习例如Celery这样的全新消息传递体系结构。我不想用celery!我只想使用一种简单的方法,就可以在接下来的半小时左右的时间内进行设置并开始运行。在Django中没有

    • windows phone 8.1应用程序中的计时器后台任务仅在应用程序从visual Studio以调试模式运行时激发。但是,如果我在没有调试的情况下启动debug binary,它就不能工作,15分钟后,几个小时后都不能工作。我在windows Phone8.1模拟器和nokia Lumia920上测试了它--同样的结果:在调试会话中它可以工作(它由系统触发,我可以从调试位置工具栏手动触发),

    • 我是flink的新手,我部署了我的flink应用程序,它基本上执行简单的模式匹配。它部署在库伯内特斯集群中,具有1个JM和6个TM。我每10分钟向eventhub主题发送大小4.4k和200k消息并执行负载测试。我添加了重启策略和检查点,如下所示,我没有在代码中显式使用任何状态,因为没有要求 最初,我遇到了网络缓冲区的Netty服务器问题,我遵循了以下链接https://ci.apache.org

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

    • 说明 在后台任务中,因为是运行在task进程,所以无法使用协程和协程客户端。如果你要操作数据库或Redis,一定要配置同步的连接池。 配置 项目配置文件中mainServer.configs.task_worker_num一定要配置为大于0,否则无法使用后台任务。 定义任务执行类 <?php namespace Test; use Imi\Task\TaskParam; use Imi\Task