美文网首页
iOS BLE基础开发

iOS BLE基础开发

作者: lin哥哥 | 来源:发表于2019-11-07 18:43 被阅读0次
1.jpg

工作模式:

  • 当 central 和 peripheral 通信时,绝大部分操作都在 central 这边。此时,central 被描述为 CBCentralManager,这个类提供了扫描、寻找、连接 peripheral(被描述为 CBPeripheral)的方法。

    • 下图标示了 central 和 peripheral 在 Core Bluetooth 中的表示方式:
    image
    • 当你操作 peripheral 的时候,实际上是在和它的 service 和 characteristic 打交道,这两个分别由 CBService 和 CBCharacteristic 表示。

服务、特征和特征的属性

  • 一个 peripheral 包含一个或多个 service,或提供关于信号强度的信息。service 是数据和相关行为的集合。例如,一个心率监测仪的数据就可能是心率数据。

    • service 本身又是由 characteristic 或者其他 service 组成的。characteristic 又提供了更为详细的 service 信息。还是以心率监测仪为例,service 可能会包含两个 characteristic,一个描述当前心率带的位置,一个描述当前心率的数据。
    image
    • 每个 characteristic 属性分为这么几种:读,写,通知这么几种方式

步骤简述:

  • 1.导入CoreBluetooth.framework,遵循代理< CBCentralManagerDelegate , CBPeripheralDelegate >;
  • 2.建立中心角色;
  • 3.实现“蓝牙状态”的delegate方法,判断蓝牙状态,如成功则扫描指定UUID设备(如不指定UUID,则无法后台持续连接);
  • 4.实现“扫描成功”的delegate方法,连接外围设备;
  • 5.实现“连接成功”的delegate方法,断开连接,获取外围设备服务;
  • 6.实现“获取服务”的delegate方法,获取外围设备服务的特征;
  • 7.实现“获取服务特征”的delegate方法,订阅特征值的通知;
  • 8.实现“获取服务特征属性和特征属性值”的delegate方法,读取外围设备服务特征属性和特征属性值,进行数据交互;
  • 9.断开连接。

1.导入 CoreBluetooth.framework

image.png

2.设置蓝牙权限

image.png

3.导入头文件,遵循CBCentralManager和CBPeripheral代理

#import <CoreBluetooth/CoreBluetooth.h>

//让ViewController实现相应的delegate
@interface ViewController () <CBCentralManagerDelegate, CBPeripheralDelegate>

@property (nonatomic , strong) CBCentralManager *centrelManager;

@end

4.判断蓝牙状态

#pragma mark --  CBCentralManagerDelegate Delegate(监控蓝牙状态,扫描外设)
/**
 *  得到蓝牙的目前状态 判断当前设备是否只拆BLE
 *
 *  @param central central description
 
 *  当central管理器更新状态时调用。这个方法是必须实现的,为了确保当前的central设备是否支持BLE以及当前是否可以被利用,当检测到central蓝牙已经打开时,需要做一些操作,比如开始寻找Peripheral。
 *  当状态改变为CBCentralManagerStatePoweredOff时,会结束当前的寻找以及断开当前连接的peripheral。当检测到PoweredOff这个状态是所有的APP必须重新开始检索以及寻找。
 */
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
    switch (central.state) {
        case CBCentralManagerStateUnknown:
            NSLog(@">>>CBCentralManagerStateUnknown");
            break;
        case CBCentralManagerStateResetting:
            NSLog(@">>>CBCentralManagerStateResetting");
            break;
        case CBCentralManagerStateUnsupported:
            NSLog(@">>>CBCentralManagerStateUnsupported");
            break;
        case CBCentralManagerStateUnauthorized:
            NSLog(@">>>CBCentralManagerStateUnauthorized");
            break;
        case CBCentralManagerStatePoweredOff:
            NSLog(@">>>CBCentralManagerStatePoweredOff");
            break;
        case CBCentralManagerStatePoweredOn:
            NSLog(@">>>CBCentralManagerStatePoweredOn");
            //开始扫描周围的外设
            [centrelManager scanForPeripheralsWithServices:nil options:nil];
            /*
             1、 如果要扫描周围指定的外设,则第一个参数为
                CBUUID *uuid = [CBUUID UUIDWithString:@"0xf2a4"];
                其中f2a4是我连接到iPad mini2的LightBlue app模拟的BLE外围设备,你要换成你设备的UUID。
             2、第一个参数nil就是扫描周围所有的外设,扫描到外设后会进入didDiscoverPeripheral
             */
            break;
        default:
            break;
     }
}

5.扫描外围设备

