在iOS 7中,应用程序似乎无法再从后台任务启动位置管理器(通过调用startUpdatingLocation)。
在iOS 6中,我使用了下面描述的方法:https://stackoverflow.com/a/6465280每n分钟运行一次后台位置更新。其想法是使用计时器运行后台任务,并在计时器触发时启动位置管理器。之后,关闭位置管理器并启动另一个后台任务。
更新到iOS 7后,这种方法不再有效。启动Location Manager后,应用程序不会收到任何locationManager:didUpdateLocations。有什么想法吗?
实现此功能的步骤如下:
>
添加位置更新的应用程序寄存器在项目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");
}
我试过你的方法,但对我来说不起作用。你能给我看看你的密码吗?
我实际上在iOS7中找到了解决位置服务问题的解决方案。
在iOS 7中,您无法在后台启动位置服务。如果你想让定位服务在后台继续运行,你必须在前台启动它,它将继续在后台运行。
如果你像我一样,停止定位服务,并在后台使用计时器重新启动它,它将无法在iOS7工作。
有关更多详细信息,您可以观看WWDC 2013的视频307的前8分钟:https://developer.apple.com/wwdc/videos/
更新:定位服务也可以在后台工作。请查看未在iOS 7中运行的后台位置服务,以获取在Github上发布的完整解决方案的更新帖子以及解释详细信息的博客帖子。
我找到了问题/解决办法。当该启动定位服务并停止后台任务时,后台任务应该延迟停止(我用了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