前言
蓝牙设备想必大家都很熟悉了,相关的开发资料也是很多了,这里就不必多说了
iOS蓝牙的开发专题
iOS蓝牙开发(一)蓝牙相关基础知识
iOS蓝牙开发(二)ios连接外设的代码实现
iOS蓝牙开发(三)app作为外设被连接的实现
iOS蓝牙开发(四)BabyBluetooth蓝牙库介绍
iBeacon 是苹果公司2013年9月发布的移动设备用OS(iOS7)上配备的新功能。其工作方式是,配备有 低功耗蓝牙(BLE)通信功能的设备使用BLE技术向周围发送自己特有的ID,接收到该ID的应用软件会根据该ID采取一些行动。比如,在店铺里设置iBeacon通信模块的话,便可让iPhone和iPad上运行一资讯告知服务器,或者由服务器向顾客发送折扣券及进店积分。此外,还可以在家电发生故障或停止工作时使用iBeacon向应用软件发送资讯。
苹果 WWDC 14 之后,对 iBeacon 加大了技术支持和对其用于室内地图的应用有个更明确的规划。苹果公司公布了 iBeacon for Developers 和 Maps for Developers 等专题页面。
应用场景
- 侦测iPhone进入或者离开某个iBeacon的范围触发事件
- 侦测iPhone跟iBeacon的距离,依据不同的距离触发事件
1.比如,当你在国家博物馆参观的时候,当你走进《四羊方尊》前,APP侦测到装在这个藏品展牌底座的iBeacon,于是APP就开始自动播放相关的介绍,透过AirPods传进你的耳朵,这样的讲解真的也算是一种创新!
2.再比如,在地下车库按照三点确定一个稳定区域的设计,布置好iBeacon设备,也能设计出一套室内导航的方案!
如何获得
如何去获得这样的设备呢?其实你打开某宝某多某东,这类的产品数不胜数。
其实你只是在开发阶段,也可以自己去模拟一个iBeacon的设备。因为做iOS开发的我们都有一台iPhone&Mac,高版本的设备都有变身成iBeacon的蓝牙(bluetooth)能力。
将Mac或者iPhone变成iBeacon
-方法1: [Apple官方文档-将iPhone变成iBeacon(https://developer.apple.com/documentation/corelocation/turning_an_ios_device_into_an_ibeacon_device)
-
方法2:可以下载一个APP将iPhone/iPad变成iBeacon设备下载APP
IMG_9119.PNG
-
我们可以下载别人已经开发好的应用,安装到我们的Mac上:MactsAsBeacon
然后再去设定它的UUID、major、minor,然后再点击Start按钮,此时你的Mac就配置了一个iBeacon设备,开始发出讯号。
如果你想修改UUID,可以使用下列方法:
1.打开终端(terminal)
2.输入
uuidgen
3.回车按键
image.png
ps: 该项目比较老旧,运行会报错,
解决方案:
在Info.plist文件中,右键单击空白区域,选择 "Add Row" 添加一行。
在新添加的行中,将键名设置为NSBluetoothAlwaysUsageDescription。
在该键的值字段中,提供一条简明扼要的描述,说明您的应用程序为何需要蓝牙权限。例如,您可以写一句话,解释您的应用程序如何使用蓝牙,例如:"用于搜索和连接附近的蓝牙设备"。
保存Info.plist文件并重新构建您的应用程序。
这样做后,您的应用程序将在请求蓝牙权限时显示您提供的描述,以便用户了解为什么需要这些权限,并可以选择允许或拒绝访问。
请确保您的应用程序遵循隐私权规定,并提供清晰的权限描述,以确保用户的隐私权得到尊重。
iBeacon的参数相关
每个设备都有UUID(128bit),major(16bit),minor(16bit);因此我们可以透过这三个标识区分不同的iBeacon。
- 让设备具有相同的UUID & major,利用minor区分
- 让设备具有相同的UUID,利用major & minor区分
- 利用UUID,major,minor来区分
如果不是很复杂的需求,其实前两种区分即可,比如上述的博物馆游览;如果你有分店(UUID)、产品分类(major)和不同产品(minor),就可以用第三种方案。
开发 iBeacon 的 iOS App
这里有官方的相关参考说明
Determining the proximity to an iBeacon device
1. 加入获取位置的权限描述说明
依据Apple以下表格的说明,为了侦测iPhone进入某个iBeacon范围,量测iBeacon间的距离,我们需要在info.plist配置里加入以下两种权限的描述说明:
Apple官方说明:Choosing the Location Services Authorization to Request
Privacy — Location Always and When In Use Usage Description
为了获取博物馆的展品iBeacon信号,请允许获取你的位置
Privacy — Location When In Use Usage Description
为了获取博物馆的展品iBeacon信号,请允许获取你的位置
2. 建立 CLLocationManager,将 controller 设置为 CLLocationManager 的 delegate 且 要求获取位置的权限
import CoreLocation
class ViewController: UIViewController {
var locationManager: CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
}
extension ViewController: CLLocationManagerDelegate {
}
3. 开始侦测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()
}
说明
(1) 利用CLBeaconRegion指定你想要侦测的iBeacon
Apple官方文档:CLBeaconRegion
let region = CLBeaconRegion(proximityUUID: proximityUUID!, identifier: beaconId)
产生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)
在刚刚的例子里,我们假设目前只有一个iBeacon设备,因此利用UUID来区分设备足以,不需要用到major和minor(ps:请记得UUID要和刚刚在Mac iBeacon APP上设定的UUID一致,如此才能侦测到化身iBeacon的Mac)
let region = CLBeaconRegion(proximityUUID: proximityUUID!, identifier: beaconId)
(2) 开始侦测是否进入/离开iBeacon的范围
locationManager.startMonitoring(for: region)
4. 定义CLLocationManagerDelegate 的 function 侦测进入/离开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. 计算距离
有时候我们还想进一步知道iPhone和iBeacon之间的距离,Apple将距离粗略的分为四个等级,由近及远:Immediate 、Near、Far、Unknown
比方在看博物馆展览时,我们希望走到展品前时 App 才呈现相关的资讯,於是我们可从程式判断距离為 Immediate 时显示展品资讯,如此才不会距离画作还有一大段距离,连画都看不清楚时就奇怪地显示展品资讯。
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)
}
}
说明:
利用 startRangingBeacons & stopRangingBeacons 开始 / 停止侦测 iPhone & beacon 的距离。我们在 locationManager(_:didEnterRegion:) 裡才开始侦测距离,因為侦测距离比较耗电,它将不断地量测更新距离。
不过有一点值得注意的,实测时发现 locationManager(:didEnterRegion:) 有可能没被触发,进而让程式不会呼叫 startRangingBeacons,因此永远不会侦测到 iPhone 已经在 beacon 旁边。比方若你原本就在 beacon 范围裡,locationManager(:didEnterRegion:) 将不会被触发。因此测试时最好一开始远离 beacon,在 beacon 范围之外,然后再慢慢地靠近 beacon,进入 beacon 的范围,这样较容易触发 locationManager(_:didEnterRegion:)。(ps: 若想确保我们一定能侦测到 iPhone 就在 beacon 旁边,另一种做法是一开始就同时呼叫 startMonitoring & startRangingBeacons)
let region = CLBeaconRegion(proximityUUID: proximityUUID!, identifier: beaconId)
locationManager.startMonitoring(for: region)
locationManager.startRangingBeacons(in: region)
6. 定义 CLLocationManagerDelegate 的 function 量测距离。
从 CLBeacon 物件的 proximity 判断距离。当我们在 beacon 附近时,此 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")
}
}
}
实验:
利用 Mac 当 iBeacon,然后啟动刚刚开发的程式侦测 beacon,我们可利用此难得的机会运动一下,走走路让 iPhone 靠近和远离 Mac,观察 locationManager(_:didRangeBeacons:in:) 裡 CLBeacon 距离的变化。
在APP进入后台侦测 beacon & 显示通知
我们也可以在APP进入后台侦测 beacon,甚至在 App 没启动但进入 beacon 范围时,由 iOS 自动啟动 App,然后触发 locationManager:didEnterRegion:。比方以下例子,我们在 locationManager:didEnterRegion: 触发时显示通知讯息:
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)
}
}
為了显示通知,记得要先请求使用者的同意。
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
}
实验步骤:
安装 App,然后啟动 App 同意权限后,先将它杀掉,维持 App 不啟动的状态。
把 iPhone 收进胸前左边口袋,走到远离 beacon 的天涯海角散心。
从天涯海角出发,朝著心爱的 beacon 方向前进。
ps:
若你原本就在 beacon 范围裡,locationManager(_:didEnterRegion:) 将不会被触发。因此测试时请记得先远离 beacon。
- 根据 Apple 文件的说明,为了在APP进入后台侦测到进入 beacon 范围时启动 App,我们得将 Capabilities 页面 Background Modes 的 Location Updates 打开。不过根据实测的结果,不需打开 Location Updates 一样可触发 locationManager:didEnterRegion: & application(_:didFinishLaunchingWithOptions:)。
Handling location updates in the background
image.png
image.png
网友评论