三、用iPhone实现一个外设CBPeripheralManag
2023-05-07 本文已影响0人
LucXion
Peripheral规范:对外广播Peripheral,发布Characteristic,对连接的Central做读写请求的响应,发送Characteristic更新后的值给Central
一、外设的UUID
外设的UUID有两种:
一:16位通用UUID,以 "180D" 为例:"180D"是Bluetooth SIG定义的16位通用UUID,用于识别心率Service,等于128位 "0000180D-0000-1000-8000-00805F9B34FB",当你使用了一些通用的UUID,那么查询服务的时候,UUID在控制台中的输出就是对应的功能,比如 Heart Rate
二:128位 UUID,用于自定义服务、特征,可以通过 $uuidgen 在终端生成。
二、初始化 CBPeripheralManager
// 主服务,primary = true,主服务可以直接被扫描到
lazy var s1:CBMutableService = CBMutableService.init(type: CBUUID.init(string: s1UUID), primary: true)
// 特征
// 1.value != nil ,代表特征值不可变,那么ATT的读写权限(特征许可)permissions 必须是readable,且不会响应中心设备的读取请求,直接返回值
// 2.value = nil,我们可以通过代理- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request;动态响应中心设备的读取请求
lazy var s1c1:CBMutableCharacteristic = CBMutableCharacteristic.init(type: CBUUID.init(string: s1c1UUID), properties: [.read], value: "123".data(using: .utf8), permissions: .readable)
// 描述
lazy var s1c1Des:CBMutableDescriptor = CBMutableDescriptor.init(type: CBUUID(string: CBUUIDCharacteristicUserDescriptionString), value: "我是s1c1的特征描述")
// 初始化外设
peripheralManager = CBPeripheralManager.init(delegate: self, queue: nil)
三、构建服务树
// 一、与中心设备相似,都是验证设备的可用性,但中心设备验证后会直接发起连接,而外设则是在验证设备可用性后构建服务树
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
if(peripheral.state == .poweredOn){
s1.characteristics = [s1c1 as! CBCharacteristic,s1c2 as! CBCharacteristic]
s2.characteristics = [s2c1]
peripheral.add(s2)
s1.includedServices = [s2]
peripheral.add(s1)
}
}
// 二、构建服务树成功,开始广播
func peripheralManager(_ peripheral: CBPeripheralManager, didAdd service: CBService, error: Error?) {
if(error == nil){
// 构建服务树成功
// 特别注意,服务是按添加顺序逐个响应的,只有等到最后一个添加的服务响应成功了,再去广播服务
if(service.uuid == s1.uuid){
let jsonData : [String:Any] = [
CBAdvertisementDataServiceUUIDsKey:[s1.uuid,s2.uuid]
]
// 发布服务以后,设备将服务、特征保存,不能再改变
peripheral.startAdvertising(jsonData)
}
}
}
// 三、广播服务回调
func peripheralManagerDidStartAdvertising(_ peripheral: CBPeripheralManager, error: Error?) {
if(error != nil){
appendPeripheralInfo(content: "广播服务失败 \(error.debugDescription)")
}else {
appendPeripheralInfo(content: "广播服务成功")
}
}
四、只需要对中心设备的请求做出响应
每个请求都要有respond与之对应
// appendPeripheralInfo 是输出内容到控制台的方法,直接忽略,可帮助理解
func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveRead request: CBATTRequest) {
appendPeripheralInfo(content: "接到读请求")
// 接到读写请求的正确处理流程
// 1.判断是否是需要我们处理的 characteristic
if(request.characteristic.uuid.isEqual(s1c1.uuid)){
// 2.判断请求offset是否越界
if(request.offset > s1c1.value?.count ?? 0){
peripheral.respond(to: request, withResult: .invalidOffset)
}else {
let maxLength = s1c1.value?.count ?? 0 - request.offset
let dataLength = min(request.value?.count ?? 0, maxLength)
let data = s1c1.value?.subdata(in: request.offset..<request.offset+dataLength)
request.value = data
peripheral.respond(to: request, withResult: .success)
}
}
}
func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveWrite requests: [CBATTRequest]) {
appendPeripheralInfo(content: "接到写请求")
let a = requests.first!.value!
appendPeripheralInfo(content: String.init(data: a, encoding: .utf8)!)
peripheral.respond(to: requests.first!, withResult: CBATTError.success)
appendPeripheralInfo(content: " success")
}
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) {
appendPeripheralInfo(content: "接到订阅请求")
let updatedValue = "订阅信息".data(using: .utf8)
peripheral.updateValue(updatedValue!, for: s1c2!, onSubscribedCentrals: nil)
}