找到最近的信标的正确方法



当didRangeBeacons方法被调用时,最近的信标是beacons.first吗?或者是信标列表中精度值最低的信标?都对吗?由于

虽然didRangeBeacons:inRegion:回调中的信标列表是按精度字段(实际上以米为单位测量距离)排序的,但依赖于此存在许多问题:

  • 如果过去一秒内没有RSSI(信号强度)样本,信标的精度值有时为-1。如果您依赖于自动排序,则会得到不正确的结果。

  • 如果在最后一秒没有检测到信标,有时信标会从列表中退出。

  • 在嘈杂的蓝牙环境和不频繁传输信标时,这是一个常见的问题。

知道最近的信标的更健壮的方法是自己实现一个算法,该算法忽略精度值-1,并容忍信标检测中的临时丢失(例如5秒)。

当然,这仅仅是个开始。您还可以添加各种其他过滤器,使其更适合您的确切用例。为了不让事情过于复杂,下面是我使用的一些基本的Swift代码:

let expirationTimeSecs = 5.0
public var closestBeacon: CLBeacon? = nil
var trackedBeacons: Dictionary<String, CLBeacon>
var trackedBeaconTimes: Dictionary<String, NSDate>
override init() {
  trackedBeacons = Dictionary<String, CLBeacon>()
  trackedBeaconTimes = Dictionary<String, NSDate>()
}
public func locationManager(manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], inRegion region: CLBeaconRegion) {
  let now = NSDate()
  for beacon in beacons {
    let key = keyForBeacon(beacon)
    if beacon.accuracy < 0 {
      NSLog("Ignoring beacon with negative distance")
    }
    else {
      trackedBeacons[key] = beacon
      if (trackedBeaconTimes[key] != nil) {
        trackedBeaconTimes[key] = now
      }
      else {
        trackedBeaconTimes[key] = now
      }
    }
  }
  purgeExpiredBeacons()
  calculateClosestBeacon()
}
func calculateClosestBeacon() {
  var changed = false
    // Initialize cloestBeaconCandidate to the latest tracked instance of current closest beacon
    var closestBeaconCandidate: CLBeacon?
    if closestBeacon != nil {
      let closestBeaconKey = keyForBeacon(closestBeacon!)
      for key in trackedBeacons.keys {
        if key == closestBeaconKey {
          closestBeaconCandidate = trackedBeacons[key]
        }
      }
    }
    for key in trackedBeacons.keys {
      var closer = false
      let beacon = trackedBeacons[key]
      if (beacon != closestBeaconCandidate) {
        if beacon!.accuracy > 0 {
          if closestBeaconCandidate == nil {
            closer = true
          }
          else if beacon!.accuracy < closestBeaconCandidate!.accuracy {
            closer = true
          }
        }
        if closer {
          closestBeaconCandidate = beacon
          changed = true
        }
      }
    }
    if (changed) {
      closestBeacon = closestBeaconCandidate
    }
}
func keyForBeacon(beacon: CLBeacon) -> String {
  return "(beacon.proximityUUID.UUIDString) (beacon.major) (beacon.minor)"
}
func purgeExpiredBeacons() {
  let now = NSDate()
  var changed = false
  var newTrackedBeacons = Dictionary<String, CLBeacon>()
  var newTrackedBeaconTimes = Dictionary<String, NSDate>()
  for key in trackedBeacons.keys {
    let beacon = trackedBeacons[key]
    let lastSeenTime = trackedBeaconTimes[key]!
    if now.timeIntervalSinceDate(lastSeenTime) > expirationTimeSecs {
      NSLog("******* Expired seeing beacon: (key) time interval is (now.timeIntervalSinceDate(lastSeenTime))")
      changed = true
    }
    else {
      newTrackedBeacons[key] = beacon!
      newTrackedBeaconTimes[key] = lastSeenTime
    }
  }
  if changed {
    trackedBeacons = newTrackedBeacons
    trackedBeaconTimes = newTrackedBeaconTimes
  }
}

一旦检测到信标,为了查看最接近的信标,您需要在locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region回调中遍历信标数组,并比较每个信标的精度属性。精度值最低的信标距离最近。

相关内容

最新更新