简体   繁体   English

后台位置服务在iOS 7中不起作用

[英]Background Location Services not working in iOS 7

I've recently upgraded my iOS devices to use iOS 7. One of the apps that we're developing uses background location services to track device location and all of our testers have reported that the app no longer appears to track in the background under iOS 7. 我最近升级了我的iOS设备以使用iOS 7.我们正在开发的其中一个应用程序使用后台位置服务来跟踪设备位置,我们所有的测试人员都报告该应用程序不再出现在iOS下的后台跟踪7。

We have verified that backgrounding for the app is enabled in the settings on the device and the previous build worked flawlessly under iOS 6. Even if the device were cycled, the app would restart after a location update. 我们已经确认在设备上的设置中启用了应用程序的后台处理,并且之前的版本在iOS 6下运行良好。即使设备已循环,应用程序也会在位置更新后重新启动。

Is there something else that needs to be done to make this work under iOS 7? 还有什么需要做才能在iOS 7下完成这项工作吗?

Here is the solution that I used to get continuous location from iOS 7 devices no matter it is in foreground or background. 这是我用来从iOS 7设备获得连续位置的解决方案,无论它是在前景还是后台。

You may find the full solution and explanation from blog and also github:- 您可以从博客和github找到完整的解决方案和解释: -

  1. Background Location Update Programming for iOS 7 and 8 iOS 7和8的后台位置更新编程

  2. Github Project: Background Location Update Programming for iOS 7 and 8 Github项目:iOS 7和8的后台位置更新编程

Methods and Explanation:- 方法和说明: -

  1. I restart the location manager every 1 minute in function didUpdateLocations 我在函数didUpdateLocations中每1分钟重新启动一次位置管理器

  2. I allow the location manager to get the locations from the device for 10 seconds before shut it down (to save battery). 我允许位置管理员在关闭之前从设备获取位置10秒(以节省电池电量)。

Partial Code Below:- 以下部分代码: -

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{

for(int i=0;i<locations.count;i++){
    CLLocation * newLocation = [locations objectAtIndex:i];
    CLLocationCoordinate2D theLocation = newLocation.coordinate;
    CLLocationAccuracy theAccuracy = newLocation.horizontalAccuracy;
    NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];

    if (locationAge > 30.0)
        continue;

    //Select only valid location and also location with good accuracy
    if(newLocation!=nil&&theAccuracy>0
       &&theAccuracy<2000
       &&(!(theLocation.latitude==0.0&&theLocation.longitude==0.0))){
        self.myLastLocation = theLocation;
        self.myLastLocationAccuracy= theAccuracy;
        NSMutableDictionary * dict = [[NSMutableDictionary alloc]init];
        [dict setObject:[NSNumber numberWithFloat:theLocation.latitude] forKey:@"latitude"];
        [dict setObject:[NSNumber numberWithFloat:theLocation.longitude] forKey:@"longitude"];
        [dict setObject:[NSNumber numberWithFloat:theAccuracy] forKey:@"theAccuracy"];
        //Add the vallid location with good accuracy into an array
        //Every 1 minute, I will select the best location based on accuracy and send to server
        [self.shareModel.myLocationArray addObject:dict];
    }
}

//If the timer still valid, return it (Will not run the code below)
if (self.shareModel.timer)
    return;

self.shareModel.bgTask = [BackgroundTaskManager sharedBackgroundTaskManager];
[self.shareModel.bgTask beginNewBackgroundTask];

//Restart the locationMaanger after 1 minute
self.shareModel.timer = [NSTimer scheduledTimerWithTimeInterval:60 target:self
                                                       selector:@selector(restartLocationUpdates)
                                                       userInfo:nil
                                                        repeats:NO];

//Will only stop the locationManager after 10 seconds, so that we can get some accurate locations
//The location manager will only operate for 10 seconds to save battery
NSTimer * delay10Seconds;
delay10Seconds = [NSTimer scheduledTimerWithTimeInterval:10 target:self
                                                selector:@selector(stopLocationDelayBy10Seconds)
                                                userInfo:nil
                                                 repeats:NO];
 }

