Почему я не получаю вызовы didEnterRegion или didExitRegion при использовании startMonitoringForRegion из CLLocationManager

Я пытаюсь настроить клиентское приложение для запуска обновления базы данных, когда устройство iOS прибывает / покидает офис.

(Это приложение, которое продавцы моего клиента могут использовать в полевых условиях, где некоторые сайты клиентов не имеют сетевого подключения, поэтому клиент хочет обновить базу данных, когда продавцы покидают офис / возвращаются в офис.)

Я никогда не получаю didEnterRegion или же didExitRegion звонки.

У меня есть синглтон RegionsManager который управляет экземпляром менеджера местоположения. я использую CLLocationManager и startMonitoringForRegion метод.

На запуске я призываю RegionsManager который создает менеджер местоположения и устанавливает себя как делегат менеджера местоположения.

В моем приложении делегат didFinishLaunchingWithOptions метод, который я проверяю для UIApplicationLaunchOptionsLocationKeyна случай, если меня перезапустят для региона, в который можно войти / выйти, но этого никогда не произойдет.

у меня есть NSLocationAlwaysUsageDescription пара ключ / значение в info.plist.

Я звоню CLLocationManager.authorizationStatus чтобы убедиться, что приложение авторизовано, и если нет, я звоню requestAlwaysAuthorization,

Как только я проверяю, что приложение авторизовано, я также проверяю isMonitoringAvailableForClass(CLCircularRegion).

Предполагая, что мониторинг доступен, я затем проверяю, установлен ли monitoredRegions уже содержит регион, который я собираюсь создать (я просто проверяю координаты). Если так, я пропускаю добавление региона.

Если менеджер местоположения еще не контролирует регион, я добавляю его с вызовом startMonitoringForRegion,

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

Код для установки всего этого достаточно сложен, поскольку он настроен на обработку добавления нескольких областей, а также имеет логику для поддержки массива отслеживаемых областей и блока, который должен вызываться, если на didEnterRegion или же didExitRegion сообщение.

Вот этот метод в целом (довольно долго):

func startMonitoring(#coordinate: CLLocationCoordinate2D,
  radius: CLLocationDistance = regionDistance,
  id: String = "",
  notificationBlock: regionNotificationBlock)
{
  var authorizationStatus = CLLocationManager.authorizationStatus()
  if !locationManagerReady
  {
    //Make sure we're authorized to use the location manager.
    if authorizationStatus == .NotDetermined && !waitingForAuthorization
    {
      //We haven't been authorized yet. Trigger a prompt to the user.
      theLocationMgr.requestAlwaysAuthorization()
      waitingForAuthorization = true
      authorizationStatus = CLLocationManager.authorizationStatus()
    }

    //Wait for the user to grant/deny permission.
    if authorizationStatus == .NotDetermined
    {
      //After 1 second, re-call this method to try again.
      delay(1.0)
        {
          ()-> () in
          self.startMonitoring(
            coordinate: coordinate,
            radius: radius,
            id: id,
            notificationBlock: notificationBlock)
      }
      return
    }

    let rootVC: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController
    if authorizationStatus == CLAuthorizationStatus.Restricted ||
      authorizationStatus == CLAuthorizationStatus.Denied
    {
      Utils.showAlertOnVC(
        rootVC,
        title: "Location manager error",
        message: "Permission to access location denied")
      return
    }

    else if !CLLocationManager.isMonitoringAvailableForClass(CLCircularRegion)
    {
      Utils.showAlertOnVC(
        rootVC,
        title: "Location manager error",
        message: "geofencing is not available.")
      return
    }
  }
  if !locationManagerReady
  {
    locationManagerReady = true
    theLocationMgr.desiredAccuracy = kCLLocationAccuracyBest
    theLocationMgr.distanceFilter = kCLDistanceFilterNone;
  }

  //If we get here, we're done configuring the location manager

  //If this region is already in our array of regions, don't add it again.
  if let existingRegionIndex = regionIndexForCoordinate(coordinate)
  {
    return
  }
  let regionToMonitor =  CLCircularRegion(
    center: coordinate,
    radius: radius,
    identifier: id)


  //See if the system is still monitoring this region from a previous launch.
  var found = false
  var foundRegion: CLCircularRegion? = nil
  if let monitoredRegions = theLocationMgr.monitoredRegions as NSSet?
  {
    let regionsArray = monitoredRegions.allObjects as NSArray
    let regionIndex = regionsArray.indexOfObjectPassingTest()
      { (object, index, flag) -> Bool in
        if let region = object as? CLCircularRegion
        {
          return region.center.latitude == coordinate.latitude &&
            region.center.longitude == coordinate.longitude
        }
        else
        {
          return false
        }
    }
    found = regionIndex != NSNotFound
    if found
    {
      foundRegion = regionsArray[regionIndex] as? CLCircularRegion
    }
  }
  if found
  {
    logToFile("already monitoring (\(coordinate.latitude),\(coordinate.longitude)). ID = '\(foundRegion!.identifier!)'")
  }
  else
  {
    logToFile("Adding geofence for (\(coordinate.latitude),\(coordinate.longitude)). ID = '\(id)'")
    theLocationMgr.startMonitoringForRegion(regionToMonitor)
  }
  let aRegionEntry = RegionEntry(region: regionToMonitor, regionNoticeBlock: notificationBlock)
  regionsBeingMonitored.append(aRegionEntry)
}

Мой класс RegionsManager имеет массив regionsBeingMonitored из RegionEntry объекты:

lazy var regionsBeingMonitored = [RegionEntry]()

Вот объект RegionEntry:

class RegionEntry: NSObject
{
  var theRegion: CLCircularRegion?
  var theRegionNoticeBlock: regionNotificationBlock?
  init(region: CLCircularRegion?, regionNoticeBlock: regionNotificationBlock?)
  {
    theRegion = region
    theRegionNoticeBlock = regionNoticeBlock
  }
}

У этого также есть флаги состояния, чтобы отследить настройку менеджера местоположения:

var waitingForAuthorization: Bool = false
var locationManagerReady: Bool = false

Я внимательно изучил документацию по настройке мониторинга региона и уверен, что выполняю все настройки, которые я должен делать.

Мои методы didEnterRegion и didExitRegion записывают сообщение в файл журнала, как только они вызываются, так что даже если в моей логике есть проблема с сопоставлением региона с записью в моем regionsBeingMonitored массив я все еще должен увидеть запись в журнале:

func locationManager(manager: CLLocationManager!,
  didEnterRegion region: CLRegion!)
{
  logToFile("In \(__FUNCTION__). region = \(region)")
  if let region = region as? CLCircularRegion
  {
    if let regionIndex = regionIndexForCoordinate(region.center)
    {
      let aRegionEntry = regionsBeingMonitored[regionIndex]
      aRegionEntry.theRegionNoticeBlock?(region: region, didEnter: true)
    }
  }
}

func locationManager(manager: CLLocationManager!,
  didExitRegion region: CLRegion!)
{
  logToFile("In \(__FUNCTION__). region = \(region)")
  if let region = region as? CLCircularRegion
  {
    if let regionIndex = regionIndexForCoordinate(region.center)
    {
      let aRegionEntry = regionsBeingMonitored[regionIndex]
      aRegionEntry.theRegionNoticeBlock?(region: region, didEnter: false)
    }
  }
}

Вы видите что-нибудь, что я могу делать неправильно? Подпись метода для моего didEnterRegion или же didExitRegion выглядит правильно, так что я не думаю, что это все.

0 ответов

Другие вопросы по тегам