美文网首页
iOS蓝牙开发-1-通识

iOS蓝牙开发-1-通识

作者: ___吉 | 来源:发表于2017-07-11 22:25 被阅读0次

    个人认为iOS蓝牙开发算是相对偏门的领域,做iOS蓝牙相关的开发也有一段时间了,在此写下蓝牙相关的东西,一则方便日后查阅,二则给后来之人一点参考。
    关于蓝牙是什么就不多做解释了,百度一搜一大把。iOS蓝牙开发。蓝牙开发有两种:

        1.手机做中心 - CBCentralManager、外部硬件做外设 - CBPeripheral
        2.外部硬件做中心 - CBCentralManager、手机做外设 - CBPeripheral
    

    一般情况下开发,都是以手机(App)作为中心,硬件设备(智能硬件、手环之类的)作为外设。这里只记录这种情况。
    最开始主要有两个概念:服务(CBService)、特征(CBCharacteristic)。
    服务:每个设备都会有一些服务,每个服务里面都会有一些特征,特征就是具体键值对,提供数据的地方。每个特征属性分为这么几种:读,写,通知这么几种方式。
    特征:读、写数据等。
    画了个简图,没有美术天赋。(“、、、”表示重复的省略)


    外设-服务-特性结构图.png

    刚接触蓝牙的人,估计会不太理解服务和特性是什么东西,我刚刚开始也没搞明白。我最开始接触蓝牙是从大学玩单片机的蓝牙2.0开始的(苹果是4.0),学电子的应该知道。那时候只需要设置AT指令,调用收发数据的API即可。
    我的理解是:
    【1】服务是用来提供传输数据通道的。比如,一个人体数据监测仪,服务A用于传输心率、服务B用于传输血压、服务C用于传输脑电波。。。嗯,是的,这么打个比方吧。
    【2】服务A中(传输心率那个)有:特性1->用于App读取数据、特性2->用于App发送指令或者数据到硬件,特性3->用于读取硬件的mac地址。这样就将这些功能模块(心率、血压、脑电波等)及其接口(读取、发送等)都很好的分开了,我理解成面向对象的解耦。
    下面是已手机App作为中心的大致步骤:

    -[1]创建管理中心,并设置其代理。
    
    -[2]判断手机蓝牙状态。(是否打开、是否支持、是否授权),这里可以做提示用户打开手机蓝牙之类的。。。
    
    -[3]扫描外设。每次扫描到一个蓝牙外设,都会通过管理中心的代理方法将外设相关信息回调过来(外设名字、信号值、广播等),此时可以自定义一个对象用于保存这个外设。然后将这个模型添加进数组中,利用自定义tableview显示出来,就和网络请求展示数据类似。
    
    -[4]连接外设。
    
    -[5]连接外设成功,寻找需要的服务(比如我只需要监测心率,不需要发脑电波,那就只需要找到监测心率那个服务就好了)。
    
    -[6]寻找到需要的服务后,接下来 -> 寻找需要的特性(读数据、写指令、读mac等需要的特性)。找到的这些特性,都将其作为属性保存起来,后续发送数据等会需要用到。
    
    -[7]订阅读数据的特性。这个特性是这样的:每次硬件传输数据过来时,都会走这里,所以需要订阅它,以便能收到硬件的数据。
    
    -[8]发送自己的指令,注意:每次最多只能发送20个字节。
    
    -[9]有以上步骤,收发数据基本OK了,还有的就是写完善功能:自动连接,断线重连,过滤不需要的设备,按指定mac地址连接等等。
    
    

    以下是相关代码:

    ///创建管理中心
        _manager = [[CBCentralManager alloc] initWithDelegate:self
                                                        queue:nil];///默认在主线程中
    ///初始化数组,用于存放搜索到的外设
        _allPeripheral = [NSMutableArray array];
    ///开始扫描外设
        [_manager scanForPeripheralsWithServices:nil options:nil];
    

    以下是管理中心代理方法:

    #pragma mark - - - - - -管理中心代理 - - - - - - - - -
    
    #pragma mark 【1】监测蓝牙状态
    ///这里可以做相应处理,当蓝牙状态: 未打开->提示用于打开蓝牙
    ///                            其他->提示其他
    - (void)centralManagerDidUpdateState:(CBCentralManager *)central{
        switch (central.state){
            case CBManagerStateUnknown:
                NSLog(@"蓝牙-未知");
                break;
            case CBManagerStateUnsupported:
                NSLog(@"蓝牙-不支持");
                break;
            case CBManagerStateUnauthorized:
                NSLog(@"蓝牙-未授权");
                break;
            case CBManagerStatePoweredOff:{///蓝牙关闭
                NSLog(@"蓝牙-已关闭");
            }
                break;
            case CBManagerStateResetting:
                NSLog(@"蓝牙-复位");
                break;
            case CBManagerStatePoweredOn:{///蓝牙打开
                NSLog(@"蓝牙-已打开");
            }
                break;
        }
    }
    
    #pragma mark 【2】发现外部设备
    - (void)centralManager:(CBCentralManager *)central
     didDiscoverPeripheral:(CBPeripheral *)peripheral
         advertisementData:(NSDictionary *)advertisementData
                      RSSI:(NSNumber *)RSSI{
        BLEModel *model = [[BLEModel alloc] initWithPeripheral:peripheral rssi:RSSI advertisementData:advertisementData];
        for (BLEModel *saveModel in _allPeripheral) {
            if ([saveModel.peripheral isEqual:peripheral]) {
                return;
            }
        }
        [_allPeripheral addObject:model];
        [_tableView reloadData];
    }
    
    #pragma mark 【3】连接外部蓝牙设备
    - (void)connectToPeripheral:(CBPeripheral *)peripheral{
        if (!peripheral) {
            return;
        }
        [_manager connectPeripheral:peripheral options:nil];
    }
    
    #pragma mark 【4】连接外部蓝牙设备成功
    - (void)centralManager:(CBCentralManager *)central
      didConnectPeripheral:(CBPeripheral *)peripheral{
        ///连接成功
        NSLog(@"连接成功,开始寻找服务和特征");
        [peripheral discoverServices:nil];
    }
    
    #pragma mark 【5】连接外部蓝牙设备失败
    - (void)centralManager:(CBCentralManager *)central
    didFailToConnectPeripheral:(CBPeripheral *)peripheral
                     error:(NSError *)error{
        ///这里可以尝试重连
        [_manager connectPeripheral:peripheral options:nil];
    }
    
    #pragma mark 【6】蓝牙外设连接断开,自动重连
    - (void)centralManager:(CBCentralManager *)central
    didDisconnectPeripheral:(CBPeripheral *)peripheral
                     error:(NSError *)error{
        ///当连接断开时,会走这个回调,可以做重连等
    }
    

    以下是外设代理方法:

    #pragma mark - - - - - -外设代理 - - - - - - - - - 
    #pragma mark 【1】寻找蓝牙服务
    -(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
        
        if(error){
            NSLog(@"外围设备寻找服务过程中发生错误,错误信息:%@",error.localizedDescription);
        }
        
        CBUUID *serviceUUID=[CBUUID UUIDWithString:kServiceUUID];
        for (CBService *service in peripheral.services) {
            
            if([service.UUID isEqual:serviceUUID]){
                [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:kNotifyUUID],[CBUUID UUIDWithString:kWriteUUID],[CBUUID UUIDWithString:kReadMacUUID]] forService:service];
            }
        }
    }
    
    #pragma mark 【2】寻找蓝牙服务中的特征
    - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
        if (error) {//报错直接返回退出
            NSLog(@"didDiscoverCharacteristicsForService error : %@", [error localizedDescription]);
            return;
        }
        
        for (CBCharacteristic *characteristic in service.characteristics)
        {
            if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kNotifyUUID]]){///订阅读数据,执行此行代码,每次收到数据时才会走下面 “【8】直接读取特征值被更新后”
                [peripheral setNotifyValue:YES forCharacteristic:characteristic];
                self.readCharacteristic = characteristic;
            }
            
            if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kWriteUUID]]) {
                ///保存写数据的特征,用于给硬件设备发送数据
                self.writeCharacteristic = characteristic;
            }
            
            if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kReadMacUUID]]) {
                ///这个特征,在我目前的项目中是读取蓝牙mac地址的
                self.readMACCharacteristic = characteristic;
            }
        }
        if (_readCharacteristic && _writeCharacteristic) {
            NSLog(@"连接成功");///此时才算真正连接成功,因为此时才有读、写特征,可以正常进行数据交互
        }
    }
    
    #pragma mark 【3】直接读取特征值被更新后、即收到订阅的那个特征的数据
    -(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
        
        if (error) {
            NSLog(@"更新特征值时发生错误,错误信息:%@",error.localizedDescription);
            return;
        }
        NSLog(@"收到数据 -- %@",characteristic.value);
        ///这里就是处理数据了
    }
    

    然后是tableView代理

    #pragma mark - tableViewDelegate
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
        return _allPeripheral.count;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        BLETableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BLETableViewCell" forIndexPath:indexPath];
        cell.model = _allPeripheral[indexPath.row];
        return cell;
    }
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
        BLEModel *bleModel = _allPeripheral[indexPath.row];
        bleModel.peripheral.delegate = self;
        [_manager connectPeripheral:bleModel.peripheral options:nil];
    }
    

    代码中的几个宏定义:

    #pragma mark - 蓝牙服务及属性
    #define         kServiceUUID                                        @"0001"
    #define         kWriteUUID                                          @"0002"
    #define         kNotifyUUID                                         @"0003"
    #define         kReadMacUUID                                        @"0004"
    

    为什么是0001、0002等,是有原因的,这里介绍个App,叫LightBlue,可以查看到蓝牙设备的特性。当然这些也可以找硬件工程师拿到,或者自己查DataSheet也可以查到。

    IMG_1632.PNG
    再介绍个串口调试助手,CoolTerm。能实时调试蓝牙模块。
    代码地址:https://github.com/chan106/BLEDemo.git

    相关文章

      网友评论

          本文标题:iOS蓝牙开发-1-通识

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