Update on May 2014 : I got a few requests for adding sample codes on sending the location to server for a certain time interval. 2014年5月更新 :我收到一些请求,要求在将位置发送到服务器一定时间间隔时添加示例代码。 I have added the sample codes and also combined a fix for BackgroundTaskManager to solve a glitch for background running over an extended period of time. 我已经添加了示例代码,并结合了BackgroundTaskManager的修复程序,以解决在较长时间内运行的后台故障。 If you have any questions, you are welcomed to join us for a discussion here: Background Location Update Programming for iOS 7 with Location Update to Server Discussion 如果您有任何疑问,欢迎您加入我们的讨论: iOS7的后台位置更新编程,服务器讨论的位置更新

Update on January 2015 : If you want to get the location update even when the app is suspended, please see: Get Location Updates for iOS App Even when Suspended 2015年1月更新 :如果您想要在应用程序暂停时获取位置更新 ,请参阅: 获取iOS应用程序的位置更新,即使已暂停

If you look at WWDC 2013 Session video #204 - What's new with multitasking pdf, page number 15 clearly mentions that apps wont launch in the background if user kills it from the app switcher. 如果你看看WWDC 2013会议视频#204 - 多任务处理的新功能pdf,第15页清楚地提到,如果用户从应用程序切换器中杀死应用程序,应用程序将无法在后台启动。 Please see the image, 请看图片,

在此输入图像描述

I think they made an optimization (probably using motion sensors), to detect "relatively" stationary positioning of the phone and they stop the location updates. 我认为他们进行了优化(可能使用运动传感器),以检测手机的“相对”固定位置,并停止位置更新。 This is only a speculation, but my tests currently show: 这只是一个推测,但我的测试目前显示:

  1. Starting location updates; 开始位置更新; (tested with accuracy of 10 and 100 meters, 3 times each) (测试精度为10和100米,每次3次)
  2. Turn device's screen off to put the app in the background; 关闭设备屏幕,将应用程序置于后台;
  3. Leave the device stationary (eg on a desk) for 30 min. 将设备静止(例如放在桌子上)30分钟。

The data I log shows the geo-updates stop coming after ~ 15m and 30s. 我记录的数据显示地理更新在约15分钟和30秒后停止。 With that all other background processing you do is also terminated. 您所做的所有其他后台处理也会终止。

My device is iPhone 5 with iOS 7. 我的设备是带有iOS 7的iPhone 5。

I am 95% sure, this wasn't the case on iOS 6/6.1. 我95%肯定,这不是iOS 6 / 6.1的情况。 Where getting geo updates with 100m accuracy used to give you pretty much continuous running in background. 如果获得100米精度的地理更新,可以让您在后台连续运行。

Update 更新

If you restart the location manager every 8 minutes, it should run continuously. 如果每8分钟重新启动一次位置管理器,它应该连续运行。

Update #2 更新#2

I haven't tested this in latest, but this is how I restarted it when I wrote the post. 我最近没有对此进行测试,但这是我在撰写帖子时重新启动它的方法。 I hope this is helpful. 我希望这是有帮助的。

- (void)tryRestartLocationManager
{
    NSTimeInterval now = [[NSDate date] timeIntervalSince1970];

    int seconds = round(floor(now - locationManagerStartTimestamp));

    if ( seconds > (60 * 8) ) {
        [locationManager stopUpdatingLocation];
        [locationManager startUpdatingLocation];
        locationManagerStartTimestamp = now;
    }
}

One of my iOS app needs to send location update to server at regular intervals and following approach worked for us.... 我的一个iOS应用程序需要定期向服务器发送位置更新,并且以下方法适用于我们....

Starting in iOS 7: 从iOS 7开始:

  • an app must have already been using location services (startUpdatingLocation) BEFORE having been backgrounded in order for the eligible for background run time 应用程序必须已经使用位置服务(startUpdatingLocation)之前已经背景化以便符合条件的后台运行时间
  • the background grace period timeout was reduced from 10 minutes to 3 minutes 后台宽限期超时从10分钟减少到3分钟
  • stopping location updates (via stopUpdatingLocation) will start the 3 minute backgroundTimeRemaining count down 停止位置更新(通过stopUpdatingLocation)将启动3分钟backgroundTimeRemaining倒计时
  • starting location updates while already in the background will not reset the backgroundTimeRemaining 已经在后台启动位置更新将不会重置backgroundTimeRemaining

So, DO NOT STOP the location updates anytime...Instead, prefer to use the necessary accuracy (fine location vs coarse location). 所以,不要随时停止位置更新......而是更喜欢使用必要的精度(精确位置与粗略位置)。 Coarse location does not consume much battery...so this solution solves your problem. 粗糙的位置不会消耗太多电池......所以这个解决方案可以解决您的问题。

