三、用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)
    }
上一篇下一篇

猜你喜欢

热点阅读