> [Determining the Proximity to an iBeacon](https://developer.apple.com/documentation/corelocation/determining_the_proximity_to_an_ibeacon?language=occ)
學習如何探測信標,并確定它們的相對距離。
### 第1節概述
iBeacon 是一種設備,它能發出藍牙信號,可以被你的設備檢測到。企業可以在距離檢測對用戶有利的環境中部署 iBeacon 設備,應用可以利用信標的近距離來確定合適的行動路線。根據附近的信標,你決定采取什么行動。例如,百貨商店可能會部署識別商店每個部分的信標,相應的應用程序可能會在用戶靠近每個區域時指出銷售項目。
在你的應用中加入 iBeacon 支持,包括在兩個不同的階段探測信標:
1. 使用區域監測來檢測 iBeacon 的存在。
2. 使用信標來確定接近被檢測到的iBeacon的距離。
使用兩個步驟來探測信標可以大大降低功耗。測距需要頻繁地測量藍牙信號的強度,并計算距離到相關的信標的距離。相比之下,區域監測只需要被動地傾聽附近的信標,后者消耗的電力要少得多。
### 第2節部署 iBeacon 硬件
在部署 iBeacon 硬件時,必須使用適當的鄰近 UUID,major, minor 值來編程每個 iBeacon設備。這些值可唯一標識每個信標,并使應用程序能夠在一后區分這些信標。
- 鄰近UUID(通用唯一標識符)是一個128位值,唯一標識應用程序的信標。
- major 值是一個16位無符號整數,用于區分具有相同的鄰近 UUID 的信標組。
- minor 值是一個16位無符號整數,用于區分具有相同 UUID 和 major 值的信標組。
只有鄰近的 UUID 是必須的,但是建議將三個值編程到 iBeacon 硬件中。在應用程序中,可以通過指定值的一個子集來查找相關的信標組。
### 第3節 利用區域監測檢測信標的存在
當 iBeacon 在附近時,使用區域監測來提醒應用程序。要監視信標,請創建一個 [CLBeaconRegion](https://developer.apple.com/documentation/corelocation/clbeaconregion?language=objc) 對象,并使用 [CLLocationManager](https://developer.apple.com/documentation/corelocation/cllocationmanager?language=objc) 對象的 [startMonitoringForRegion:](https://developer.apple.com/documentation/corelocation/cllocationmanager/1423656-startmonitoringforregion?language=objc) 方法進行注冊。BeaconRegion 包含要檢測的信標的鄰近 UUID ,major 值和 minor 值。只有具有匹配值的信標才會觸發對委托對象的調用。
清單1顯示了如何為公司的信標設置區域監控的例子。由于通常為公司定義一個 UUID,稍后不要更改,因此該示例包含該值的硬編碼版本。在調用此方法之前,必須已經創建了一個 [CLLocationManager](https://developer.apple.com/documentation/corelocation/cllocationmanager?language=objc) 對象并為其指派了一個委托。
###### 清單1 為信標設置區域檢測
```
func monitorBeacons() {
if CLLocationManager.isMonitoringAvailable(for:
CLBeaconRegion.self) {
// Match all beacons with the specified UUID
let proximityUUID = UUID(uuidString:
"39ED98FF-2900-441A-802F-9C398FC199D2")
let beaconID = "com.example.myBeaconRegion"
// Create the region and begin monitoring it.
let region = CLBeaconRegion(proximityUUID: proximityUUID!,
identifier: beaconID)
self.locationManager.startMonitoring(for: region)
}
}
```
當檢測到匹配的 iBeacon 時,CLLocationManager 對象通過調用 [locationManager:didEnterRegion:](https://developer.apple.com/documentation/corelocation/cllocationmanagerdelegate/1423560-locationmanager?language=objc) 方法來通知其委托。類似地,當檢測到的信標移出范圍時,位置管理器調用 [locationManager:didExitRegion:](https://developer.apple.com/documentation/corelocation/cllocationmanagerdelegate/1423630-locationmanager?language=objc) 方法。使用委托方法來啟動和停止信標測距。
如果應用在檢測到信標時未運行,系統會嘗試啟動您的應用。
> 重要提示
> 應用程序必須始終具有使用區域監視的權限,并且必須配置位置更新后臺模式才能啟動。
### 第4節使用測距確定與信標的距離
在檢測到 iBeacon 后,使用測距來確定信標和用戶設備之間的相對距離。當兩臺設備相距甚遠,彼此靠近或彼此緊鄰時,會發出報告。它不提供一個精確的距離,也不應該依靠信號的強度來自己計算這些信息。使用相對值來確定適當的操作過程。例如,一個美術館的應用程序可能會等待,直到用戶在 iBeacon 的附近,然后才能提供相應的作品信息。
###### 圖1 確定相對接近 iBeacon 的距離

開始測距的最合理的地方是在首次檢測到信標時 locationManager.delegat 的 [locationManager:didEnterRegion:](https://developer.apple.com/documentation/corelocation/cllocationmanagerdelegate/1423560-locationmanager?language=objc) 方法。(停止測距量的地方在代理的 [locationManager:didExitRegion:](https://developer.apple.com/documentation/corelocation/cllocationmanagerdelegate/1423630-locationmanager?language=objc) 方法中。)
要開始測距,請將用于區域監測的 [CLBeaconRegion](https://developer.apple.com/documentation/corelocation/clbeaconregion?language=objc) 對象傳遞給 locationManager 的 [startRangingBeaconsInRegion:](https://developer.apple.com/documentation/corelocation/cllocationmanager/1620554-startrangingbeaconsinregion?language=objc) 方法。
清單2展示了這個委托方法的一個實現,它檢測到信標時打開了的測距。該方法還將信標添加到內部數組,以便應用程序可以隨時停止和重新啟動測距。例如,當應用程序在后臺以節省電力時,可能會停止測距。
###### 清單2 測距信標
```
func locationManager(_ manager: CLLocationManager,
didEnterRegion region: CLRegion) {
if region is CLBeaconRegion {
// Start ranging only if the feature is available.
if CLLocationManager.isRangingAvailable() {
manager.startRangingBeacons(in: region as! CLBeaconRegion)
// Store the beacon so that ranging can be stopped on demand.
beaconsToRange.append(region as! CLBeaconRegion)
}
}
}
```
當測距處于活動狀態時,只要有更改報告,locationManager 對象就會調用其委托的 locationManager:didRangeBeacons:inRegion: 方法。使用此方法根據附近的信標的距離采取行動。清單3顯示博物館應用程序如何使用鄰近值來顯示最近展覽的信息。在這個例子中,博物館使用 major 和 minor 來確定哪個展覽。
### ### 清單3 在最近的信標上的操作
```
func locationManager(_ manager: CLLocationManager,
didRangeBeacons beacons: [CLBeacon],
in region: CLBeaconRegion) {
if beacons.count > 0 {
let nearestBeacon = beacons.first!
let major = CLBeaconMajorValue(nearestBeacon.major)
let minor = CLBeaconMinorValue(nearestBeacon.minor)
switch nearestBeacon.proximity {
case .near, .immediate:
// Display information about the relevant exhibit.
displayInformationAboutExhibit(major: major, minor: minor)
break
default:
// Dismiss exhibit information, if it is displayed.
dismissExhibit(major: major, minor: minor)
break
}
}
}
```
> 提示
> 部署信標時,考慮給每一個UUID,major 和 minor 值的獨特組合,以便可以更容易地區分它們。
如果多個信標使用相同的UUID,major 和 minor ,則傳送到 [locationManager:didRangeBeacons:inRegion:](https://developer.apple.com/documentation/corelocation/cllocationmanagerdelegate/1621501-locationmanager?language=objc) 方法的信標數組可能只能通過它們的距離和精度值進行區分。