#pragma mark -- 扫描外围设备
/**
 *  如果发现周围有可联系的peripheral,该方法会不断地执行
 *
 *  @param central           中心设备
 *  @param peripheral        外围设备
 *  @param advertisementData 外围设备广播内容
 *  @param RSSI              信号强度
 *
 *  当central管理器发现一个peripheral时调用,广播的数据被以AdvertisementDataRetrievalKeys键值的形式接受。
 *  你必须建立一个本地的副本,当需要对他进行操作时。
 *  在一般的情况下,你的APP要保证能够在一定的范围内自动连接还是上peripheral,你能够使用RSSI的值来判断与发现的peripheral的距离。
 */
- (void)centralManager:(CBCentralManager *)central
 didDiscoverPeripheral:(CBPeripheral *)peripheral
     advertisementData:(NSDictionary *)advertisementData
                  RSSI:(NSNumber *)RSSI{
    
    /*
     advertisementData:(NSDictionary *)advertisementData:
     CBAdverisementDataLocalNameKey:             一个包含了peripheral设备名称的字符串。
     CBAdvertisementDataManudfactureDataKey:     一个包含了制造商信息的NSdata对象。
     CBAdvertisementDataServiceDataKey:          这个keys是一个CBUUID的对象代表了CBServicesUUID,这个NSData代表了服务指定的Data。
     CBAdvertisementDataServiceUUIDsKey:         这是一包含了服务的UUID的数组。
     CBAdvertisementDataOverflowServiceUUIDsKey: 这个数组包含了一个或者更多的CBUUID对象,这些对象代表了被广播在溢出区域的数据,关于这个keys的详细介绍请看我的上一篇译文《CBPeripheralManager 类介绍》。
     CBAdvertisementDataTxPowerLeverlKey:        这个NSnumber对象包含了peripheral传输功率的强弱。如果peripheral广播的数据中包含了传输的功率是这个key值将可以被使用,使用RSSI和传输功率可以计算之间的距离。
     CBAdvertisementDataIsconnectable:           这个BOOL值指明当前广播的事件是否可连接。
     CBAdvertisementDataSolicitedServiceUUIDsKEy:一个包含了CBServices UUIDs的数组。
     */
    
    //取得 local name,唯一标识设备
    NSString *localName = peripheral.name;
        
        if([localName hasPrefix:@“LL”]) {

            self.peripheral = [peripheral copy];
            
            //连接外设,有时候会连接不上,可以尝试用timer多连接几次
            [self.centrelManager connectPeripheral:peripheral options:nil];
          }
      }
}

一个主设备最多能连7个外设,每个外设最多只能给一个主设备连接,连接成功,失败,断开会进入各自的代理方法。

6.连接外围设备成功:

#pragma mark -- 连接成功
/**
 *  连接成功
 *
 *  @param central    中心设备
 *  @param peripheral 外围设备
 */
- (void)centralManager:(CBCentralManager *)central
  didConnectPeripheral:(CBPeripheral *)peripheral{
    
    //中央设备停止扫描外围设备
    [self.centrelManager stopScan];

    // 设置外围设备代理
    peripheral.delegate = self;
    
    //寻找服务 查找设备中所包含的服务了  执行完后会执行CBPeripheral delegate didDiscoverServices
    [peripheral discoverServices:nil];
    /*
      可根据所设定的参数搜寻指定的服务
      NSArray *serviceUUIDs = @[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]];
     [peripheral discoverServices:serviceUUIDs];
    */
}

7.外围设备连接失败:

/*
 *  连接失败
 *
 *  @param central    中心设备
 *  @param peripheral 外围设备
 *  @param error      错误参数
 *
 *  这个方法在方法connectPeripheral:options建立的连接断开时调用,应为建立连接的动作是不能超时的,通常在失败连接时你需要再次试图连接peripheral。
 */
- (void)centralManager:(CBCentralManager *)central
didFailToConnectPeripheral:(CBPeripheral *)peripheral
                 error:(NSError *)error{
        if (error) {
            NSLog(@"Failed to connect to %@. (%@)", peripheral, [error localizedDescription]);
      }
  }  

8.断开外围设备的连接和连接超时:

/*
 *  连接超时 断开连接
 *
 *  @param central    中心设备
 *  @param peripheral 外围设备
 *  @param error      错误参数
 *    
 *  当已经建立的连接被断开时调用。
 *  这个方法在connectPeripheral:options方法建立的连接断开时调用。
 *  如果断开连接不是有cancelPeripheralConnection方法发起的,那么断开连接的详细信息就在error参数中。
 *  当这个方法被调用只有peripheral代理中的方法不在被调用。
 *  注意:当peripheral断开连接时,peripheral所有的service、characteristic、descriptors都无效。
 */
