文章目录
一、蓝牙BLE
BLE是蓝牙4.0(Bluetooth low energy)的简称,特点就是低耗电。
二、蓝牙设备间是怎么连接交互的?
只要是集成了蓝牙BLE模块的设备,都可以通过蓝牙协议栈(GATT、ATT、L2CAP)进行交互。iphone和mac都集成了BLE,我们可以通过框架与底层的蓝牙协议栈进行交互。
举例:当iPhone作为中心设备时,通过CBCentralManager来管理 Remote Peripheral(CBPeripheral、CBCharacteristic、CBService).
当iPhone作为外设时,通过CBPeripheralManager、可变的CBMutableService、CBMutableCharacteristic提供服务。
中心设备和外设的区别与规范
中心设备Central
是发起蓝牙连接的设备,并对外设Peripheral进行管理。
中心设备的规范需要提供三个功能:
1.搜索连接外设;
2.与外设提供的数据交互;
3.订阅一个当数据发生变化就会发出通知的特征Characteristic。
外设Peripheral
通过Radio(无线电广播设备)广播数据包,提供数据的一方。外设的规范也需要提供三个功能:
1.发布、广播服务Service;
2.响应对特征的读写请求;
3.响应对特征的订阅请求。
三、蓝牙连接
1. 初始化蓝牙中心
CBCentralManager 是中心设备管理者,并设置代理
let dic = [CBCentralManagerOptionRestoreIdentifierKey: kRestoreIdentifierKey]
centralManager = CBCentralManager.init(delegate: self, queue: .main, options: nil)
options:
CBCentralManagerOptionShowPowerAlertKey
用于当中心管理类被初始化时若此时蓝牙系统为关闭状态,是否向用户显示警告对话框。该字段对应的是NSNumber类型的对象,默认值为NO
CBCentralManagerOptionRestoreIdentifierKey
中心管理器的唯一标识符,系统根据这个标识识别特定的中心管理器,为了继续执行应用程序,标识符必须保持不变,才能还原中心管理类
判断蓝牙状况,能获得当前设备是否能作为 central
// MARK: - CBCentralManagerDelegate
extension DKCBCenterManager: CBCentralManagerDelegate {
// 蓝牙状态
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .poweredOn:
scanBluetooth()
case .poweredOff:
delegate?.bleDidUpdateState(central)
default:
break
}
}
}
- 状态未知
CBCentralManagerStateUnknown = 0, - 连接断开 即将重置
CBCentralManagerStateResetting, - 该平台不支持蓝牙
CBCentralManagerStateUnsupported, - 未授权蓝牙使用 hovertree.com
CBCentralManagerStateUnauthorized, - 蓝牙关闭
CBCentralManagerStatePoweredOff, - 蓝牙正常开启
CBCentralManagerStatePoweredOn,
2. 扫描蓝牙
let options: [String: Any] = [CBCentralManagerScanOptionAllowDuplicatesKey: NSNumber(value: false)]
centralManager.scanForPeripherals(withServices: nil, options: options)
-
UUID
表示外设的服务标识,当serviceUUIDs参数为nil时,将返回所有发现的外设(苹果不推荐此种做法);当填写改服务标识时,系统将返回对应该服务标识的外设 -
options
CBCentralManagerScanOptionAllowDuplicatesKey
是否允许重复扫描设备,默认为NO,官方建议此值为NO,当为YES时,可能对电池寿命产生影响,建议在必要时才使用
CBCentralManagerScanOptionSolicitedServiceUUIDsKey
想要扫描的服务的UUID,对应一个NSArray数值
3. 停止扫描
centralManager?.stopScan()
4. 连接蓝牙
let options = [CBConnectPeripheralOptionNotifyOnNotificationKey: true]
centralManager?.connect(peripheral, options: nil)
CBConnectPeripheralOptionNotifyOnConnectionKey
应用程序被挂起时,成功连接到外设,是否向用户显示警告对话框,对应NSNumber对象,默认值为NO
CBConnectPeripheralOptionNotifyOnDisconnectionKey
应用程序被挂起时,与外设断开连接,是否向用户显示警告对话框,对应NSNumber对象,默认值为NO
CBConnectPeripheralOptionNotifyOnNotificationKey
应用程序被挂起时,只要接收到给定peripheral的通知,是否就弹框显示
5. 获取连接过的设备
// 重新获取当前连接着的设备列表
var peripheralArray = centralManager.retrieveConnectedPeripherals(withServices: [peripheraUUID])
// 重新获取已发现的设备列表
guard let bleUUID = bleUUID else { return }
peripheralArray = centralManager.retrievePeripherals(withIdentifiers: [bleUUID])
6. 断开蓝牙连接
centralManager?.cancelPeripheralConnection(peripheral)
7. 蓝牙中心代理
CBCentralManagerDelegate
7.1 蓝牙状态
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .poweredOn:
scanBluetooth()
case .poweredOff:
delegate?.bleDidUpdateState(central)
default:
break
}
}
7.2 发现蓝牙设备
func centralManager(_ central: CBCentralManager,
didDiscover peripheral: CBPeripheral,
advertisementData: [String: Any],
rssi RSSI: NSNumber) {
}
7.3 蓝牙连接
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
stopScanBluetooth()
// 连接蓝牙设备的代理
peripheral.delegate = self
self.peripheral = peripheral
}
7.4 蓝牙连接失败
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
DKLog("*************** 蓝牙连接失败")
delegate?.bleDidFailToConnectPeripheral(peripheral, error: error)
}
7.5 蓝牙断开连接
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
DKLog("*************** 断开蓝牙连接")
delegate?.bleDidDisconnectPeripheral(peripheral, error: error)
}
7.6 蓝牙恢复连接
func centralManager(_ central: CBCentralManager, willRestoreState dict: [String: Any]) {
let arr = dict[CBCentralManagerRestoredStatePeripheralsKey]
guard let peripheralArr = arr as? [CBPeripheral] else {
return
}
let meek = peripheralArr[0]
DKLog("*************** 蓝牙恢复连接 \(meek)")
// self.connectPeripheral(meek, delegate: self)
}
8. 蓝牙设备服务
CBPeripheralDelegate
8.1 读取蓝牙 RSSI
func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) {
delegate?.bleDidReadRSSI(RSSI)
}
8.2 发现蓝牙服务
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
// DKLog("*************** 发现蓝牙服务 \(peripheral.services)")
peripheral.services?.forEach({ service in
peripheral.discoverCharacteristics(nil, for: service)
})
}
8.3 订阅蓝牙特征
func peripheral(_ peripheral: CBPeripheral,
didDiscoverCharacteristicsFor service: CBService,
error: Error?) {
// DKLog("*************** 订阅蓝牙特征 \(service.characteristics)")
if service.uuid.uuidString == configuration?.serviceUUIDString.uppercased() {
characteristic_serve = service
service.characteristics?.forEach({ characteristic in
if characteristic.uuid.uuidString == configuration?.writeCharacteristicUUIDString.uppercased() {
characteristic_write = characteristic
}
if characteristic.uuid.uuidString == configuration?.readCharacteristicUUIDString {
characteristic_read = characteristic
peripheral.setNotifyValue(true, for: characteristic)
}
})
}
delegate?.bleDidDiscoverCharacteristicsForService(peripheral, error: error)
}
8.4 蓝牙订阅成功
func peripheral(_ peripheral: CBPeripheral,
didUpdateNotificationStateFor characteristic: CBCharacteristic,
error: Error?) {
DKLog("*************** 订阅蓝牙通知 成功")
delegate?.bleDidUpdateNotificationStateForCharacteristic(characteristic, error: error)
}
8.5 蓝牙写数据回调
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
DKLog("*************** didWriteValueForCharacteristic")
DKLog(error)
DKLog(characteristic)
}
8.6 蓝牙读数据
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
delegate?.bleDidUpdateValue(characteristic, error: error)
}
9. 蓝牙写数据
peripheral.writeValue(wdata, for: characteristic_write, type: .withoutResponse)
10. 蓝牙读数据
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
delegate?.bleDidUpdateValue(characteristic, error: error)
}
}