当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
回调中遍历信标数组,并比较每个信标的精度属性。精度值最低的信标距离最近。