前言
藍(lán)牙設(shè)備想必大家都很熟悉了,相關(guān)的開(kāi)發(fā)資料也是很多了,這里就不必多說(shuō)了
iOS藍(lán)牙的開(kāi)發(fā)專題
iOS藍(lán)牙開(kāi)發(fā)(一)藍(lán)牙相關(guān)基礎(chǔ)知識(shí)
iOS藍(lán)牙開(kāi)發(fā)(二)ios連接外設(shè)的代碼實(shí)現(xiàn)
iOS藍(lán)牙開(kāi)發(fā)(三)app作為外設(shè)被連接的實(shí)現(xiàn)
iOS藍(lán)牙開(kāi)發(fā)(四)BabyBluetooth藍(lán)牙庫(kù)介紹
iBeacon 是蘋(píng)果公司2013年9月發(fā)布的移動(dòng)設(shè)備用OS(iOS7)上配備的新功能巡球。其工作方式是驮瞧,配備有 低功耗藍(lán)牙(BLE)通信功能的設(shè)備使用BLE技術(shù)向周圍發(fā)送自己特有的ID拷况,接收到該ID的應(yīng)用軟件會(huì)根據(jù)該ID采取一些行動(dòng)肌稻。比如,在店鋪里設(shè)置iBeacon通信模塊的話挺邀,便可讓iPhone和iPad上運(yùn)行一資訊告知服務(wù)器揉忘,或者由服務(wù)器向顧客發(fā)送折扣券及進(jìn)店積分跳座。此外,還可以在家電發(fā)生故障或停止工作時(shí)使用iBeacon向應(yīng)用軟件發(fā)送資訊泣矛。
蘋(píng)果 WWDC 14 之后疲眷,對(duì) iBeacon 加大了技術(shù)支持和對(duì)其用于室內(nèi)地圖的應(yīng)用有個(gè)更明確的規(guī)劃。蘋(píng)果公司公布了 iBeacon for Developers 和 Maps for Developers 等專題頁(yè)面您朽。
應(yīng)用場(chǎng)景
- 偵測(cè)iPhone進(jìn)入或者離開(kāi)某個(gè)iBeacon的范圍觸發(fā)事件
- 偵測(cè)iPhone跟iBeacon的距離狂丝,依據(jù)不同的距離觸發(fā)事件
1.比如,當(dāng)你在國(guó)家博物館參觀的時(shí)候哗总,當(dāng)你走進(jìn)《四羊方尊》前几颜,APP偵測(cè)到裝在這個(gè)藏品展牌底座的iBeacon,于是APP就開(kāi)始自動(dòng)播放相關(guān)的介紹讯屈,透過(guò)AirPods傳進(jìn)你的耳朵蛋哭,這樣的講解真的也算是一種創(chuàng)新!
2.再比如涮母,在地下車庫(kù)按照三點(diǎn)確定一個(gè)穩(wěn)定區(qū)域的設(shè)計(jì)谆趾,布置好iBeacon設(shè)備,也能設(shè)計(jì)出一套室內(nèi)導(dǎo)航的方案叛本!
如何獲得
如何去獲得這樣的設(shè)備呢沪蓬?其實(shí)你打開(kāi)某寶某多某東,這類的產(chǎn)品數(shù)不勝數(shù)来候。
其實(shí)你只是在開(kāi)發(fā)階段跷叉,也可以自己去模擬一個(gè)iBeacon的設(shè)備。因?yàn)樽鰅OS開(kāi)發(fā)的我們都有一臺(tái)iPhone&Mac营搅,高版本的設(shè)備都有變身成iBeacon的藍(lán)牙(bluetooth)能力云挟。
將Mac或者iPhone變成iBeacon
-方法1: [Apple官方文檔-將iPhone變成iBeacon(https://developer.apple.com/documentation/corelocation/turning_an_ios_device_into_an_ibeacon_device)
-
方法2:可以下載一個(gè)APP將iPhone/iPad變成iBeacon設(shè)備下載APP
我們可以下載別人已經(jīng)開(kāi)發(fā)好的應(yīng)用,安裝到我們的Mac上:MactsAsBeacon
然后再去設(shè)定它的UUID剧防、major植锉、minor,然后再點(diǎn)擊Start按鈕峭拘,此時(shí)你的Mac就配置了一個(gè)iBeacon設(shè)備,開(kāi)始發(fā)出訊號(hào)狮暑。
如果你想修改UUID鸡挠,可以使用下列方法:
1.打開(kāi)終端(terminal)
2.輸入
uuidgen
3.回車按鍵
ps: 該項(xiàng)目比較老舊,運(yùn)行會(huì)報(bào)錯(cuò)搬男,
解決方案:
在Info.plist文件中拣展,右鍵單擊空白區(qū)域,選擇 "Add Row" 添加一行缔逛。
在新添加的行中备埃,將鍵名設(shè)置為NSBluetoothAlwaysUsageDescription姓惑。
在該鍵的值字段中,提供一條簡(jiǎn)明扼要的描述按脚,說(shuō)明您的應(yīng)用程序?yàn)楹涡枰{(lán)牙權(quán)限于毙。例如,您可以寫(xiě)一句話辅搬,解釋您的應(yīng)用程序如何使用藍(lán)牙唯沮,例如:"用于搜索和連接附近的藍(lán)牙設(shè)備"。
保存Info.plist文件并重新構(gòu)建您的應(yīng)用程序堪遂。
這樣做后介蛉,您的應(yīng)用程序?qū)⒃谡?qǐng)求藍(lán)牙權(quán)限時(shí)顯示您提供的描述,以便用戶了解為什么需要這些權(quán)限溶褪,并可以選擇允許或拒絕訪問(wèn)币旧。
請(qǐng)確保您的應(yīng)用程序遵循隱私權(quán)規(guī)定,并提供清晰的權(quán)限描述猿妈,以確保用戶的隱私權(quán)得到尊重佳恬。
iBeacon的參數(shù)相關(guān)
每個(gè)設(shè)備都有UUID(128bit),major(16bit)于游,minor(16bit)毁葱;因此我們可以透過(guò)這三個(gè)標(biāo)識(shí)區(qū)分不同的iBeacon。
- 讓設(shè)備具有相同的UUID & major贰剥,利用minor區(qū)分
- 讓設(shè)備具有相同的UUID倾剿,利用major & minor區(qū)分
- 利用UUID,major蚌成,minor來(lái)區(qū)分
如果不是很復(fù)雜的需求前痘,其實(shí)前兩種區(qū)分即可,比如上述的博物館游覽担忧;如果你有分店(UUID)芹缔、產(chǎn)品分類(major)和不同產(chǎn)品(minor),就可以用第三種方案瓶盛。
開(kāi)發(fā) iBeacon 的 iOS App
這里有官方的相關(guān)參考說(shuō)明
Determining the proximity to an iBeacon device
1. 加入獲取位置的權(quán)限描述說(shuō)明
依據(jù)Apple以下表格的說(shuō)明最欠,為了偵測(cè)iPhone進(jìn)入某個(gè)iBeacon范圍,量測(cè)iBeacon間的距離惩猫,我們需要在info.plist配置里加入以下兩種權(quán)限的描述說(shuō)明:
Apple官方說(shuō)明:Choosing the Location Services Authorization to Request
Privacy — Location Always and When In Use Usage Description
為了獲取博物館的展品iBeacon信號(hào)芝硬,請(qǐng)?jiān)试S獲取你的位置
Privacy — Location When In Use Usage Description
為了獲取博物館的展品iBeacon信號(hào),請(qǐng)?jiān)试S獲取你的位置
2. 建立 CLLocationManager轧房,將 controller 設(shè)置為 CLLocationManager 的 delegate 且 要求獲取位置的權(quán)限
import CoreLocation
class ViewController: UIViewController {
var locationManager: CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
}
extension ViewController: CLLocationManagerDelegate {
}
3. 開(kāi)始偵測(cè)iBeacon
func monitorBeacons() {
if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) {
let proximityUUID = UUID(uuidString: "B0702880-A295-A8AB-F734-031A98A512DE")
let beaconId = "deeplove"
let region = CLBeaconRegion(proximityUUID: proximityUUID!, identifier: beaconId)
locationManager.startMonitoring(for: region)
}
}
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
monitorBeacons()
}
說(shuō)明
(1) 利用CLBeaconRegion指定你想要偵測(cè)的iBeacon
Apple官方文檔:CLBeaconRegion
let region = CLBeaconRegion(proximityUUID: proximityUUID!, identifier: beaconId)
產(chǎn)生CLBeaconRegion的方法有三種:
public init(proximityUUID: UUID, identifier: String)
public init(proximityUUID: UUID, major: CLBeaconMajorValue, identifier: String)
public init(proximityUUID: UUID, major: CLBeaconMajorValue, minor: CLBeaconMinorValue, identifier: String)
在剛剛的例子里拌阴,我們假設(shè)目前只有一個(gè)iBeacon設(shè)備,因此利用UUID來(lái)區(qū)分設(shè)備足以奶镶,不需要用到major和minor(ps:請(qǐng)記得UUID要和剛剛在Mac iBeacon APP上設(shè)定的UUID一致迟赃,如此才能偵測(cè)到化身iBeacon的Mac)
let region = CLBeaconRegion(proximityUUID: proximityUUID!, identifier: beaconId)
(2) 開(kāi)始偵測(cè)是否進(jìn)入/離開(kāi)iBeacon的范圍
locationManager.startMonitoring(for: region)
4. 定義CLLocationManagerDelegate 的 function 偵測(cè)進(jìn)入/離開(kāi)iBeacon的范圍
extension ViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
print("enter region")
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
print("exit region")
}
}
5. 計(jì)算距離
有時(shí)候我們還想進(jìn)一步知道iPhone和iBeacon之間的距離陪拘,Apple將距離粗略的分為四個(gè)等級(jí),由近及遠(yuǎn):Immediate 纤壁、Near左刽、Far、Unknown
比方在看博物館展覽時(shí)摄乒,我們希望走到展品前時(shí) App 才呈現(xiàn)相關(guān)的資訊悠反,於是我們可從程式判斷距離為 Immediate 時(shí)顯示展品資訊,如此才不會(huì)距離畫(huà)作還有一大段距離馍佑,連畫(huà)都看不清楚時(shí)就奇怪地顯示展品資訊斋否。
extension ViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
print("enter region")
if CLLocationManager.isRangingAvailable() {
locationManager.startRangingBeacons(in: region as! CLBeaconRegion)
}
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
print("exit region")
locationManager.stopRangingBeacons(in: region as! CLBeaconRegion)
}
}
說(shuō)明:
利用 startRangingBeacons & stopRangingBeacons 開(kāi)始 / 停止偵測(cè) iPhone & beacon 的距離。我們?cè)?locationManager(_:didEnterRegion:) 裡才開(kāi)始偵測(cè)距離拭荤,因?yàn)閭蓽y(cè)距離比較耗電茵臭,它將不斷地量測(cè)更新距離。
不過(guò)有一點(diǎn)值得注意的舅世,實(shí)測(cè)時(shí)發(fā)現(xiàn) locationManager(:didEnterRegion:) 有可能沒(méi)被觸發(fā)旦委,進(jìn)而讓程式不會(huì)呼叫 startRangingBeacons,因此永遠(yuǎn)不會(huì)偵測(cè)到 iPhone 已經(jīng)在 beacon 旁邊雏亚。比方若你原本就在 beacon 范圍裡缨硝,locationManager(:didEnterRegion:) 將不會(huì)被觸發(fā)。因此測(cè)試時(shí)最好一開(kāi)始遠(yuǎn)離 beacon罢低,在 beacon 范圍之外查辩,然后再慢慢地靠近 beacon,進(jìn)入 beacon 的范圍网持,這樣較容易觸發(fā) locationManager(_:didEnterRegion:)宜岛。(ps: 若想確保我們一定能偵測(cè)到 iPhone 就在 beacon 旁邊,另一種做法是一開(kāi)始就同時(shí)呼叫 startMonitoring & startRangingBeacons)
let region = CLBeaconRegion(proximityUUID: proximityUUID!, identifier: beaconId)
locationManager.startMonitoring(for: region)
locationManager.startRangingBeacons(in: region)
6. 定義 CLLocationManagerDelegate 的 function 量測(cè)距離功舀。
從 CLBeacon 物件的 proximity 判斷距離萍倡。當(dāng)我們?cè)?beacon 附近時(shí),此 function 將不斷被呼叫辟汰,告訴我們最新的距離資訊列敲。
func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
if beacons.count > 0 {
let nearestBeacon = beacons[0]
print(nearestBeacon.proximityUUID, nearestBeacon.major, nearestBeacon.minor)
switch nearestBeacon.proximity {
case .immediate:
print("immediate")
case .near:
print("near")
case .far:
print("far")
case .unknown:
print("unknown")
@unknown default:
print("@unknown default")
}
}
}
實(shí)驗(yàn):
利用 Mac 當(dāng) iBeacon,然后啟動(dòng)剛剛開(kāi)發(fā)的程式偵測(cè) beacon莉擒,我們可利用此難得的機(jī)會(huì)運(yùn)動(dòng)一下酿炸,走走路讓 iPhone 靠近和遠(yuǎn)離 Mac,觀察 locationManager(_:didRangeBeacons:in:) 裡 CLBeacon 距離的變化涨冀。
在APP進(jìn)入后臺(tái)偵測(cè) beacon & 顯示通知
我們也可以在APP進(jìn)入后臺(tái)偵測(cè) beacon,甚至在 App 沒(méi)啟動(dòng)但進(jìn)入 beacon 范圍時(shí)麦萤,由 iOS 自動(dòng)啟動(dòng) App鹿鳖,然后觸發(fā) locationManager:didEnterRegion:扁眯。比方以下例子,我們?cè)?locationManager:didEnterRegion: 觸發(fā)時(shí)顯示通知訊息:
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
let content = UNMutableNotificationContent()
content.title = "注意"
content.subtitle = "小明就在你身邊"
content.badge = 1
content.sound = UNNotificationSound.default
let request = UNNotificationRequest(identifier: "notification", content: content, trigger: nil)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
if CLLocationManager.isRangingAvailable() {
locationManager.startRangingBeacons(in: region as! CLBeaconRegion)
}
}
為了顯示通知翅帜,記得要先請(qǐng)求使用者的同意姻檀。
import UIKit
import UserNotifications
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge], completionHandler: { granted, error in
if granted {
} else {
print("使用者不同意[圖片上傳中...(IMG_9120.PNG-dd714c-1695030587401-0)]
,哭哭!")
}
})
return true
}
實(shí)驗(yàn)步驟:
安裝 App涝滴,然后啟動(dòng) App 同意權(quán)限后绣版,先將它殺掉,維持 App 不啟動(dòng)的狀態(tài)歼疮。
把 iPhone 收進(jìn)胸前左邊口袋杂抽,走到遠(yuǎn)離 beacon 的天涯海角散心。
從天涯海角出發(fā)韩脏,朝著心愛(ài)的 beacon 方向前進(jìn)缩麸。
ps:
若你原本就在 beacon 范圍裡弧械,locationManager(_:didEnterRegion:) 將不會(huì)被觸發(fā)。因此測(cè)試時(shí)請(qǐng)記得先遠(yuǎn)離 beacon空民。
- 根據(jù) Apple 文件的說(shuō)明刃唐,為了在APP進(jìn)入后臺(tái)偵測(cè)到進(jìn)入 beacon 范圍時(shí)啟動(dòng) App,我們得將 Capabilities 頁(yè)面 Background Modes 的 Location Updates 打開(kāi)袭景。不過(guò)根據(jù)實(shí)測(cè)的結(jié)果唁桩,不需打開(kāi) Location Updates 一樣可觸發(fā) locationManager:didEnterRegion: & application(_:didFinishLaunchingWithOptions:)。
Handling location updates in the background