【问题标题】:Background Location Services not working in iOS 7后台定位服务在 iOS 7 中不起作用
【发布时间】:2013-09-27 14:51:41
【问题描述】:

我最近升级了我的 iOS 设备以使用 iOS 7。我们正在开发的一个应用程序使用后台定位服务来跟踪设备位置,我们所有的测试人员都报告说该应用程序似乎不再在iOS 7 下的背景。

我们已验证该应用的后台功能已在设备的设置中启用,并且之前的版本在 iOS 6 下可以完美运行。即使设备被循环使用,该应用也会在位置更新后重新启动。

在 iOS 7 下是否还需要做其他事情才能完成这项工作?

【问题讨论】:

    标签: ios objective-c ios7 core-location ios-background-mode


    【解决方案1】:

    您必须将CLLocationManagerclass 的pausesLocationUpdatesAutomatically 属性设置为false,以禁止系统暂停位置更新。

    【讨论】:

      【解决方案2】:

      这是我用来从 iOS 7 设备获取连续位置的解决方案,无论它是在前台还是后台。

      您可以从博客和 github 中找到完整的解决方案和解释:-

      1. Background Location Update Programming for iOS 7 and 8

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

      方法及说明:-

      1. 我在函数 didUpdateLocations

      2. 中每 1 分钟重新启动一次位置管理器
      3. 我允许位置管理器在设备关机前从设备获取位置 10 秒(以节省电池)。

      部分代码如下:-

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

      2014 年 5 月更新:我收到了一些请求,要求在特定时间间隔内将位置发送到服务器时添加示例代码。我已经添加了示例代码,并且还结合了 BackgroundTaskManager 的修复程序,以解决后台长时间运行的故障。如果您有任何问题,欢迎在这里加入我们的讨论:Background Location Update Programming for iOS 7 with Location Update to Server Discussion

      2015 年 1 月更新:如果您想在应用暂停的情况下获取位置更新,请参阅:Get Location Updates for iOS App Even when Suspended

      【讨论】:

      • iOS 7.1 的更新不需要这些变通办法,对吗?
      • 我不确定。我没有在 iOS 7.1 上尝试过旧的解决方案。有时间我会测试一下。
      • @Ricky 如果我们使用后台获取机制在应用程序不运行时唤醒它会怎样?我不知道苹果是否可以接受使用 BackgroundFetch 来获取位置详细信息。
      • @Ricky Hey Rickey 我喜欢你的代码,我下载并测试了你的 github 项目,但是你能添加一个关于将你的代码添加到其他人的项目的教程吗?
      • 我爱你 :) 我有你下载的代码并使用了你的类,我的 AppDelegate 几乎没有变化。它的工作就像一个魅力非常感谢你
      【解决方案3】:

      我的一个 iOS 应用需要定期向服务器发送位置更新,以下方法对我们有用....

      从 iOS 7 开始:

      • 应用必须已经在使用定位服务 (startUpdatingLocation) 在后台之前 符合后台运行时间的条件
      • 后台宽限期超时从 10 分钟减少到 3 分钟 分钟
      • 停止位置更新(通过 stopUpdatingLocation)将启动 3 分钟 backgroundTimeRemaining 倒计时
      • 在后台启动位置更新不会 重置 backgroundTimeRemaining

      因此,不要随时停止位置更新...相反,更喜欢使用必要的精度(精细位置与粗略位置)。粗略的位置不会消耗太多电池...因此此解决方案可以解决您的问题。

      在网上搜索了很多,找到了一个链接,提供了一个iOS 7可行的解决方案。解决方案如下:

      • 当应用程序仍在前台时,开始位置更新 (startUpdatingLocation) 但将精度和距离过滤器设置为 非常粗略(例如 3 公里)的更新。这样做很重要 在前台(在 applicationDidEnterBackground 中为时已晚)。
      • 当需要细粒度的分辨率时,临时设置 精度和距离过滤器以获得最佳位置,以及 然后将它们恢复为粗粒度的值——但永远不要停止 位置更新。
      • 因为始终启用位置更新,所以应用程序将无法获取 进入后台时暂停。

      并确保将以下内容添加到应用程序的 Info.plist UIBackgroundModes 键的“位置” UIRequiredDeviceCapabilities 键的“位置服务”和“gps”

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

      【讨论】:

        【解决方案4】:

        我发现另一个线程Start Location Manager in iOS 7 from background taskSash 提到了

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

        任何人都可以尝试并验证吗?

        Nikolay,你能把你的代码贴在这里吗?我尝试每 8 分钟重新启动一次位置管理器,但它没有连续运行。

        更新:

        搜索了High和Low后,我从苹果论坛找到了解决方案!

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

        如果你像我一样,停止定位服务并使用计时器在后台重新启动它,它不会工作。

        更多详细信息,您可以观看 WWDC 2013 的前 8 分钟视频 307:https://developer.apple.com/wwdc/videos/

        2014 年 2 月更新: 经过几个月的尝试,我可以从使用 iOS 7 的设备连续获取位置。你可以在这里看到完整的答案:Background Location Services not working in iOS 7

        【讨论】:

        • 对不起,我没有看到这个线程有任何进展(为什么不给我发电子邮件,stackoverflow?)。我在前台启动它。尽管如此,我还是在后台重新启动它,每 8 分钟一次。
        • 你说的“后台重启”是指调用startUpdatingLocation/stopUpdatingLocation吗?
        • 对不起各位,你能帮我知道如何在前台启动定位服务吗?我需要做什么?我真的很感激你的帮助。谢谢
        • 我们可以在应用进入后台时更改所需的精度或距离过滤器吗?
        • 伙计们,在尝试了许多不同类型的解决方案两个多月之后。我发现了一种非常好的解决方案,它每小时消耗的电池电量不到 5%。我将在几天后与大家分享解决方案。
        【解决方案5】:

        我认为他们进行了优化(可能使用运动传感器),以检测手机的“相对”静止位置并停止位置更新。这只是一个猜测,但我的测试目前显示:

        1. 开始位置更新; (测试精度为 10 米和 100 米,各 3 次)
        2. 关闭设备屏幕以将应用置于后台;
        3. 让设备静止不动(例如放在桌子上)30 分钟。

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

        我的设备是装有 iOS 7 的 iPhone 5。

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

        更新

        如果您每 8 分钟重新启动一次位置管理器,它应该会连续运行。

        更新 #2

        我最近没有对此进行测试,但这是我在写这篇文章时重新启动它的方式。我希望这会有所帮助。

        - (void)tryRestartLocationManager
        {
            NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
        
            int seconds = round(floor(now - locationManagerStartTimestamp));
        
            if ( seconds > (60 * 8) ) {
                [locationManager stopUpdatingLocation];
                [locationManager startUpdatingLocation];
                locationManagerStartTimestamp = now;
            }
        }
        

        【讨论】:

        • 这似乎与我观察到的一致。只要我移动应用程序就会保持活动状态,但如果我长时间静止不动,就像 CoreLocation 会忽略 pausesLocationUpdatesAutomatically 设置并且永远不会恢复。
        • 没错。如果它停止更新,就像它们永远不会恢复一样。
        • @NikolayTsenkov 你能发布一个代码 sn-p 吗?我发现如果我在后台重新启动位置管理器,当backgroundTimeRemaining 达到零时,任务最终会被终止。
        • @NikolayTsenkov,感谢您的提示。我每分钟重新启动一次位置管理器,该应用程序能够连续报告我们用户的位置。但是,我发现使用这种方法,手机电池耗尽的速度比预期的要快.. 即在更改之前,我们的测试手机(iPhone 5、4S)可以从早上 8 点运行到晚上 10 点,更改后,电池在 4 点耗尽: 00pm...这与您的结果相同吗?
        • 我的测试显示 AccuracyBest 每小时 10%,AccuracyHundredMeters 每小时 5%。用 iPhone 5 测试。
        【解决方案6】:

        如果您观看 WWDC 2013 会议视频 #204 - What's new with multitasking pdf,第 15 页清楚地提到如果用户从应用切换器中终止应用,应用将不会在后台启动。请看图,

        【讨论】:

        • 直到下次重启
        【解决方案7】:

        状态栏上的图标是否打开?我也有这种奇怪的行为。 检查我的问题:startMonitoringSignificantLocationChanges but after some time didUpdateLocations is not called anymore

        我发现重大位置更改已启用,但只是停止并重新启动服务(对于重大更改)并没有触发新位置。

        【讨论】:

          猜你喜欢
          • 2014-03-04
          • 1970-01-01
          • 2013-12-30
          • 2017-11-09
          • 2014-10-09
          相关资源
          最近更新 更多