之前做过蓝牙连接的功能,但更多是按图索骥。这次借编写YModem升级工具完成蓝牙多设备同时升级功能的机会,从头梳理一遍蓝牙连接的功能。
更详细信息可以查看官方蓝牙框架文档:《Core Bluetooth Programming Guide》
文章链接:蓝牙连接(swift版)
蓝牙2.0是传统蓝牙,也叫做经典蓝牙。
蓝牙2.0如要上架需进行MFI认证,使用ExternalAccessory框架。
蓝牙4.0因为耗电低,也叫做低功耗蓝牙(BLE)。它将三种规格集于一体,包括传统蓝牙技术、高速技术和低耗能技术。
蓝牙4.0使用CoreBluetooth框架。
一个外设包含多个服务,而每一个服务中又包含多个特征,特征包括特征的值和特征的描述.每个服务包含多个字段,字段的权限有read(读)、write(写)、notify(通知/订阅)。
write:发送信息给外围设备
notify:接收外围设备的通知
read:获取外围设备的信息。当部分设备为只读时,无法使用write发送信息给外围设备,但可以使用read去获取外围设备的信息。
正常多使用write和notify。
蓝牙开发分为两种模式,中心模式(central),和外设模式(peripheral)。一般来讲,我们需要在软件内连接硬件,通过连接硬件给硬件发送指令以完成一些动作的蓝牙开发都是基于中心模式(central)模式的开发,也就是说我们开发的app是中心,我们要连接的硬件是外设。如果需要其他设备连接手机蓝牙,并对手机进行一些操作,那就是基于外设模式(peripheral)的开发。
swift版:
oc版:
常用方法记录用到的方法,代码是具体运用
import CoreBluetoothprivate let BLE_WRITE_UUID = "xxxx"
private let BLE_NOTIFY_UUID = "xxxx"
var centralManager:CBCentralManager?
///扫描到的所有设备
var aPeArray:[CBPeripheral] = []
//当前连接的设备
var pe:CBPeripheral?
var writeCh: CBCharacteristic?
var notifyCh: CBCharacteristic?
实例化
var centralManager = CBCentralManager(delegate: self, queue: nil, options: nil)
开始扫描
centralManager.scanForPeripherals(withServices: serviceUUIDS, options: nil)
连接设备
centralManager.connect(peripheral, options: nil)
断开连接
centralManager.cancelPeripheralConnection(peripheral)
停止扫描
centralManager.stopScan()
发现服务
peripheral.discoverServices(nil)
peripheral.delegate = self发现特征
peripheral.discoverCharacteristics(nil, for: service)
peripheral.services对应搜索特征设置通知
peripheral.setNotifyValue(true, for: characteristic)
将CBCenteralManager实例化:
centralManager = CBCentralManager(delegate: self, queue: nil, options: [CBCentralManagerOptionShowPowerAlertKey:false])
实例化完成后的回调:
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == CBManagerState.poweredOn {
print("powered on")
} else {
if central.state == CBManagerState.poweredOff {
print("BLE powered off")
} else if central.state == CBManagerState.unauthorized {
print("BLE unauthorized")
} else if central.state == CBManagerState.unknown {
print("BLE unknown")
} else if central.state == CBManagerState.resetting {
print("BLE ressetting")
}
}
}
CBPeripheral扫描设备:
centralManager.scanForPeripherals(withServices: serviceUUIDS, options: nil)
发现设备:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
guard !aPeArray.contains(peripheral), let deviceName = peripheral.name, deviceName.count > 0 else {
return
}
}
连接设备:
centralManager.connect(peripheral, options: nil)
设备连接完成后的回调:
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("\(#function)连接外设成功。\ncentral:\(central),peripheral:\(peripheral)\n")
// 设置代理
peripheral.delegate = self
// 开始发现服务
peripheral.discoverServices(nil)
}
Service设备连接失败的回调:
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral:
CBPeripheral, error: Error?) {
print("\(#function)连接外设失败\n\(String(describing:
peripheral.name))连接失败:\(String(describing: error))\n")
// 这里可以发通知出去告诉设备连接界面连接失败
}
连接丢失的回调:
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("\(#function)连接丢失\n外设:\(String(describing:
peripheral.name))\n错误:\(String(describing: error))\n")
// 这里可以发通知出去告诉设备连接界面连接丢失
}
搜索服务(设备连接成功的回调处执行):
peripheral.discoverServices(nil)
发现服务:
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if let error = error {
print("\(#function)搜索到服务-出错\n设备(peripheral):\(String(describing:
peripheral.name)) 搜索服务(Services)失败:\(error)\n")
return
} else {
print("\(#function)搜索到服务\n设备(peripheral):\(String(describing:
peripheral.name))\n")
}
for service in peripheral.services ?? [] {
peripheral.discoverCharacteristics(nil, for: service)
}
}
搜索特征(当发现服务之后即执行搜索):
peripheral.discoverCharacteristics(nil, for: service)
发现特征
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if let _ = error {
print("\(#function)发现特征\n设备(peripheral):\(String(describing: peripheral.name))\n服务(service):\(String(describing: service))\n扫描特征(Characteristics)失败:\(String(describing: error))\n")
return
} else {
print("\(#function)发现特征\n设备(peripheral):\(String(describing: peripheral.name))\n服务(service):\(String(describing: service))\n服务下的特征:\(service.characteristics ?? [])\n")
}
for characteristic in service.characteristics ?? [] {
if characteristic.uuid.uuidString.lowercased().isEqual(BLE_WRITE_UUID) {
pe = peripheral
writeCh = characteristic
} else if characteristic.uuid.uuidString.lowercased().isEqual(BLE_NOTIFY_UUID) {
notifyCh = characteristic
peripheral.setNotifyValue(true, for: characteristic)
}
//此处代表连接成功
}
}
peripheral和特征characteristic,后续发送接收数据时使用获取设备发送的数据:
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic:
CBCharacteristic, error: Error?) {
if let _ = error {
return
}
//拿到设备发送过来的值,可传出去并进行处理
}
发送数据:
peripheral.writeValue(data, for: characteristic, type: .withResponse)
characteristic需要是写入的特征,不能用其他的特征检测发送数据是否成功:
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
if let error = error {
print("\(#function)\n发送数据失败!错误信息:\(error)")
}
}
github代码:BleDemo
欢迎相互学习交流,也欢迎去github点个star。