重大的位置变化不会在设备上触发

我正在使用重要的位置更改监控。 当我在模拟器中运行代码并检查Freeway选项时,我会定期更新位置。 我抓住这些更新,并将其保存在NSUserDefaults,并比每10秒更新tableview,所以我可以看到,如果我有任何更新。 如果我在真实的设备上运行应用程序,我得到零更新。 我把电话放在口袋里,走了80多公里,在两个城市。 零更新。 不知道我是否搞砸了。 我附上了代码。 代码是复制粘贴,随时testing。 只要确保在故事板中使用TableViewController并将单元ID设置为ID即可。 我错过了什么? 我正在testingiPhone 5。

info.plist中:

在这里输入图像说明

编辑:在苹果文档中find这个。 我的locationManager应该创build不同?

当由于位置更新而重新启动应用程序时,将启动选项字典传递给您的应用程序:willFinishLaunchingWithOptions:或application:didFinishLaunchingWithOptions:方法包含UIApplicationLaunchOptionsLocationKey项。 该键的存在表示新的位置数据正在等待传送到您的应用程序。 要获取这些数据,您必须创build一个新的CLLocationManager对象,并重新启动您的应用程序终止之前运行的位置服务。 当您重新启动这些服务时,位置pipe理器会将所有待处理的位置更新传递给其代理。

EDIT2:

基于此,位置应至less每15分钟更新一次。 我的代码中的错误确认。

如果GPS级精度对您的应用程序不是至关重要的,并且您不需要连续跟踪,则可以使用重大更改位置服务。 正确使用重大更改位置服务至关重要,因为它至less每隔15分钟就会唤醒系统和应用程序,即使没有发生位置更改,也会持续运行,直到您停止。

