iBeacon開(kāi)發(fā)之IoT&Swift&OC&iOS

前言

藍(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

    IMG_9119.PNG

  • 我們可以下載別人已經(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)狮暑。

image.png

如果你想修改UUID鸡挠,可以使用下列方法:
1.打開(kāi)終端(terminal)
2.輸入

uuidgen

3.回車按鍵


image.png

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

image.png

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

image.png

比方在看博物館展覽時(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)缩麸。

一旦進(jìn)入 beacon 的訊號(hào)范圍,此時(shí)將觸發(fā) function locationManager:didEnterRegion:赡矢,口袋裡的 iPhone 將傳來(lái)通知聲音杭朱,顯示著通知訊息,xxx就在你身邊吹散。
IMG_9120.PNG

ps:

若你原本就在 beacon 范圍裡弧械,locationManager(_:didEnterRegion:) 將不會(huì)被觸發(fā)。因此測(cè)試時(shí)請(qǐng)記得先遠(yuǎn)離 beacon空民。

  1. 根據(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
    image.png

    image.png
image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末耸棒,一起剝皮案震驚了整個(gè)濱河市荒澡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌与殃,老刑警劉巖单山,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異幅疼,居然都是意外死亡米奸,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)爽篷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)悴晰,“玉大人,你說(shuō)我怎么就攤上這事≌∠” “怎么了漂辐?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)棕硫。 經(jīng)常有香客問(wèn)我髓涯,道長(zhǎng),這世上最難降的妖魔是什么哈扮? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任纬纪,我火速辦了婚禮,結(jié)果婚禮上滑肉,老公的妹妹穿的比我還像新娘包各。我一直安慰自己,他們只是感情好赦邻,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布髓棋。 她就那樣靜靜地躺著,像睡著了一般惶洲。 火紅的嫁衣襯著肌膚如雪按声。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,146評(píng)論 1 297
  • 那天恬吕,我揣著相機(jī)與錄音签则,去河邊找鬼。 笑死铐料,一個(gè)胖子當(dāng)著我的面吹牛渐裂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播钠惩,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼柒凉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了篓跛?” 一聲冷哼從身側(cè)響起膝捞,我...
    開(kāi)封第一講書(shū)人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎愧沟,沒(méi)想到半個(gè)月后蔬咬,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡沐寺,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年林艘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片混坞。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡狐援,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情咕村,我是刑警寧澤场钉,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布蚊俺,位于F島的核電站懈涛,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏泳猬。R本人自食惡果不足惜批钠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望得封。 院中可真熱鬧埋心,春花似錦、人聲如沸忙上。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)疫粥。三九已至茬斧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間梗逮,已是汗流浹背项秉。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留慷彤,地道東北人娄蔼。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像底哗,于是被迫代替她去往敵國(guó)和親岁诉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353