蓝牙连接(swift版)

发表于 - 8 分钟   |   --

之前做过蓝牙连接的功能,但更多是按图索骥。这次借编写YModem升级工具完成蓝牙多设备同时升级功能的机会,从头梳理一遍蓝牙连接的功能。

一、原理

更详细信息可以查看官方蓝牙框架文档:《Core Bluetooth Programming Guide》

文章链接:蓝牙连接(swift版)

1.基本概念

1.1 蓝牙版本

蓝牙2.0

蓝牙2.0是传统蓝牙,也叫做经典蓝牙。

蓝牙2.0如要上架需进行MFI认证,使用ExternalAccessory框架。

蓝牙4.0

蓝牙4.0因为耗电低,也叫做低功耗蓝牙(BLE)。它将三种规格集于一体,包括传统蓝牙技术、高速技术和低耗能技术。

蓝牙4.0使用CoreBluetooth框架。

1.2 参数

基本参数

一个外设包含多个服务,而每一个服务中又包含多个特征,特征包括特征的值和特征的描述.每个服务包含多个字段,字段的权限有read(读)、write(写)、notify(通知/订阅)。

characteristic的三种操作:

正常多使用write和notify。

2.模式

蓝牙开发分为两种模式,中心模式(central),和外设模式(peripheral)。一般来讲,我们需要在软件内连接硬件,通过连接硬件给硬件发送指令以完成一些动作的蓝牙开发都是基于中心模式(central)模式的开发,也就是说我们开发的app是中心,我们要连接的硬件是外设。如果需要其他设备连接手机蓝牙,并对手机进行一些操作,那就是基于外设模式(peripheral)的开发。

中心模式流程

swift版:

  1. 创建中心设备(CBCentralManager)
  2. 中心设备开始扫描(scanForPeripherals)
  3. 扫描到外围设备之后, 自动调用中心设备的代理方法(didDiscoverPeripheral)
  4. 如果设备过多, 可以将扫描到的外围设备添加到数组
  5. 开始连接, 从数组中过滤出自己想要的设备, 进行连接(connectPeripheral)
  6. 连接上之后, 自动调用中心设备的代理方法(didConnectPeripheral), 在代理中, 进行查找外围设备的服务(peripheral.discoverServices)
  7. 查找到服务之后, 自动调用外围设备的代理(didDiscoverServices), 可通过UUID,查找具体的服务,查找服务(discoverCharacteristics)
  8. 查找到特征之后, 自动调用外围设备的代理(didDiscoverCharacteristics), 通过UUID找到自己想要的特征, 读取特征(readValueForCharacteristic)
  9. 读取到特征之后, 自动调用外设的代理方法(didUpdateValueForCharacteristic),在这里打印或者解析自己想要的特征值.

oc版:

  1. 建立中心角色 [[CBCentralManager alloc] initWithDelegate:self queue:nil]
  2. 扫描外设 cancelPeripheralConnection
  3. 发现外设 didDiscoverPeripheral
  4. 连接外设 connectPeripheral
    • 4.1连接失败 didFailToConnectPeripheral
    • 4.2连接断开 didDisconnectPeripheral
    • 4.3连接成功 didConnectPeripheral
  5. 扫描外设中的服务 discoverServices
    • 5.1发现并获取外设中的服务 didDiscoverServices
  6. 扫描外设对应服务的特征 discoverCharacteristics
    • 6.1发现并获取外设对应服务的特征 didDiscoverCharacteristicsForService
    • 6.2给对应特征写数据 writeValue:forCharacteristic:type:
  7. 订阅特征的通知 setNotifyValue:forCharacteristic:
    • 7.1根据特征读取数据 didUpdateValueForCharacteristic

外设模式流程

  1. 建立外设设备
  2. 设置本地外设的服务和特征
  3. 发布外设和特征
  4. 广播服务
  5. 响应中心的读写请求
  6. 发送更新的特征值,订阅中心


二、实现

常用方法记录用到的方法,代码是具体运用

2.1 前置

变量

private 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.discoverCharacteristics(nil, for: service)

设置通知

peripheral.setNotifyValue(true, for: characteristic)

2.2 代码

2.2.1 流程

实例化

将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")
            }
        }
}

扫描并发现设备

扫描设备:

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)
}

设备连接失败的回调:

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)
        }
        //此处代表连接成功
    }
}

读取设备发送的数据

获取设备发送的数据:

func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic:
CBCharacteristic, error: Error?) {
    if let _ = error {
        return
    }
    //拿到设备发送过来的值,可传出去并进行处理
    
}

向设备发送数据

发送数据:

peripheral.writeValue(data, for: characteristic, type: .withResponse)

检测发送数据是否成功:

func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
    if let error = error {
        print("\(#function)\n发送数据失败!错误信息:\(error)")
    }
}

2.2.2 完整代码下载

github代码:BleDemo

欢迎相互学习交流,也欢迎去github点个star。

Michael Lynx

Michael Lynx

三反昼夜

rss facebook twitter github gitlab youtube mail spotify lastfm instagram linkedin pinterest medium vimeo stackoverflow reddit quora quora