edit3:将此代码添加到AppDelegate didFinishLaunchingWithOptions:查看应用程序是否被唤醒。 它不会被唤醒 – 我在表格视图中看不到200 200条目。 有什么可疑的事情正在发生。

  if let options = launchOptions { print("options") if (launchOptions![UIApplicationLaunchOptionsLocationKey] != nil){ locationManager.startUpdatingLocation() self.lat.append(Double(200)) self.lon.append(Double(200)) self.times.append(NSDateFormatter.localizedStringFromDate(NSDate(), dateStyle: .NoStyle, timeStyle: .ShortStyle)) NSUserDefaults.standardUserDefaults().setObject(lat, forKey: "lat") NSUserDefaults.standardUserDefaults().setObject(lon, forKey: "lon") NSUserDefaults.standardUserDefaults().setObject(times, forKey: "time") } 

CODE:// AppDelegate:

 import UIKit import CoreLocation @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate { var lat:[CLLocationDegrees]! var lon:[CLLocationDegrees]! var times:[String]! var distances: [String]! var window: UIWindow? var locationManager: CLLocationManager! func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { locationManager=CLLocationManager() locationManager.delegate=self locationManager.requestAlwaysAuthorization() let isFirstLaunch = NSUserDefaults.standardUserDefaults().objectForKey("lat") if isFirstLaunch == nil{ lat = [CLLocationDegrees]() lon = [CLLocationDegrees]() times = [String]() NSUserDefaults.standardUserDefaults().setObject(lat, forKey: "lat") NSUserDefaults.standardUserDefaults().setObject(lon, forKey: "lon") NSUserDefaults.standardUserDefaults().setObject(times, forKey: "time") }else{ lat = NSUserDefaults.standardUserDefaults().arrayForKey("lat") as! [CLLocationDegrees] lon = NSUserDefaults.standardUserDefaults().arrayForKey("lon") as! [CLLocationDegrees] times = NSUserDefaults.standardUserDefaults().objectForKey("time") as! [String] // distances = NSUserDefaults.standardUserDefaults().objectForKey("distance") as! [String] } return true } func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { print("location updated") self.lat.append(locations[0].coordinate.latitude) self.lon.append(locations[0].coordinate.longitude) self.times.append(NSDateFormatter.localizedStringFromDate(NSDate(), dateStyle: .NoStyle, timeStyle: .ShortStyle)) NSUserDefaults.standardUserDefaults().setObject(lat, forKey: "lat") NSUserDefaults.standardUserDefaults().setObject(lon, forKey: "lon") NSUserDefaults.standardUserDefaults().setObject(times, forKey: "time") print("Location: \(locations[0].coordinate.latitude) \(locations[0].coordinate.longitude)") } func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) { print("did change AS") switch status { case .AuthorizedWhenInUse: locationManager.startMonitoringSignificantLocationChanges() case .AuthorizedAlways: print("to always") locationManager.startMonitoringSignificantLocationChanges() if lat.count==0{ self.lat.append((locationManager.location?.coordinate.latitude)!) self.lon.append((locationManager.location?.coordinate.longitude)!) self.times.append(NSDateFormatter.localizedStringFromDate(NSDate(), dateStyle: .NoStyle, timeStyle: .ShortStyle)) NSUserDefaults.standardUserDefaults().setObject(lat, forKey: "lat") NSUserDefaults.standardUserDefaults().setObject(lon, forKey: "lon") NSUserDefaults.standardUserDefaults().setObject(times, forKey: "time") } // locationManager.startUpdatingLocation() break default: locationManager.stopMonitoringSignificantLocationChanges() break } } } 

//视图控制器

 import UIKit class TableViewController: UITableViewController { let appDel = UIApplication.sharedApplication().delegate as! AppDelegate override func viewDidLoad() { super.viewDidLoad() NSTimer.scheduledTimerWithTimeInterval(10, target: self, selector: "updateTableView", userInfo: nil, repeats: true) } override func numberOfSectionsInTableView(tableView: UITableView) -> Int { // #warning Incomplete implementation, return the number of sections return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // #warning Incomplete implementation, return the number of rows return appDel.lon.count } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("ID", forIndexPath: indexPath) cell.textLabel?.text = "\(appDel.lat[indexPath.row]) \(appDel.lon[indexPath.row]) \(appDel.times[indexPath.row])" cell.textLabel?.font = UIFont.systemFontOfSize(9) return cell } func updateTableView(){ self.tableView.reloadData() } } 

代码有几个问题:

  1. 当应用程序由iOS启动时,位置更新不会启动。
  2. 不要求后台位置更新。
  3. 代码依赖授权状态的变化来启动位置更新
  4. didChangeAuthorizationStatus方法中缺lessbreak语句。

以下是相关文件:

  • startMonitoringSignificantLocationChanges
  • didChangeAuthorizationStatus
  • allowsBackgroundLocationUpdates

第一个文档说,当iOS启动应用程序时,位置pipe理器对象必须完全configuration,以便位置事件可以传递给应用程序。

重新启动后,您仍然必须configuration一个位置pipe理器对象并调用此方法[startMonitoringSignificantLocationChanges]继续接收位置事件。

我通常这样做是为了确保位置pipe理器完全启动,无论是从图标还是由iOS启动(对不起,我使用ObjectiveC)。

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. NSLog(@"app launching"); bgTask = UIBackgroundTaskInvalid; locationMgr = [[CLLocationManager alloc] init]; [locationMgr setDelegate:self]; if([locationMgr respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) [locationMgr setAllowsBackgroundLocationUpdates:YES]; CLAuthorizationStatus authorizationStatus= [CLLocationManager authorizationStatus]; if([launchOptions valueForKey:UIApplicationLaunchOptionsLocationKey] != nil) { NSLog(@"relaunching because of significant location change - restarting SLC"); [locationMgr startMonitoringSignificantLocationChanges]; } else { if (authorizationStatus == kCLAuthorizationStatusAuthorizedAlways) { NSLog(@"launching with authorization to always use location - starting SLC"); [locationMgr startMonitoringSignificantLocationChanges]; } else { NSLog(@"launching with no authorization to always use location - requesting authorization"); if([locationMgr respondsToSelector:@selector(requestAlwaysAuthorization)]) [locationMgr requestAlwaysAuthorization]; } } return YES; } 

注意对setAllowsBackgroundLocationUpdates的调用。 这是iOS9中的新function,如果您希望在后台接收位置更新,则必须在应用程序每次启动时完成。 (这就像“我不是在开玩笑,我知道我在后台模式下要求他们,但我真的很想要他们”)。

希望在暂停时接收位置更新的应用程序必须在其应用程序的Info.plist文件中包含UIBackgroundModes键(具有位置值),并将此属性的值设置为YES。

最后你不能依靠被调用的didChangeAuthorizationStatus 。 如果您拥有授权kCLAuthorizationStatusAuthorizedAlways,则调用[locationMgr requestAlwaysAuthorization]不会导致授权状态的更改,因此不会调用ChangeChangeAuthorizationStatus

如果在调用requestWhenInUseAuthorization或requestAlwaysAuthorization方法时授权状态已知,则位置pipe理器不会将当前授权状态报告给此方法。

我认为你必须不pipe启动更新位置? 你有没有尝试插入断点,看看你到哪里?