在屏幕打开之前,重要的位置更改将不起作用

significantLocationChanges will not work until screen is turned on

我正在通过重新启动应用程序的后台 API 测试位置更新。我已经成功地测试了访问和区域,并且正在使用同一个应用程序来测试 significantLocationChanges (SLC)。我 运行 我的应用程序,按两次主页然后将其关闭以将其关闭。然后我开车兜风。我可以在不通过服务器接触 phone 的情况下观察应用程序背景 activity,其中(参见下面的代码)单例方法 sendBackgroundTestRecord 将简单的状态消息上传到服务器。

当我测试访问和区域时,我没有遇到任何问题。但是,当我测试 SLC 时,直到我打开 phone 的屏幕(按一次电源或主屏幕按钮——而不是重新 运行 应用程序,甚至解锁 phone).我可以开很远的距离而不会发生任何事情。我怀疑该应用程序在该驱动器的某个时间收到了 SLC 事件,因为只要我打开 phone 大约 2 秒,下面的代码就会执行,我可以观察到服务器上的消息。

我相信这不仅仅是网络连接延迟,因为 sendBackgrounTestRecord 方法使用了时间戳。服务器上的记录显示我打开屏幕的时间戳,而不是 SLC 事件被怀疑触发的时间。

我从来没有遇到过访问或区域问题,只有 SLC。顺便说一句,代码已经经历了许多更改以试图解决这个问题。最近的尝试(下面的代码)是将所有内容都放在 appDelegate 中。

有什么想法吗? 提前感谢任何想法!

编辑:我添加了 beginBackgroundTaskWithExpirationHandler,这也在我最初的测试中。

//  AppDelegate.h

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate, CLLocationManagerDelegate>
  @property (strong, nonatomic) UIWindow *window;
  @property (strong, nonatomic) CLLocationManager *locationManager;
@end



//  AppDelegate.m

#import "AppDelegate.h"
#import "clsCommon.h"
@interface AppDelegate ()
@end
@implementation AppDelegate

  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

//Ask iOS for more time to process - before we do anything else
  [clsCommon sharedInstance].backgroundTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{}];

    [[clsCommon sharedInstance] sendBackgroundTestRecord:@"didFinishLaunchingWithOptions"];

    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;
    if([self.locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) {
      [self.locationManager setAllowsBackgroundLocationUpdates:YES];
    }
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
    self.locationManager.distanceFilter = kCLDistanceFilterNone;
    self.locationManager.activityType = CLActivityTypeAutomotiveNavigation;
    self.locationManager.allowsBackgroundLocationUpdates = YES;
    self.locationManager.pausesLocationUpdatesAutomatically = NO;
    if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
      [self.locationManager requestAlwaysAuthorization];
    }

    [self.locationManager startMonitoringSignificantLocationChanges];

    return YES;
  }


  - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
    [[clsCommon sharedInstance] sendBackgroundTestRecord:@"didUpdateLocations"];
    CLLocation * currentLocation = [locations objectAtIndex:0];
    if(currentLocation !=nil) {
      [[clsCommon sharedInstance] sendBackgroundTestRecord:@"didUpdateLocations curLoc not nill"];
   }

 }

@end

self.locationManager.distanceFilter中留出一些距离,更利于更换电池self.locationManager.pausesLocationUpdatesAutomatically=YES;

Start Location Manager in iOS 7 from background task

好吧,知道 iOS 如何积极地解决所有有利于电池寿命的权衡,我不会感到非常惊讶。例如,"breadcrumbs" 应用程序的行为(在您当前位置设置 100 米地理围栏,在退出事件时将该地理围栏移动到新位置)非常不同,具体取决于 iPhone 是否一直在您的口袋里睡觉,或者你偶尔检查锁屏。

但是,运行昨天在回家的路上使用了一个与您的非常相似的应用程序确实为我生成了位置更新。

SLC 读数之间的距离在 4 到 14 公里范围内,两个后续读数之间的最小时间间隔 - 14 分钟。该应用程序与您的应用程序非常相似,它不包含任何网络部分,只是将事件记录到本地文件(通过 stderr 重定向的 NSLog)。此外,我没有在位置管理器中配置与 SLC 无关的属性,如 desiredAccuracy、distanceFIlter、activityType。我建议你从准系统应用程序开始,观察改进,它打破了它。

要检查的一件事是您的应用程序在处理位置更新时是否崩溃。如果它发生在后台,除非您 运行 通过 Settings.app 记录或检查崩溃日志,否则您不会注意到这一点。