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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18946881/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 01:32:34  来源:igfitidea点击:

Background Location Services not working in iOS 7

iosobjective-cios7core-locationios-background-mode

提问by Alan Samet

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 下还需要做些什么才能使这项工作正常进行吗?

回答by Ricky

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

  2. Github Project: Background Location Update Programming for iOS 7 and 8

  1. iOS 7 和 8 的后台位置更新编程

  2. Github 项目:iOS 7 和 8 的后台位置更新编程

Methods and Explanation:-

方法和解释:-

  1. I restart the location manager every 1 minute in function didUpdateLocations

  2. I allow the location manager to get the locations from the device for 10 seconds before shut it down (to save battery).

  1. 我每 1 分钟在didUpdateLocations函数中重新启动位置管理器

  2. 我允许位置管理器在关闭设备之前从设备获取位置 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. 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. 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

2014 年 5 月更新:我收到了一些添加示例代码的请求,以便在特定时间间隔内将位置发送到服务器。我添加了示例代码,并结合了 BackgroundTaskManager 的修复程序,以解决后台长时间运行的故障。如果您有任何问题,欢迎您加入我们的讨论:iOS 7 后台位置更新编程与服务器位置更新讨论

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 应用程序的位置更新

回答by Obj-Swift

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. Please see the image,

如果您查看 WWDC 2013 Session video #204 - What's new with multitasking pdf,第 15 页清楚地提到,如果用户从应用程序切换器中删除应用程序,应用程序将不会在后台启动。请看图,

enter image description here

在此处输入图片说明

回答by Nikolay Tsenkov

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)
  2. Turn device's screen off to put the app in the background;
  3. Leave the device stationary (e.g. on a desk) for 30 min.
  1. 开始位置更新;(测试精度分别为10米和100米,各3次)
  2. 关闭设备的屏幕以将应用程序置于后台;
  3. 让设备静止(例如在桌子上)30 分钟。

The data I log shows the geo-updates stop coming after ~ 15m and 30s. With that all other background processing you do is also terminated.

我记录的数据显示地理更新在大约 15m 和 30s 后停止。您所做的所有其他后台处理也将终止。

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. Where getting geo updates with 100m accuracy used to give you pretty much continuous running in background.

我有 95% 的把握,iOS 6/6.1 并非如此。过去以 100m 的精度获取地理更新可以让您在后台连续运行。

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;
    }
}

回答by androidExplorer

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
  • the background grace period timeout was reduced from 10 minutes to 3 minutes
  • stopping location updates (via stopUpdatingLocation) will start the 3 minute backgroundTimeRemaining count down
  • starting location updates while already in the background will not reset the backgroundTimeRemaining
  • 一个应用程序必须已经在使用定位服务(startUpdatingLocation),然后才进入后台,以便有资格获得后台运行时间
  • 后台宽限期超时从 10 分钟减少到 3 分钟
  • 停止位置更新(通过 stopUpdatingLocation)将开始 3 分钟的 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 (e.g. 3 km) updates. It is important to do this in the foreground (in applicationDidEnterBackground is too late).
  • 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.
  • 当应用程序仍处于前台时,开始位置更新 (startUpdatingLocation),但将精度和距离过滤器设置为非常粗粒度的(例如 3 公里)更新。在前台执行此操作很重要(在 applicationDidEnterBackground 中为时已晚)。
  • 当需要细粒度分辨率时,临时设置精度和距离过滤器以获得最佳位置,然后将它们恢复为粗粒度值——但永远不要停止位置更新。
  • 由于位置更新始终处于启用状态,因此应用程序在进入后台时不会暂停。

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/

回答by Ricky

I found another thread Start Location Manager in iOS 7 from background taskSash mentioned that

从后台任务Sash 中发现另一个线程Start Location Manager in 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). Otherwise location service wont start.

我找到了问题/解决方案。当需要启动位置服务和停止后台任务时,应延迟停止后台任务(我设置为 1 秒)。否则定位服务不会启动。

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!

搜索高低后,我从苹果论坛找到了解决方案!

In iOS 7, you can not start the location service in background. 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.

在 iOS 7 中,您无法在后台启动位置服务。如果你想让定位服务一直在后台运行,你必须在前台启动它,它会继续在后台运行。

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. You may see the full answer here: Background Location Services not working in iOS 7

2014 年 2 月更新:经过几个月的尝试,我可以从使用 iOS 7 的设备连续获取位置。您可以在这里看到完整的答案:后台定位服务在 iOS 7 中不起作用

回答by Mr. Cobblepot

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.

我发现重要的位置更改已开启,但只是停止并重新启动服务(对于重大更改)并不会触发新位置。

回答by Tibin Thomas

You must set pausesLocationUpdatesAutomaticallyproperty of CLLocationManagerclass to falseto disable system from pausing the location updates.

您必须将class 的pausesLocationUpdatesAutomatically属性设置CLLocationManagerfalse以禁止系统暂停位置更新。