在iOS 7中,应用程序似乎不能再从后台任务启动位置管理器(通过调用startUpdatingLocation)。
在iOS 6中,我使用了这里描述的方法:https://stackoverflow.com/a/6465280来每n分钟运行一次后台位置更新。这个想法是用一个定时器运行后台任务,并在定时器触发它时启动位置管理器。之后,关闭位置管理器并启动另一个后台任务。
在更新到iOS 7后,这种方法不再起作用。启动位置管理器后,应用程序不会收到任何locationManager:didUpdateLocations。有什么想法吗?
发布于 2013-09-23 23:12:27
我找到了问题/解决方案。当启动定位服务并停止后台任务时,后台任务需要延迟停止(我用了1秒)。否则定位服务将无法启动。此外,位置服务应该保持打开几秒钟(在我的示例中是3秒)。
另一个重要的注意事项是,iOS 7中的最大后台时间现在是3分钟,而不是10分钟。
10月29日更新的 '16
有一个cocoapod APScheduledLocationManager,它允许每隔n秒获得一次后台位置更新,并获得所需的位置精度。
let manager = APScheduledLocationManager(delegate: self)
manager.startUpdatingLocation(interval: 170, acceptableLocationAccuracy: 100)
该存储库还包含一个用Swift 3编写的示例应用程序。
更新日期:5月27日14日
Objective-C示例:
1)在".plist“文件中,将UIBackgroundModes
设置为"location”。
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的实现:
ScheduledLocationManager.h
#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
#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
发布于 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上发布的完整解决方案的更新帖子和解释详细信息的博客帖子。
发布于 2013-10-07 15:50:48
实现这一点的步骤如下:
[self selector:@selector(startFetchingLocationsContinously) object:nil];
[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;}
#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“);}
https://stackoverflow.com/questions/18901583
复制相似问题