由于公司项目需求,研究一下iOS
的蓝牙(中心者模式)
一.概念名词
服务:蓝牙外围设备对外连接必定提供一个或者多个服务,服务下边包含多个特征.
CBService
的属性有:peripheral
外围设备,isPrimary
服务类型,includedServices
服务列表,characteristics
特征列表.
特征:存在于服务的下边,一个服务包含多个特征,特征中有一个属性value
,就是蓝牙传输的数据,特征是于外界的最小单位.
UUID:蓝牙设备的唯一标识.
二.蓝牙设备的连接步骤
- 创建
CBCentralManager
中心设备管理者 - 使用
scanForPeripherals
方法通过中心设备管理者
扫描外围设备 - 使用
connect
方法连接外围设备 - 连接外围设备成功,设置外围设备
delegate
,开始扫描服务
- 通过
discoverCharacteristics
方法扫描服务特征
- 从外围设备读取数据
- 给外围设备发送数据
三.代码实现
- 创建
CBCentralManager
中心设备管理者,设置管理者代理
,当CBCentralManager
管理者被创建以后,就会调用centralManagerDidUpdateState
方法.在该方法中可以检测蓝牙状态.
// 中心设备管理者
var manager : CBCentralManager!;
// 在viewDidLoad中创建CBCentralManager,并设置代理
override func viewDidLoad() {
super.viewDidLoad()
manager = CBCentralManager(delegate: self, queue: nil)
manager.delegate = self;
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .unknown:
print("未知蓝牙")
break
case .resetting:
print("蓝牙连接暂时丢失")
break
case .unsupported:
print("不支持蓝牙")
break
case .unauthorized:
print("未授权")
break
case .poweredOff:
print("未开启蓝牙")
break
case .poweredOn:
print("蓝牙已开启")
break
default:
break;
}
}
- 使用
scanForPeripherals
方法通过中心设备管理者
扫描外围设备.
// 开始扫描外围设备,这里可以传入指定服务.
// 如果扫描到设备会调用方法
// centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber)
manager.scanForPeripherals(withServices: nil, options: nil)
- 发现外围设备
将扫描到的外围设备保存到一个外围设备数组peripheralArray
中,用tableView
展示peripheralArray
中的内容,刷新tableView
数据.
// 发现外围设备
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print(peripheral.name ?? 0)
// 这里peripheral有时候返回的是空
// 将发现的设备添加到外围设备数组中
if peripheral.name != nil {
peripheralArray.append(peripheral)
}
tableView.reloadData()
}
- 连接外围设备成功,设置外围设备
delegate
,开始扫描服务
点击tableView
中的cell
,取出对应外围设备数组peripheralArray
中的外围设备,开始连接外围设备.如果设备连接成功会调用方法centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
.如果连接失败则会调用方法centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?)
,设置外围设备的代理delegate
,并且开始扫描服务
.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
peripheral = peripheralArray[indexPath.row] as! CBPeripheral
// 这里可以做判断,满足我们的条件才连接
if peripheral.name == "LF-000010" {
// 停止扫描
manager.stopScan()
// 开始连接
manager.connect(peripheral, options: nil)
}
}
// 连接外围设备成功
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("连接到了")
central.stopScan()
// 设置外设代理
peripheral.delegate = self
// 发现服务,如果传nil,就会发现所有的服务
peripheral.discoverServices(nil)
}
- 通过
discoverCharacteristics
方法扫描服务特征
当扫描服务
成功以后会调用方法peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?)
,在这里调用peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?)
方法,扫描特征值
.
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
// 外围设备有很多服务,服务中有很多特征.
//发现服务
for service in peripheral.services! {
if service.uuid.uuidString == "49535343-FE7D-4AE5-8FA9-9FAFD205E455" {
print("发现服务")
// 扫描特征值
peripheral.discoverCharacteristics(nil, for: service)
}
}
}
// 扫描到特征值
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if error != nil {
print("扫描特征错误")
return
}
for characteristic in service.characteristics! {
//发现特征
print(characteristic)
if characteristic.uuid.uuidString == "49535343-1E4D-4BD9-BA61-23C647249616" {
// 监听特征
peripheral.setNotifyValue(true, for: characteristic)
}
print(characteristic)
}
}
- 接收到数据
因为已经对特征
进行了监听,如果往外围设备的特征里写数据,就会调用peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?)
方法
// 接收到数据
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
print(characteristic.value)
}
- 给外围设备发送数据
//第一个参数是已连接的蓝牙设备 ;第二个参数是要写入到哪个特征; 第三个参数是通过此响应记录是否成功写入
peripheral.writeValue(<#T##data: Data##Data#>, for: <#T##CBCharacteristic#>, type: <#T##CBCharacteristicWriteType#>)
中间有些问题待处理,后续更新...