iBeacon是蘋果公司提出的「一種可以讓附近手持電子設備檢測到的一種新的低功耗、低成本信號傳送器」的一套可用於室內定位系統的協議。[1][2][3][4][5] 這種技術可以使一個智慧型手機或其他裝置在一個iBeacon基站的感應範圍內執行相應的命令。[6]
這是幫助智慧型手機確定他們大概位置或環境的一個應用程式。在一個iBeacon基站的幫助下,智慧型手機的軟體能大概找到它和這個iBeacon基站的相對位置。iBeacon能讓手機收到附近售賣商品的通知,也可以讓消費者不用拿出錢包或信用卡就能在銷售點的POS機上完成支付。iBeacon技術通過低功耗藍牙(BLE),也就是智能藍牙來實現。[7]
iBeacon為利用低功耗藍牙可以近距離感測的功能來傳輸通用唯一識別碼的一個app或作業系統。[8] 這個識別碼可以在網上被查找到用以確定設備的物理位置[9]或者可以在設備上觸發一個動作比如在社交媒體簽到或者推送通知。
各種供應商創造了不同形式的iBeacon硬體設備,包括小硬幣電池設備,隨身碟和藍牙4.0通用加密狗。[10]
Beacon 像燈塔一樣一直發送 藍芽的廣告訊號,主要有 UUID, Major 及 Minor 再包含一些 payload 資料。而 UUID 可以代表一個公司, Major 及 Minor 則可以讓我們再分別定義 分公司 或 地區等等。
Beacon 要透過藍芽去掃描它,iOS就內建有 Core Location APIs 可以使用。而 Android 則可以使用 Beacon Library 來掃 Beacon。
在一開始測試 Beacon 時,建議使用 Android 安裝 掃描 Beacon 的 App比較方便,因為 iPhone 無法直接掃描,需要輸入 UUID 等資訊才可以掃。一開始掃到時,會有進入這個 Beacon 區域的事件 (Monitoring),當進入 Beacon 這個區域後,就可以一直掃描這個 Beacon (Ranging),然後取得它的 RSSI 值來判斷跟它的距離。
最後如果掃不到這個 Beacon 的話,會有一個 離開這個 Beacon 區域的事件 (Monitoring)。
Beacon 可以做以下的應用:
1.室用定位
網路上的文章都說它可以用在室內定位,在一個辦公室中,放3個Beacon利用三角定位來找出人在那裡,看看能不能取得每個人行走的路線,未來還可以分析那條路是熱區,或是那個員工都會去找那個員工之類的分析。
測試結果發現, Beacon 過了3公尺後,RSSI值後不穩定,所以我真的要定位準的話,就要買很多顆的 Beacon。一顆穩定的 Beacon ,大約NT$500,滿便宜的,還可以使用標準的3號電池來更換。
2.自動簽到、簽退
前面提到,我們可以知道進入、離開及一直掃描 Beacon ,所以我們可以自動記錄這些資訊。
就可以知道員工幾點到公司、幾點離開公司。
Android的部份如果要在背景掃的話,就要使用 Service,Android 6.0 還要加入白名單。
而iOS內建就Support在背景處理(App拉掉,還是會運作),但雖然 App 知道進入或離開 Beacon 區域,這時 Http 卻不給用,因為畫面是暗的。解法就是當 User 進入或離開時,發一個 Local 的通知,讓手機亮起來,這時 Http 就可以用,所以就可以將資料送到 Server 上了(只是有點擾人)。
3.控制門禁,達到自動開門
當知道人與Beacon的距離之後,因為我們公司有門禁,進出都要刷卡。有時開會時,手上會拿筆電或其他的東西,再要刷卡實在不太方便。當員工靠近門時,Server收到資訊之後,就自動開門。
教學文章:
iBeacon 教學(swift 3, iOS)
https://medium.com/@jerrywang0420/ibeacon-%E6%95%99%E5%AD%B8-swift-3-ios-1d4ea88311be
iBeacon Tutorial with iOS and Swift
https://www.raywenderlich.com/152330/ibeacon-tutorial-ios-swift
How To Use iBeacons in iOS 7 to Enhance Your Apps
https://www.appcoda.com/ios7-programming-ibeacons-tutorial/
使用方法,還滿簡單的。
先 LINK
Go to your project settings and scroll to the bottom. Click the “+” button under “Linked Frameworks and Libraries” to add CoreBluetooth.framework and CoreLocation.framework.
我實際上只有使用 CoreLocation.framework, 沒有使用 CoreBluetooth 也可以正常執行。
接著是設定 plist 或去勾 Capabilities, 直接改 plist 比較快:
<key>LSRequiresIPhoneOS</key> <true/> <key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict> <key>NSLocationAlwaysAndWhenInUseUsageDescription</key> <string>進入Beacon區域檢測必須確認您的位址</string> <key>NSLocationWhenInUseUsageDescription</key> <string>進入Beacon區域檢測必須確認您的位址</string> <string>This app requires access to the photo library.</string> <key>UIBackgroundModes</key> <array> <string>bluetooth-central</string> <string>external-accessory</string> <string>location</string> </array>
iOS 在 appDelegate 裡 call server side 的結果:
[TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.47.58] input json: {"platform":"iOS","inRegion":false} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.48.39] input json: {"platform":"iOS","inRegion":false} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.48.39] input json: {"platform":"iOS","inRegion":true} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.49.21] input json: {"platform":"iOS","inRegion":false} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.49.21] input json: {"platform":"iOS","inRegion":true} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.50.03] input json: {"platform":"iOS","inRegion":false} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.50.03] input json: {"platform":"iOS","inRegion":true} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.50.50] input json: {"platform":"iOS","inRegion":false} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.50.56] input json: {"platform":"iOS","inRegion":true} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.51.36] input json: {"platform":"iOS","inRegion":false} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.51.42] input json: {"platform":"iOS","inRegion":true} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.52.23] input json: {"platform":"iOS","inRegion":false} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.52.29] input json: {"platform":"iOS","inRegion":true} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.53.10] input json: {"platform":"iOS","inRegion":false} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.53.15] input json: {"platform":"iOS","inRegion":true} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.53.56] input json: {"platform":"iOS","inRegion":false} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.54.02] input json: {"platform":"iOS","inRegion":true} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.54.43] input json: {"platform":"iOS","inRegion":false} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.54.49] input json: {"platform":"iOS","inRegion":true} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.55.30] input json: {"platform":"iOS","inRegion":false} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.55.36] input json: {"platform":"iOS","inRegion":true} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.56.17] input json: {"platform":"iOS","inRegion":false} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.56.23] input json: {"platform":"iOS","inRegion":true} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.57.04] input json: {"platform":"iOS","inRegion":false} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.57.09] input json: {"platform":"iOS","inRegion":true} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.58.12] input json: {"platform":"iOS","inRegion":false} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.58.13] input json: {"platform":"iOS","inRegion":true} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.58.54] input json: {"platform":"iOS","inRegion":false} [TRACE] [tw..servlet.last_seen_v1->doPost@40 2018.04.25-15.58.54] input json: {"platform":"iOS","inRegion":true}
結果說明:
假設目前的程式會在 didEnterRegion 時送出一個 “inRegion”:true 的json 到 server side API.
假設目前的程式會在 didExitRegion 時送出一個 “inRegion”:false 的json 到 server side API.
假設目前程式使用下面的 code , delay 5秒送出一個 local notification:
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:5 repeats:NO]; UNNotificationRequest *notificationRequest = [UNNotificationRequest requestWithIdentifier:@"KFGroupNotification" content:content trigger:trigger]; [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:notificationRequest withCompletionHandler:^(NSError * _Nullable error) { }];
從結果來看,固定會先觸發didExitRegion,再觸發 didEnterRegion。如果在 exit 和 enter 相隔5秒內,