首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >从后台任务启动iOS 7中的位置管理器

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

Stack Overflow用户
提问于 2013-09-20 01:45:37
回答 3查看 29.4K关注 0票数 27

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

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

在更新到iOS 7后,这种方法不再起作用。启动位置管理器后,应用程序不会收到任何locationManager:didUpdateLocations。有什么想法吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-09-23 23:12:27

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

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

10月29日更新的 '16

有一个cocoapod APScheduledLocationManager,它允许每隔n秒获得一次后台位置更新,并获得所需的位置精度。

代码语言:javascript
运行
复制
let manager = APScheduledLocationManager(delegate: self)
manager.startUpdatingLocation(interval: 170, acceptableLocationAccuracy: 100)

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

更新日期:5月27日14日

Objective-C示例:

1)在".plist“文件中,将UIBackgroundModes设置为"location”。

2)在任意位置创建ScheduledLocationManager实例。

代码语言:javascript
运行
复制
@property (strong, nonatomic) ScheduledLocationManager *slm;

3)设置

代码语言:javascript
运行
复制
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)实现委托方法

代码语言:javascript
运行
复制
-(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的实现:

ScheduledLocationManager.h

代码语言:javascript
运行
复制
#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

ScheduledLocationManager.m

代码语言:javascript
运行
复制
#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
票数 43
EN

Stack Overflow用户

发布于 2013-09-27 13:55:16

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

实际上,我在iOS 7中找到了一个解决位置服务问题的方案。

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

如果你像我一样,停止定位服务,并使用计时器在后台重新启动它,它在iOS 7中将不起作用。

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

更新:定位服务也可以在后台中工作。请查看Background Location Services not working in iOS 7上发布的完整解决方案的更新帖子和解释详细信息的博客帖子。

票数 7
EN

Stack Overflow用户

发布于 2013-10-07 15:50:48

实现这一点的步骤如下:

  1. 在项目的info.plist中的“必需的后台模式”中的第0项中添加“位置更新的应用程序注册”。
  2. 在应用程序确实完成启动时编写以下代码。

[self selector:@selector(startFetchingLocationsContinously) object:nil];

  • Write NSNotificationCenter:self selector:@selector(startFetchingLocationsContinously) name:START_FETCH_LOCATION下面的代码是您想要开始跟踪的位置

[NSNotificationCenter defaultCenter postNotificationName:START_FETCH_LOCATION object:nil];AppDelegate *appDelegate = ( appDelegate *)[UIApplication sharedApplication delegate];appDelegate appDelegate跟随AppDelegate.m的代码

#杂注标记-位置更新-(空)startFetchingLocationsContinously{NSLog(@“开始获取位置”);self.locationUtil = [LocationUtil分配初始化];self.locationUtil setDelegate:自身;self.locationUtil startLocationManager;} -(void)locationRecievedSuccesfullyWithNewLocation:(CLLocation*)newLocation oldLocation:(CLLocation*)oldLocation{ NSLog(@"location在app代理中成功接收,经度:%f,经度:%f,高度:%f,垂直精度:%f",newLocation.coordinate.latitude,newLocation.coordinate.longitude,newLocation.altitude,newLocation.verticalAccuracy);} -(void)startUpdatingDataBase{ UIApplication* app = UIApplication sharedApplication;bgTask = UIBackgroundTaskInvalid;bgTask = [app #en1#bgTask:bgTask;}];selector:@selector(startFetchingLocationsContinously) = NSTimer scheduledTimerWithTimeInterval:300 target:self selector:@selector(startFetchingLocationsContinously) userInfo:nil repeats:YES;}

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

#import #import @CoreLocation @optional -(void)locationRecievedSuccesfullyWithNewLocation:(CLLocation*)newLocation oldLocation:(CLLocation*)oldLocation;-(空)addressParsedSuccessfully:( id )address;@end @interface LocationUtil : NSObject {}//属性@property (非原子,强)id委托;-(空)startLocationManager;

并将以下代码粘贴到LocationUtil.m中

-(void)startLocationManager{ locationManager = [CLLocationManager alloc ];locationManager.delegate = self;locationManager setPausesLocationUpdatesAutomatically:是;//Utkarsh 20pic2013 //locationManager setActivityType:CLActivityTypeFitness;locationManager.distanceFilter = kCLDistanceFilterNone;locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;locationManager startUpdatingLocation;//反向地理编码。geoCoder=[CLGeocoder分配初始化];//设置反向地理编码的默认值}//对于iOS<6 - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {//调用委托方法委托oldLocation:oldLocation;NSLog(@"did更新位置“);}//对于iOS>=6。- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { CLLocation *newLocation = locations objectAtIndex:0;CLLocation *oldLocation = locations objectAtIndex:0;delegate iOS<6 oldLocation:oldLocation;(@”did更新位置NSArray“);}

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18901583

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档