After much searching online, found a link which provide a viable solution for iOS 7. The solution is as follows: 经过大量的在线搜索,找到了一个为iOS 7提供可行解决方案的链接。解决方案如下:

  • While the app is still in the foreground, start location updates (startUpdatingLocation) but set the accuracy and distance filters to very course-grained (eg 3 km) updates. 当应用程序仍处于前台时,启动位置更新(startUpdatingLocation),但将精度和距离过滤器设置为非常粗略(例如3 km)的更新。 It is important to do this in the foreground (in applicationDidEnterBackground is too late). 在前台执行此操作非常重要(在applicationDidEnterBackground中为时已晚)。
  • When a fine-grained resolution is required, temporarily set the accuracy and distance filters to get the best possible location, and then revert them back to the course-grained values – but never stop location updates. 当需要细粒度分辨率时,临时设置精度和距离过滤器以获得最佳位置,然后将它们恢复为粗粒度值 - 但永远不要停止位置更新。
  • Because location updates are always enabled, the app will not get suspended when it goes to the background. 由于始终启用位置更新,因此应用程序在进入后台时不会被暂停。

And make sure you add the following to your application's Info.plist “location” to the UIBackgroundModes key “location-services” and “gps” to the UIRequiredDeviceCapabilities key 并确保将以下内容添加到应用程序的Info.plist“location”中,将UIBackgroundModes键“location-services”和“gps”添加到UIRequiredDeviceCapabilities键

Credits: http://gooddevbaddev.wordpress.com/2013/10/22/ios-7-running-location-based-apps-in-the-background/ 致谢: http//gooddevbaddev.wordpress.com/2013/10/22/ios-7-running-location-based-apps-in-the-background/

I found another thread Start Location Manager in iOS 7 from background task Sash mentioned that 在后台任务 Sash中提到了另一个在iOS 7中启动位置管理器的线程

I found the problem/solution. 我发现了问题/解决方案。 When it is time to start location service and stop background task, background task should be stopped with a delay (I set 1 second). 当需要启动位置服务并停止后台任务时,应该延迟后台任务(我设置1秒)。 Otherwise location service wont start. 否则位置服务不会启动。

Can anyone try that and verify? 任何人都可以尝试并验证?

Nikolay, can you paste your code here? 尼古拉,你能在这里粘贴你的代码吗? I tried to restart the location manager every 8 minutes but it does not run continuously. 我试图每8分钟重新启动一次位置管理器,但它不会连续运行。

Update: 更新:

After searching High and Low, I found the Solution from Apple Forum! 在搜索了High and Low之后,我从Apple Forum找到了解决方案!

In iOS 7, you can not start the location service in background . 在iOS 7中,您无法在后台启动位置服务 If you want the location service to keep running in the background, you have to start it in foreground and it will continue to run in the background. 如果您希望位置服务在后台继续运行,则必须在前台启动它,它将继续在后台运行。

If you were like me, stop the location service and use timer to re-start it in the background, it will NOT work. 如果你像我一样,停止位置服务并使用计时器在后台重新启动它,它将无法正常工作。

For more detailed information, you can watch the first 8 minutes of video 307 from WWDC 2013: https://developer.apple.com/wwdc/videos/ 有关更多详细信息,您可以观看WWDC 2013中视频307的前8分钟: https//developer.apple.com/wwdc/videos/

Feb 2014 Update: I can get the location continuously from device using iOS 7 after several months of trying. 2014年2月更新:经过几个月的尝试,我可以在使用iOS 7的设备上连续获取该位置。 You may see the full answer here: Background Location Services not working in iOS 7 您可以在此处看到完整的答案: 后台位置服务在iOS 7中不起作用

Is the icon on the status bar turned on? 状态栏上的图标是否已打开? It's a strange behaviour I had too. 这也是一种奇怪的行为。 Check my question: startMonitoringSignificantLocationChanges but after some time didUpdateLocations is not called anymore 检查我的问题: startMonitoringSignificantLocationChanges但是在一段时间之后不再调用didUpdateLocations

I discovered that the significant location changes was on but simply stopping and restarting the service (for significant changes) was not firing new locations. 我发现重要的位置更改已经开启,但只是停止并重新启动服务(进行重大更改)并未触发新位置。

必须将CLLocationManager类的pausesLocationUpdatesAutomatically属性设置为false才能禁止系统暂停位置更新。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM