章节连接
iOS Core Bluetooth_1 概述
iOS Core Bluetooth_2 基础知识
iOS Core Bluetooth_3 用作中央设备的常用方法(1/2)[swift实现]
iOS Core Bluetooth_4 用作中央设备的常用方法(2/2)[swift实现]
写在前面
在蓝牙低功耗通信中发挥核心作用的设备执行许多常见任务,例如,发现并连接到可用的外围设备,以及探索外围设备所提供的数据并与之交互。实现外围角色的设备还执行许多常见的其他任务,例如发布和广告服务,以及响应来自连接的中心的读取,写入和订阅请求。
在本章中,您将从中央学习如何使用Core Bluetooth框架执行最常见的Bluetooth低能耗任务。以下基于代码的示例将帮助您开发应用程序,以在本地设备上实现核心角色。具体来说,您将学习如何:
- 实例化中央管理器对象
- 发现并连接到正在广播的外围设备
- 在连接到外围设备后浏览其数据
- 发送读写请求到外围服务的特征值
- 订阅特征值以在更新时被通知
在本文中找到的代码示例是简单抽象的。您可能需要进行适当的更改以将其合并到您的真实应用中。
1 实例化中央设备管理器
由于CBCentralManager对象是本地中央设备的核心蓝牙面向对象的表示形式,因此您可以在执行任何蓝牙低能耗事务之前分配和初始化中央管理器实例。您可以通过调用中央管理器的initWithDelegate:queue:options:方法来初始化中央管理器,代码如下:
注意:在此示例中,self被设置为接收任何外围角色事件的委托。当您将调度队列指定为时nil,外围设备管理器使用主队列调度外围设备角色事件。
创建外围设备管理器时,外围设备管理器将调用peripheralManagerDidUpdateState:其代理对象的方法。您必须实现此代理方法,以确保支持低功耗蓝牙并可以在本地外围设备上使用。通常可以在用extension来实现,实现代码如下:(完整版本)
internal func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .poweredOn:
// ... so start working with the peripheral
os_log("CBManager is powered on")
retrievePeripheral()
case .poweredOff:
os_log("CBManager is not powered on")
// In a real app, you'd deal with all the states accordingly
return
case .resetting:
os_log("CBManager is resetting")
// In a real app, you'd deal with all the states accordingly
return
case .unauthorized:
// In a real app, you'd deal with all the states accordingly
if #available(iOS 13.0, *) {
switch central.authorization {
case .denied:
os_log("You are not authorized to use Bluetooth")
case .restricted:
os_log("Bluetooth is restricted")
default:
os_log("Unexpected authorization")
}
} else {
// Fallback on earlier versions
}
return
case .unknown:
os_log("CBManager state is unknown")
// In a real app, you'd deal with all the states accordingly
return
case .unsupported:
os_log("Bluetooth is not supported on this device")
// In a real app, you'd deal with all the states accordingly
return
@unknown default:
os_log("A previously unknown central manager state occurred")
// In a real app, you'd deal with yet unknown cases that might occur in the future
return
}
}
2 发现正在广播的外围设备
实例化后,中央管理器的第一项任务是发现外围设备。外围设备通过广播来告知其存在。您的应用通过调用中央管理器的scanForPeripheralsWithServices:options:方法来发现附近正在做广告的外围设备:
centralManager.scanForPeripherals(withServices: [TransferService.serviceUUID],
options: [CBCentralManagerScanOptionAllowDuplicatesKey: true])
注意:如果nil为第一个参数指定,则中央管理器将返回所有发现的外围设备,而不管其支持的服务如何。在真实应用中,通常需要指定一个CBUUID对象数组,每个对象代表外围设备正在广播的服务的通用唯一标识符(UUID)。当您指定服务UUID的数组时,中央管理器仅返回广播这些服务的外围设备,从而使您仅扫描到您可能希望扫描的设备。CBUUID的声明方法在后文中涉及。
中央管理器每次发现外围设备时,都会调用centralManager:didDiscoverPeripheral:advertisementData:RSSI:其代理对象的方法。新发现的外围设备作为CBPeripheral对象返回。如果您打算连接到发现的外围设备,请对其进行强引用,以使系统不会取消分配它。以下示例显示了一个使用类属性来维护对发现的外围设备的引用的方案,仍通常在extension中进行实现:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
// Reject if the signal strength is too low to attempt data transfer.
// Change the minimum RSSI value depending on your app’s use case.
guard RSSI.intValue >= -50
else {
os_log("Discovered perhiperal not in expected range, at %d", RSSI.intValue)
return
}
os_log("Discovered %s at %d", String(describing: peripheral.name), RSSI.intValue)
// Device is in range - have we already seen it?
if discoveredPeripheral != peripheral {
// Save a local copy of the peripheral, so CoreBluetooth doesn't get rid of it.
discoveredPeripheral = peripheral
// And finally, connect to the peripheral.
os_log("Connecting to perhiperal %@", peripheral)
centralManager.connect(peripheral, options: nil)
}
}
如果您希望连接到多个设备,则可以保留一个Array发现的外围设备。无论如何,一旦找到了要连接的所有外围设备,就停止扫描其他设备以节省电量,代码如下:
3 扫描后连接发现的外围设备
在发现您感兴趣的外围设备广告服务之后,您可以通过调用中央管理器的connectPeripheral:options:方法来请求与外围设备的连接。代码如下:
如果连接请求成功,则中央管理器将调用centralManager:didConnectPeripheral:其代理对象的方法。在开始与外围设备进行交互之前,请设置其代理以确保该委托收到适当的回调,通常也使用extension进行实现,代码如下:
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral){
// 设置代理
peripheral.delegate = self
// 开始发现服务
peripheral.discoverServices(nil)
// 保存当前连接设备
self.peripheral = peripheral
// 这里可以发通知出去告诉设备连接界面连接成功
}
如果连接失败,也需要调用对应的 central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error? 代理方法进行回调,实现如下:
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
os_log("Failed to connect to %@. %s", peripheral, String(describing: error))
cleanup()
}
其他发现服务与特征,读取,订阅与编写特征值的方法将在下文中实现。