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

从后台任务启动iOS 7中的位置管理器,ios,objective-c,ios7,core-location,cllocationmanager,Ios,Objective C,Ios7,Core Location,Cllocationmanager,在iOS 7中,应用程序似乎无法再从后台任务启动位置管理器(通过调用startUpdatingLocation) 在iOS6中,我使用了这里描述的方法:每n分钟运行一次后台位置更新。其想法是使用计时器运行后台任务,并在计时器触发时启动位置管理器。之后,关闭位置管理器并启动另一个后台任务 更新到iOS 7后,这种方法不再有效。启动Location Manager后,应用程序不会收到任何locationManager:didUpdateLocations。有什么想法吗 我找到了问题/解决方案。当启动

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

在iOS6中,我使用了这里描述的方法:每n分钟运行一次后台位置更新。其想法是使用计时器运行后台任务,并在计时器触发时启动位置管理器。之后,关闭位置管理器并启动另一个后台任务


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

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

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

于2016年10月29日更新

有一个cocoapod,允许每n秒以期望的位置精度获得背景位置更新

let manager = APScheduledLocationManager(delegate: self)
manager.startUpdatingLocation(interval: 170, acceptableLocationAccuracy: 100)
存储库还包含一个用Swift 3编写的示例应用程序

于2014年5月27日更新

目标C示例:

1) 在“.plist”文件中,将
ui背景模式设置为“位置”

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

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

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

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

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

有关更多详细信息,您可以观看WWDC 2013的前8分钟视频307:


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

实现此功能的步骤如下:

  • 在项目的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];
    
  • 将以下代码粘贴到AppDelegate.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;
    
    #导入
    #进口
    @协议位置成功接收
    @可选的
    -(void)Location ReceivedSuccessFullyWithNewLocation:(CLLocation*)newLocation oldLocation:(CLLocation*)oldLocation;
    -(void)地址解析成功:(id)地址;
    @结束
    @接口位置util:NSObject{
    }
    //性质
    @属性(非原子,强)id委托;
    -(无效)职业经理人;
    
    并将以下代码粘贴到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");
    }
    
    -(无效)startLocationManager{
    locationManager=[[CLLocationManager alloc]init];
    locationManager.delegate=self;
    [locationManager设置PausesLocationUpdates自动:是];//Utkarsh 20sep2013
    //[locationManager setActivityType:ClaActivityTypeFitness];
    locationManager.distanceFilter=KCLDistanceFilterOne;
    locationManager.desiredAccuracy=KCallocationAccuracyBestforNavigation;
    [locationManager startUpdatingLocation];
    //反向地理编码。
    地理编码器=[[CLGeocoder alloc]init];
    //设置反向地理编码的默认值。
    }
    //对于iOS=6。
    -(无效)位置管理器:(CLLocationManager*)管理器更新位置:(NSArray*)位置{
    CLLocation*newLocation=[locations objectAtIndex:0];
    CLLocation*oldLocation=[locations objectAtIndex:0];
    [代表位置ReceivedSuccessFullyWithNewLocation:newLocation oldLocation:oldLocation];
    NSLog(@“已更新位置”);
    }
    

  • 这似乎不起作用,很难理解
    getUserLocationWithInterval
    从未被调用?请发布一个工作示例。是否在应用程序委托中创建实例?您好,我在使用上述示例代码
    -[\uu NSDictionaryI applicationdidebecomeactive:]:无法识别的选择器已发送到实例0x14db5cf0
    请给出一些相关说明:)这非常有效,只需节省我的研发时间。谢谢您的帮助,+1:)谢谢发布此解决方案@sash@AskeAnker当您进行发布版本生成时,后台进程将停止。您好,如何在前台启动定位服务?我也有同样的问题。谢谢。你好,Guerrix,你可以在这里看到我的完整解决方案@Ricky如果我们想获得位置更新,即使通过双击主屏幕将应用程序从后台删除,该怎么办?@Azhar我听说即使应用程序被删除,也可以发送位置更新(不在前台或后台)从iOS 7.1开始,但我还没有找到可靠的解决方案。你说定位服务必须在前台启动?如果在进入后台后,我必须每隔15分钟获取一次用户的位置怎么办?我的iPhone电池很高兴地同意苹果不让应用程序这样做的决定:)哪里定义了“开始位置”?
    -(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");
    }