美文网首页
蓝牙开发-中心设备开发

蓝牙开发-中心设备开发

作者: xiari1991 | 来源:发表于2020-12-12 18:41 被阅读0次
    蓝牙开发
    中心设备开发
    外设开发

    概念理解

    中心设备: 主动连接其他蓝牙设备的一方,可以通过蓝牙指令操作蓝牙设备或读取蓝牙设备数据。如手机蓝牙耳机,手机就是中心设备。
    外设: 提供蓝牙功能的设备,可以被中心设备连接。如手机蓝牙耳机,耳机就是外设。
    服务: 外设提供的功能模块。一个外设可以有多个服务,一个服务可以有一个或多个特征值。
    特征值: 中心设备通过修改特征值或读取特征值来使用外设的提供的服务。如手机可以通过修改音量对应的特征值的大小来实现控制耳机的音量。

    服务的UUID: 服务的UUID是服务的标识,外设上的每个服务都有一个UUID,但不同的外设可能会有相同uuid的服务

    特征的UUID: 特征的UUID是特征的标识,外设上的各服务的每个特征都有一个UUID,但不同的外设可能会有相同uuid的特征

    中心设备的开发流程

    image

    中心设备开发 API

    引入蓝牙框架

    #import <CoreBluetooth/CoreBluetooth.h>
    

    创建中心设备

    //创建中心设备管理者
    self.centralManager = [[CBCentralManager alloc] initWithDelegate:_sharedInstance queue:nil options:nil];
    
    ///蓝牙状态变化回调。
    ///回调时机:
    ///1、创建中心设备管理者后,系统会请求获取蓝牙权限,用户同意或拒绝后,回调该方法
    ///2、用户开启或关闭蓝牙后回调该方法
    - (void)centralManagerDidUpdateState:(CBCentralManager *)central {
        switch (central.state) {
            case CBManagerStateUnknown:
            case CBManagerStateUnsupported:
                NSLog(@"模拟器不支持蓝牙调试");
            case CBManagerStateUnauthorized:
                NSLog(@"未开启蓝牙权限");
                break;
            case CBManagerStatePoweredOff:
                NSLog(@"蓝牙处于关闭状态");
                break;
            case CBManagerStateResetting:
                NSLog(@"蓝牙处于重置状态");
                break;
            case CBManagerStatePoweredOn:
                NSLog(@"蓝牙已开启");
                //扫描外设
                [self scanForPeripherals];
                break;
        }
    
        //转为了block回调
        if (self.centralManagerStateDidUpdate) {
            self.centralManagerStateDidUpdate(central.state);
        }
    }
    

    扫描外设

    外设的属性:名字、信号强度、状态、服务、标志符。

    
    //扫描外设
    //services为nil,会扫描所有的外设
    //serviceUUIDs 是[CBUUID UUIDWithString:@"uuid1"]的集合
    //已连接状态的外设是不会被扫描到的
    //因为有可能不同外设的服务的UUID相同,所以是无法指定扫描某个外设的
    [self.centralManager scanForPeripheralsWithServices:serviceUUIDs options:nil];
    
    ///扫描到外设回调
    ///外设减少不会回调该方法,所以扫描到的蓝牙列表可能过段时间后有些外设是连不上的。可以调用扫描外设方法重新扫描。
    - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI {
        NSString *name = peripheral.name;
        NSLog(@"发现了外设:%@", name);
        
        /** 添加外设到外设列表中,根据外设的identifier.UUIDString避免重复添加
            为什么可以作为唯一标识符:
            1、不同的中心设备扫描同一台外设identifier.UUIDString是不一样的
            2、同一台中心设备每次扫描同一台外设,identifier.UUIDString是不变的 */
        if (name.length > 0) {
            BOOL exist = NO;
            for (CBPeripheral *p in self.peripheralList) {
                if ([p.identifier.UUIDString isEqualToString:peripheral.identifier.UUIDString]) {
                    exist = YES;
                    break;
                }
            }
            if (!exist) {
                [self.peripheralList addObject:peripheral];
            }
        }
        
        //转为了block回调
        self.peripheralsDidUpdate(self.peripheralList);
    }
    

    连接外设

    //peripheral是从peripheralList中找到的自己需要的一台外设
    [self.centralManager connectPeripheral:peripheral options:nil];
    
    
    ///外设连接失败回调
    - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
       //转为了block回调
        self.connectStateDidUpdate(peripheral.state);
        NSLog(@"外设连接失败");
    }
    
    //外设与中心设备连接成功回调
    - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
        //保存当前连接的外设
        self.curPeripheral = peripheral;
        //停止扫描
        [self.centralManager stopScan];
        //设置代理
        peripheral.delegate = self;
        //根据服务的UUID来寻找服务, 传nil则寻找该外设的所有服务
        [peripheral discoverServices:serviceUUIDs];
        //转为了block回调
        self.connectStateDidUpdate(peripheral.state);
        NSLog(@"外设连接成功");
    }
    
    

    扫描服务

     //根据服务的UUID来寻找服务, 传nil则寻找该外设的所有服务
        [peripheral discoverServices:serviceUUIDs];
    
    
    ///外设发现服务回调
    - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
       if (error) {
            //错误处理
            return;
        }
        for (CBService *service in peripheral.services) {
            NSLog(@"发现的服务:%@", service.UUID);
            //寻找该服务的特征,characteristicUUIDs为nil,找的是该服务的所有的特征
            [peripheral discoverCharacteristics:characteristicUUIDs forService:service];
        }
    }
    

    扫描特征

     //寻找该服务的特征,characteristicUUIDs为nil,找的是该服务的所有的特征
     [peripheral discoverCharacteristics:characteristicUUIDs forService:service];
    
    ///外设发现特征回调
    - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
        if (error) {
            return;
        }
    
        for (CBCharacteristic *characteristic in service.characteristics) {
            NSLog(@"发现的特征:%@", characteristic.UUID.UUIDString);
            /** 订阅支持通知的特征 */
            if (characteristic.properties & CBCharacteristicPropertyNotify) {
                [self.curPeripheral setNotifyValue:YES forCharacteristic:characteristic];
            }
            //记录下所有的特征
            [self.characteristics addObject:characteristic];
        }
    }
    
    ///订阅结果回调
    -(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
        if (error) {
            NSLog(@"订阅失败");
        }
        if (characteristic.isNotifying) {
            NSLog(@"订阅成功");
        } else {
            NSLog(@"取消订阅");
        }
    }
    

    使用服务---修改特征值

    //修改UUID为characteristicUUIDStr的特征的值,自定义方法
    - (void)writeData:(NSData *)data characteristicUUIDStr:(NSString *)characteristicUUIDStr callback:(void (^)(BOOL))callback {
        //记录写入回调block
        self.writeCallback = callback;
        ///判断该特征是否在扫描到的特征中存在
        BOOL existUUID = NO;
        for (CBCharacteristic *character in self.characteristics) {
            /** 找到对应UUID的特征进行写操作 */
            if ([character.UUID.UUIDString isEqualToString:characteristicUUIDStr]) {
                existUUID = YES;
                /** 如果该特征有写权限,进行写权限 */
                if (character.properties & CBCharacteristicPropertyWrite) {
                    [self.curPeripheral writeValue:data forCharacteristic:character type:CBCharacteristicWriteWithResponse];
                }else if (character.properties & CBCharacteristicPropertyWriteWithoutResponse) {
                    [self.curPeripheral writeValue:data forCharacteristic:character type:CBCharacteristicWriteWithoutResponse];
                }
                /** 如果该特征没有写权限,回调写入失败 */
                else {
                    self.writeCallback(NO);
                }
                
            }
        }
        
        /** 如果没有找到该UUID对应的特征,回调写入失败 */
        if (!existUUID) {
            NSLog(@"未找到UUID为%@的特征", characteristicUUIDStr);
            self.writeCallback(NO);
        }
    }
    
    //写入特征值结果回调。如果特征支持写入回调才会调用
    - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error {
        if (error) {
            self.writeCallback(NO);
            return;
        }
        NSLog(@"写入成功");
        //回调block
        self.writeCallback(YES);
    }
    

    使用服务---读取特征值&订阅特征通知

    ///主动读取某特征的值,自定义方法
    - (void)readValueForCharacteristicUUIDStr:(NSString *)UUIDStr {
        ///从特征列表中找到特征,并读取
        for (CBCharacteristic *character in self.characteristics) {
            if ([character.UUID.UUIDString isEqualToString:UUIDStr]) {
                //判断该特征是否可读
                if (character.properties & CBCharacteristicPropertyRead) {
                    //读取该特征值
                    [self.curPeripheral readValueForCharacteristic:character];
                }
            }
        }
    }
    
    //订阅某特征
     [self.curPeripheral setNotifyValue:YES forCharacteristic:characteristic];
    
    //1、读取到特征值回调
    //2、收到特征通知也会回调
    - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
        // 拿到外设发送过来的 NSData 数据
        NSData *data = characteristic.value;
        //转为了block回调
        if (self.valueForCharacteristicDidUpdate) {
            self.valueForCharacteristicDidUpdate(characteristic.UUID.UUIDString, data);
        }
        NSLog(@"接收到外设数据回调:%@", data);
    }
    

    相关文章

      网友评论

          本文标题:蓝牙开发-中心设备开发

          本文链接:https://www.haomeiwen.com/subject/halygktx.html