2016-02-17 4 views
6

Я использую значительный мониторинг изменений местоположения. Когда я запускаю код в симуляторе и проверяю опцию Freeway, я получаю периодические обновления местоположения. Я беру эти обновления и сохраняю их в NSUserDefaults, а затем обновляю таблицу каждые 10 секунд, поэтому я вижу, есть ли у меня обновления. Если я запустил приложение на реальном устройстве, я получаю нулевые обновления. Я держал телефон в кармане и путешествовал более чем на 80 км, был в двух городах. Нулевые обновления. Не уверен, что я что-то испортил. Я прикрепляю код. Код - скопировать пачку, не стесняйтесь протестировать. Просто убедитесь, что TableViewController используется в раскадровке и задайте идентификатор ячейки ID. Что мне не хватает? Я проверяю на Iphone 5.Значительное изменение местоположения не срабатывает на устройстве

info.plist:

enter image description here

редактирования: Нашли это в яблоневых документы. Должен ли мой locationManager быть создан по-разному?

Когда приложение возобновлено из-за обновлением местоположения, запуск вариантов СЛОВАРЯ передаются ваш применения: willFinishLaunchingWithOptions: или применения: didFinishLaunchingWithOptions: метод содержит ключ UIApplicationLaunchOptionsLocationKey. Наличие этого ключа сигнализирует, что новые данные о местоположении ждут доставки в ваше приложение. Чтобы получить эти данные, вы должны создать новый объект CLLocationManager и перезапустить службы определения местоположения, которые были у вас до завершения вашего приложения . При перезапуске этих служб диспетчер местоположений передает все ожидающие обновления местоположения своему делегату.

edit2:

Исходя из этого, место должно быть обновлено по крайней мере, каждые 15 минут. Ошибка в моем коде подтверждена.

Если точность GPS-уровень не является критичной для вашего приложения, и вам не нужно непрерывного слежения, вы можете использовать значащее изменение расположения службу. Крайне важно, чтобы вы правильно использовали услугу значительного изменения , потому что она пробуждает систему и ваше приложение как минимум каждые 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") 
      } 

КОД: // 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 
     } 
    } 
} 

// View Controller

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() 
    } 
} 
+0

Вы действительно видите запрос на авторизацию? Если нет, у вас есть NSLocationAlwaysUsageDescription в вашем plist? –

+0

Да, запрос выдается.И да, строка NSLocationAlwaysUsageDescription установлена ​​в info.plist. – brumbrum

+0

Вы убиваете приложение, дважды нажав кнопку «домой» и прокручивая приложение? Если вы убьете приложение таким образом, он не будет запускать службы значительного изменения фона. – Rob

ответ

14

Есть несколько проблем, с кодом:

  1. Место обновления не запускается, когда приложение запускается прошивкой.
  2. Обновления фонового местоположения не запрашиваются.
  3. код зависит от изменения статуса авторизации для запуска обновлений местоположения
  4. Существует недостающее заявление перерыва в методы didChangeAuthorizationStatus.

Вот соответствующие документы:

Первый документ говорит объект менеджер место должен быть полностью настроен, когда IOS запускает приложение поэтому событие местоположения может быть доставлено в приложение.

При повторном запуске вы все равно должны сконфигурировать объект менеджера местоположений и вызвать этот метод [startMonitoringSignificantLocationChanges], чтобы продолжить получать события местоположения.

Как обычно я делаю это, чтобы гарантировать, что менеджер местоположений будет полностью запущен, независимо от того, был ли он запущен с помощью значка или 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 и должно выполняться каждый раз, когда приложение запускается, если вы хотите получать обновления местоположений в фоновом режиме. (Это как «Я не шучу, я знаю, что я просил их в фоновом режиме, но я действительно хочу их»).

Приложения, которые хотят получать обновления местоположения при приостановке, должны включать ключ UIBackgroundModes (с указанием значения местоположения) в файле Info.plist своего приложения и устанавливать для этого свойства значение YES.

Наконец, вы не можете полагаться на didChangeAuthorizationStatus называют. Если у вас есть разрешение kCLAuthorizationStatusAuthorizedAlways затем вызывая [locationMgr requestAlwaysAuthorization] не приводит к изменению статуса авторизации, поэтому didChangeAuthorizationStatus не называется.

Если статус авторизации уже известен при вызове requestWhenInUseAuthorization или requestAlwaysAuthorization метод, менеджер местоположения не сообщает текущее состояние авторизации этого метода.

+0

Сэр, вы заслуживаете миллиона голосов. Спасибо! – brumbrum

+0

Нет проблем - Apple постоянно делает CoreLocation более сложной в использовании с каждой версией iOS. Я думаю, что это было идеально для iOS6, теперь это просто тайно. Удачи с вашим проектом. – BitByteDog

+1

Не могу с этим спорить. На боковой ноте. Я пару раз играю вокруг. Apple объявляет, что значительное место будет срабатывать по крайней мере каждые 15 минут независимо от фактического изменения местоположения. Я не получаю никаких обновлений, если я не двигаюсь. Вы видите обновления местоположения в своих приложениях каждые 15 минут, даже если вы не двигаетесь? – brumbrum

0

Я думаю, вы должны startUpdatingLocation независимо? Вы пытались вставить точки останова, чтобы увидеть, куда вы доберетесь?

+0

, если я установил startUpdatingLocation в true, я получаю 3 обновления в секунду. Я думаю, что это всего лишь много для стандартных служб определения местоположения. У меня нет, потому что он отлично работает на симуляторе. – brumbrum

+0

Можно ли использовать контрольные точки на приостановленном приложении в фоновом режиме? – brumbrum

+0

@ krompir2 - Нет, вы не можете использовать контрольные точки в этом случае. Я вообще 'NSLog' сообщения (так что я могу посмотреть консоль). Я также счел полезным записывать сообщения в какое-то постоянное хранилище, а затем, когда я приношу приложение на передний план, покажите эти сохраненные сообщения в виде таблицы или что-то в этом роде, чтобы я мог диагностировать, что происходило, когда приложение не было в на переднем плане. – Rob

Смежные вопросы