2013-02-24 40 views
2

我需要在应用程序转到后台时继续获取用户的位置更新,并且正如我在Apple的文档中发现的那样,这是允许执行的长时间运行的后台任务之一。我还需要进行一些处理和网络调用,以便在通知位置更新时向服务器发送一些信息。我正在试图做的,在广招,是这样的:了解iOS中用户位置的后台跟踪

- (void)applicationDidEnterBackground:(UIApplication *)application 
{ 
    bgTask = [application beginBackgroundTaskWithExpirationHandler:^{ 
     [application endBackgroundTask:bgTask]; 
     bgTask = UIBackgroundTaskInvalid; 
    }]; 

    // Background task   
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     NSLog(@"Background time remaining: %f seconds (%d mins)", 
    [[UIApplication sharedApplication] backgroundTimeRemaining], 
    (int)([[UIApplication sharedApplication] backgroundTimeRemaining]/60)); 

     // Need to get data from database here 

     // Finished 
     if (bgTask != UIBackgroundTaskInvalid) { 
     [application endBackgroundTask:bgTask]; 
     bgTask = UIBackgroundTaskInvalid; 
     } 

    }); 

    // Start location manager 
    locationManager = [[CLLocationManager alloc] init]; 
    if ([CLLocationManager locationServicesEnabled]) {   
     locationManager.delegate = self; 
     locationManager.distanceFilter = 20; 
     locationManager.desiredAccuracy = kCLLocationAccuracyBest; 
     [locationManager startUpdatingLocation]; 
    } 
} 

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation 
{ 
    bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ 
     [[UIApplication sharedApplication] endBackgroundTask:bgTask]; 
     bgTask = UIBackgroundTaskInvalid; 
    }]; 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

     // Want to perform some data processing here, including concurrent tasks 
     // and several network calls to get and send data to server 

     [self locationProcessingCompleted]; 

    }); 
} 

- (void)locationProcessingCompleted 
{ 
    // Check results. If needed, some more data processing and several network 
    // calls to send data to server 

    // Close background task 
    if (bgTask != UIBackgroundTaskInvalid) { 
     [[UIApplication sharedApplication] endBackgroundTask:bgTask]; 
     bgTask = UIBackgroundTaskInvalid; 
    } 
} 

我不`吨找到关于位置的服务的长期运行的后台任务的任何代码示例,我有一些关于它的几个问题:

一)是否有必要到dispatch_async队列中执行所有的后台代码?换句话说,applicationDidEnterBackground:中的所有代码都是异步执行的,包括位置管理器设置?

b)[[UIApplication sharedApplication] backgroundTimeRemaining]正在返回非常长的值。这次不应该在10分钟左右?

c)我想要做的是:执行初始有限长任务,开始位置更新,然后每次触发didUpdateToLocation:时执行一些其他有限长度的任务。我在Info.plist中设置了location的值UIBackgroundModes。我的方法是否正确?我是否会无限期地更新位置,然后在每次更新时,我可以执行长度不超过10分钟的有限长度任务吗?

请帮我解决这个问题。在此先感谢

回答

2

所有你需要做的是增加“应用程序注册了位置更新”下的“所需的背景模式”,您可以在文本编辑器或者编辑plist文件,并添加以下代码,也可以使用Xcode中添加所需的背景模式。

<key>UIBackgroundModes</key> 
<array> 
    <string>location</string> 
</array> 

didUpdateToLocation方法将被调用(即使您的应用程序在后台)。您可以在调用此方法的基础执行任何东西......

快照的Xcode

Snapshot of Xcode

+1

+1这是一个解决方案在iOS 6! – 2013-08-21 12:53:20

+0

这并没有解决原来的海报问题。设置UIBackgroundModes可以获得更新,但它不会让您有足够的处理时间来实际建立网络连接并进行实际工作。即使您在位置处理方法中创建了后台任务,backgroundTimeRemaining仍然是一个巨大的数字,表明它尚未设置。我的经验是我的后台操作在几秒钟内就被杀死了。 – 2013-10-01 23:18:45

+2

对不起,我不同意,我的一个应用程序在App Store上运行,它在后台位置更新(网络访问,数据操作和发送本地通知等)的基础上做了很多事情。我猜(可能是错误的)你的评论是基于假设/知识而不是这种特殊情况的经验,或者如果在类似情况下进行处理时遇到问题,你可能做错了什么。 – Zee 2013-10-02 12:39:02

0

的按照您在applicationDidEnterBackground分配的LocationManager您提供的代码,我想向您建议在didFinishLaunchingWithOptions方法中分配LocationManager,然后在applicationDidEnterBackground方法中调用startUpdatingLocation方法。

您可能还需要调用stopUpdatingLocation在applicationWillEnterForeground方法(如果您不需要接收位置更新时,应用程序是在前台)。

提示:不要启用与最佳精度的GPS很长一段时间,因为它会吃掉你的电池非常快(3至4小时内,按我的经验)。

+0

一个设计问题:如果我还想在前台应用程序中侦听位置更新并将它们显示在地图上,那么最好的方法是什么?我应该在'AppDelegate'中保存'locationManager'实例并以前台模式向viewControllers发送通知? – AppsDev 2013-03-12 09:49:02

+0

它是否需要在后台进行位置更新,在AppDelegate中拥有'locationManager'及其委托方法,还是有可能/正确/最好的解决方案,以使用另一个具有自己的'locationManager'和委托方法的类实例,以及那么让'AppDelegate'创建它? – AppsDev 2013-03-12 09:53:31

0

声明:我Cintric

我们也希望能够在后台(应用程序已被杀害即使)准确地跟踪用户位置的工作。我们花了很长时间解决了这个问题,特别是关注电池消耗。

我们发布了一篇关于如何解决这个问题的好博客文章。 http://www.blog.cintric.com/?p=121也提供免费的拖放SDK解决方案。使用一行代码,您可以不断跟踪背景中的位置并仅使用1%的电池。此外,您可以设置一个类为代理,以便您可以将信息发送到您的服务器(包括在后台而不必使用后台任务API)。

您也可以下载.framework文件,将其拖放到你的项目,并用一行代码初始化: [CintricFind initWithApiKey:@"YOUR_API_KEY_HERE" andSecret:@"YOUR_SECRET_HERE"];

你可以免费获得一个API密钥。有文件解释everythin在这里:https://www.cintric.com/docs/ios