- (void)centralManager:(CBCentralManager *)central
didDisconnectPeripheral:(CBPeripheral *)peripheral
                 error:(NSError *)error{

    if (error) {
          NSLog(@"Disconnect to %@. (%@)", peripheral, [error localizedDescription]);
    }  

    // 重连机制,可设置重新连接次数,结合连接成功的代理累计
    if (self.peripheral) {
       
        [self.centrelManager connectPeripheral:self.peripheral options:nil];
    }
}

9.搜寻外围设备中服务

/**
 *  查找外围设备中服务
 *
 *  @param peripheral 外围设备
 *  @param error      错误参数
 */
- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverServices:(NSError *)error{
    
    if (error) {
        
        NSLog(@"Service discover was unsuccessfull! error:%@ ",[error localizedDescription]);
        
    }else{
        
        for (int i = 0; i < peripheral.services.count; i++) {
            
            CBService *service = [peripheral.services objectAtIndex:i];
            
            NSLog(@"service UUID:%@", service.UUID);
            
            self.serviceUUID = service.UUID;

            //知道每个service下有多少个Characteristics特性,有服务的话扫描特征
            [peripheral discoverCharacteristics:nil forService:service];
            
            /*
              可根据所设定的参数搜寻指定服务的特征
              for (CBService *service in peripheral.services) {
                    //serviceId筛选
                    if ([service.UUID.UUIDString isEqualToString:TRANSFER_SERVICE_UUID1]) {

                          [peripheral discoverCharacteristics:nil forService:service];
                          
                         // 可根据指定的特征UUID搜寻
                         // NSArray *characteristicUUIDs = @[[CBUUID UUIDWithString:TRANSFER_CHRARCTERISTIC_UUID]];
                         // [peripheral discoverCharacteristics:charateristicUUIDs forService:service];
                        
                    }
              }
            */  
       }
    }
}

在做该类项目时,外设需求往往有一个UUID来确定需要连接的服务,对应这边service的UUID,而不是peripheral的UUID
(在使用lightblue模拟测试时,可以添加service并设置其UUID来模拟测试)

10.设置读取和订阅外围设备特征值的通知

/**
*  设置读取和订阅外围设备特征值的通知
 *  知道什么样的Services服务 什么样的Characteristics特性之后再进行处理, 并且注册通知 当BLE周边发信息过来时就会收到通知并得到资料
 *
 *  @param peripheral 中心设备
 *  @param service    服务
 *  @param error      错误参数
 */
- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverCharacteristicsForService:(CBService *)service
             error:(NSError *)error{

        if (error) {
        
              NSLog(@"Characteristic discover was unsuccessfull! error:%@ ",[error localizedDescription]);
        
         }else{

            // 获取service的characteristics
            NSArray *characteristics = [service characteristics];
    
            for (CBCharacteristic *characteristic in characteristics) {
        
                  if ([characteristic.UUID.UUIDString isEqualToString:TRANSFER_CHRARCTERISTIC_UUID]) {
        
                  self.characteristic = characteristic;

                  [peripheral readValueForCharacteristic:self.characteristic];
            
                  //注册监听
                  [peripheral setNotifyValue:YES forCharacteristic:self.characteristic];
                  //我们可以使用readValueForCharacteristic:来读取数据。
                  //如果数据是不断更新的,则可以使用setNotifyValue:forCharacteristic:来实现只要有新数据,就获取。
                  //外围设备支持监听模式,特征值发生变化时广播。
        }
    }
}

11.数据处理:读取特征值和所监听的特征的特征值发生变化时所调用代理

/**
 * 数据处理
 * 连上完成后 取得数据非常重要   当外设发送新值时候,此方法自动被动用
 *
 *  @param peripheral     外围设备
 *  @param characteristic 特征
 *  @param error          错误参数
 */
- (void)peripheral:(CBPeripheral *)peripheral
didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
             error:(NSError *)error{
    
        if (error) {
        
              NSLog(@"updateValueForCharacteristic failed! error:%@ ",[error localizedDescription]);
              return;

         }else{

            //读取数据,当周边发送新的值,此方法的第二个参数包含特征。可以用value属性读取他的值,这是一个包含特征的值的NSData。
             unsigned char characteristicValueData[1024] = {0};
             [characteristic.value getBytes:characteristicValueData];
            
             NSLog(@"characteristicValue:%@ - Length:%lu",characteristicValueData,(unsigned long)characteristicValueData.length);

            // 与外围设备进行交互

            /*
             *可以通过特征值来校验是否为正确的数据,做相对应的操作
             *   if (characteristicValueData[0] == 0x02) {
             *      //此时为第一位为2才是正确数据,做相对应的操作
             *
             *   }else if (characteristicValueData[0] == 0x04){
             *
             *     //此时为第一位为4不是正确数据或者是其他操作的数据,做相对应的操作
             *    (如设置监听后特征值发生变化为正确的数据)
             *   }
             */
            
        }
}

中心设备单次发送的数据最大不能超过20个字节,蓝牙模块内部接收缓冲区只有20个字节,如果超过20个字节,需要分包发送。

/**
 * 数据处理
 * 
 * 传输数据大于20个字节时需要分包处理
 *
 *  @param data  传输的数据
 * 
 *  TranslateDataLenght为最大传输数据值20
 */
- (void)transmissionWithData:(NSData *)data{
    
    if(data.length > TranslateDataLenght){
        
        int i = 0;

        while ((i + 1) * TranslateDataLenght <= data.length) {
            
            NSData *dataSend = [data subdataWithRange:NSMakeRange(i * TranslateDataLenght, TranslateDataLenght)];
            
            [self write: self.peripheral  data:dataSend];
            
            i++;

           //根据接收模块的处理能力做相应延时
           usleep(20 * 1000);
        }
        
        i = data.length % TranslateDataLenght;
        
        if(i >0){
            
            NSData *dataSend = [data subdataWithRange:NSMakeRange(data.length - i, i)];
            
            [self write:self.peripheral data:dataSend];
        }

        //根据接收模块的处理能力做相应延时
        usleep(20 * 1000);
        
    }else{
        
        [self write:self.peripheral data:data];
    }
}

/*
 * 向外围设备传输数据
 * @param peripheral  外围设备
 * @param data  传输的数据
 */
- (void) write:(CBPeripheral *)peripheral
          data:(NSData *)data{
      /*
       *  如果设置为CBCharacteristicWriteWithResponse,
       *  则可以写成功一次,只可读,写入数据有反馈
       * 
       *  如果为CBCharacteristicPropertyWriteWithoutResponse,
       *  则一次也不能写成功,可以读,也可以通知。
       */
      if(characteristic.properties & CBCharacteristicPropertyWriteWithoutResponse){
        
        [peripheral writeValue:data
             forCharacteristic:characteristic
                          type:CBCharacteristicWriteWithoutResponse];
    }else{
        
        [peripheral writeValue:data
             forCharacteristic:characteristic
                          type:CBCharacteristicWriteWithResponse];
    }
}

12.数据写入成功后反馈

/*
 * 数据写入成功后反馈
 *
 * 外围设备写入数据后的类型为CBCharacteristicWriteWithResponse,会调用该方法
 * @param peripheral  外围设备
 * @param data  传输的数据
 */
- (void)peripheral:(CBPeripheral *)peripheral
didWriteValueForCharacteristic:(CBCharacteristic *)characteristic
             error:(NSError *)error{
    
    if (error) {
        
        NSLog(@"Write value for characteristic failed : %@",error.userInfo);
    }else{
        
        NSLog(@"Write value for characteristic successfull!! ");
        // 如果写入数据成功,外围设备被中心设备所监听的设备的服务特征发生改变,会调用- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error,做相对应的处理
    }
}

各位大神,有不足之处,请多多指教,勿喷。

相关文章

  • 3分钟入门iOS BLE开发

    没错,只需要3分钟就可以入门iOS的BLE(Bluetooth Low Energy)开发 1分钟了解BLE的基础...

  • iOS BLE基础开发

    工作模式: 当 central 和 peripheral 通信时,绝大部分操作都在 central 这边。此时,c...

  • iOS BLE Scan

    iOS扫描BLE设备的方法 iOS在使用CoreBluetooth框架进行BLE开发时,通常作为中心设备(Mast...

  • iOS关于蓝牙框架BLE的开发--基础用法(下)

    承接上文:iOS关于蓝牙框架BLE的开发--基础用法(上)上文提及到对特征码CBCharacteristic进行操...

  • 12月第三周

    iOS-BLE蓝牙开发持续更新 - IOS - 伯乐在线 ReactiveCocoa 中 RACSignal 所有...

  • ios蓝牙参考

    参考文章:iOS中的蓝牙开发iOS-BLE蓝牙开发demo 官网 转载 CenteralManager学习笔记

  • iOS开发之BLE(二)——外设连接与断开

    在 iOS开发之BLE(一)——理论知识 一文中,主要对iOS开发中BLE的基本理论知识进行了介绍,本文以中心模式...

  • iOS蓝牙4.0基础开发

    1.蓝牙开发基础 蓝牙4.0是低电量模式所以也叫4.0BLE。本文将使用iOS系统提供的CoreBluetooth...

  • iOS-蓝牙开发Mark

    iOS蓝牙的开发专题[http://liuyanwei.jumppo.com/2015/07/17/ios-BLE...

  • iOS开发之BLE(二)——外设连接与断开

    在iOS开发之BLE(一)——理论知识一文中,主要对iOS开发中BLE的基本理论知识进行了介绍,本文以中心模式为例...

网友评论

      本文标题:iOS BLE基础开发

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