零基础iOS开发学习日记-第三方框架篇-BabyBluetooth

1,779 阅读4分钟

开头

BabyBluetooth

蓝牙开发步骤

  1. 扫描外设
  2. 发现外设
  3. 连接外设
  4. 获取外设读写特征
  5. 获取外设发出的信息和向外设发信息
  • 基于上面的步骤,通过block函数进行实现
  • 有些名词可以看Bluetooth蓝牙

基本使用

  • 这里的案例是我最近的蓝牙项目,通过tableView显示被扫描到的设备,中心设备连接一个蓝牙设备,通过写特征值进行发数据,通过监听特征值进行消息监听
  • 创建baby对象
self.baby = [BabyBluetooth shareBabyBluetooth];
  • 开始扫描
self.baby.scanForPeripherals().begin();
  • 连接设备
[self.baby cancelScan];
//取消所有外设连接
[self.baby cancelAllPeripheralsConnection];
//建立连接且发现服务和特征值
//pp为目标外设
self.baby.having(pp).and.then.connectToPeripherals().discoverServices().discoverCharacteristics().readValueForCharacteristic().discoverDescriptorsForCharacteristic().readValueForDescriptors().begin();
  • 发送数据
//通过已连接的外设调用
[self.connectPeripheral writeValue:data forCharacteristic:self.writeCharacteristic type:CBCharacteristicWriteWithResponse];
  • 初始化baby对象,就是设置对应的block函数
[self babyDelegate];
  • babyDelegate中,配置block
//弱引用self,防止blcok中调用外部属性,导致循环引用
__weak typeof(self) weakSelf = self;
//确定中心设备状态是否可以扫描
[self.baby setBlockOnCentralManagerDidUpdateState:^(CBCentralManager *central) {
    if (central.state == CBManagerStatePoweredOn) {
        [SVProgressHUD showInfoWithStatus:@"设备打开成功,开始扫描设备"];
    }
    NSLog(@"%@", central);
}];

//扫描到外设的blcok,并且添加到一个数组中,方面以后续的处理
[self.baby setBlockOnDiscoverToPeripherals:^(CBCentralManager *central, CBPeripheral *peripheral, NSDictionary *advertisementData, NSNumber *RSSI) {
//        NSLog(@"搜索到了设备:%@",peripheral.name);
    
    if (![weakSelf.peripheralArray containsObject:peripheral]) {
        [weakSelf.peripheralArray addObject:peripheral];
        //通过代理,进行界面刷新
        if ([weakSelf.delegate respondsToSelector:@selector(reloadData)]) {
            [weakSelf.delegate reloadData];
        }
        
    }
    NSLog(@"%@", weakSelf.peripheralArray);
    
}];

//连接成功
[self.baby setBlockOnConnected:^(CBCentralManager *central, CBPeripheral *peripheral) {
    [SVProgressHUD showInfoWithStatus:@"连接成功"];
    //保存连接上的外设
    weakSelf.connectPeripheral = peripheral;
    
}];

//读取所有特征值
[self.baby setBlockOnReadValueForCharacteristic:^(CBPeripheral *peripheral, CBCharacteristic *characteristics, NSError *error) {
    NSLog(@"characteristic name:%@ value is:%@",characteristics.UUID,characteristics.value);
}];


//获取读和监听的特征值,根据服务进行筛选
[self.baby setBlockOnDiscoverCharacteristics:^(CBPeripheral *peripheral, CBService *service, NSError *error) {
    NSLog(@"service name: %@", service);
    NSLog(@"service uuidstring name: %@", service.UUID.UUIDString);
    NSLog(@"%@", service.characteristics);
    //确定服务
    if([service.UUID.UUIDString isEqualToString:@"6E400001-B5A3-F393-E0A9-E50E24DCCA9E"]) {
        for (CBCharacteristic * tempChara in service.characteristics) {
            NSLog(@"%@", tempChara);
            //确定监听特征值
            if ([tempChara.UUID.UUIDString isEqualToString:@"6E400003-B5A3-F393-E0A9-E50E24DCCA9E"]) {
                weakSelf.notifyCharacteristic = tempChara;
                NSLog(@"self.notifyCharacteristic : %@", weakSelf.notifyCharacteristic);
                //对监听特征值进行订阅,并将监听到的数据进行处理
                [weakSelf.baby notify:peripheral characteristic:weakSelf.notifyCharacteristic block:^(CBPeripheral *peripheral, CBCharacteristic *characteristics, NSError *error) {
                    NSLog(@"notify %@", characteristics.value);
                    NSLog(@"notify Str %@", [[NSString alloc] initWithData:characteristics.value encoding:NSUTF8StringEncoding]);
                    //处理数据
                    [weakSelf handleData:characteristics.value];
                }];
            }
            //保存写特征值
            else if ([tempChara.UUID.UUIDString isEqualToString:@"6E400002-B5A3-F393-E0A9-E50E24DCCA9E"]) {
                weakSelf.writeCharacteristic = tempChara;
                NSLog(@"self.writeCharacteristic : %@", weakSelf.writeCharacteristic);

            }
        }
    }
}];

//设置查找设备的过滤器
[self.baby setFilterOnDiscoverPeripherals:^BOOL(NSString *peripheralName, NSDictionary *advertisementData, NSNumber *RSSI) {
    
    //最常用的场景是查找某一个前缀开头的设备
//        if ([peripheralName hasPrefix:@"Pxxxx"] ) {
//            return YES;
//        }
//        return NO;
        //mac地址
//        NSData *data = advertisementData[@""];
//        NSLog(@"%@", advertisementData);
    //设置查找规则是名称大于0 , the search rule is peripheral.name length > 0
    if (peripheralName.length >0) {
        return YES;
    }
    return NO;
}];

//写入成功
[self.baby setBlockOnDidWriteValueForCharacteristic:^(CBCharacteristic *characteristic, NSError *error) {
        [SVProgressHUD showSuccessWithStatus:@"写入成功"];
        [SVProgressHUD dismissWithDelay:1];
}];
//断开设备
[self.baby setBlockOnDisconnect:^(CBCentralManager *central, CBPeripheral *peripheral, NSError *error) {
    [SVProgressHUD showInfoWithStatus:@"断开链接"];
    [SVProgressHUD dismissWithDelay:1];
    //界面处理
    if ([weakSelf.delegate respondsToSelector:@selector(disconnect)]) {
        [weakSelf.delegate disconnect];
    }
        
}];

//取消所有设备连接
[self.baby setBlockOnCancelAllPeripheralsConnectionBlock:^(CBCentralManager *centralManager) {
    NSLog(@"setBlockOnCancelAllPeripheralsConnectionBlock");
}];
//取消扫描
[self.baby setBlockOnCancelScanBlock:^(CBCentralManager *centralManager) {
    NSLog(@"setBlockOnCancelScanBlock");
}];

//设置babyOptions
//扫描选项->CBCentralManagerScanOptionAllowDuplicatesKey:忽略同一个Peripheral端的多个发现事件被聚合成一个发现事件
NSDictionary *scanForPeripheralsWithOptions = @{CBCentralManagerScanOptionAllowDuplicatesKey:@YES};
/*连接选项->
 CBConnectPeripheralOptionNotifyOnConnectionKey :当应用挂起时,如果有一个连接成功时,如果我们想要系统为指定的peripheral显示一个提示时,就使用这个key值。
 CBConnectPeripheralOptionNotifyOnDisconnectionKey :当应用挂起时,如果连接断开时,如果我们想要系统为指定的peripheral显示一个断开连接的提示时,就使用这个key值。
 CBConnectPeripheralOptionNotifyOnNotificationKey:
 当应用挂起时,使用该key值表示只要接收到给定peripheral端的通知就显示一个提
*/
NSDictionary *connectOptions = @{CBConnectPeripheralOptionNotifyOnConnectionKey:@YES,
CBConnectPeripheralOptionNotifyOnDisconnectionKey:@YES,
CBConnectPeripheralOptionNotifyOnNotificationKey:@YES};
//连接设备->
[self.baby setBabyOptionsWithScanForPeripheralsWithOptions:scanForPeripheralsWithOptions
                              connectPeripheralWithOptions:connectOptions
                            scanForPeripheralsWithServices:nil
                                      discoverWithServices:nil
                               discoverWithCharacteristics:nil];

数据转换

  • 对于蓝牙外设来说,一般的数据为16进制的,所以会涉及到数据格式的转换,而对于iOS来说,便于处理的数据格式肯定是数据,可以根据帧结构进行不同的处理
  • 这个数组中的每个元素都以NSNumber的形式存储
  • NSArray转成NSData
- (NSData *)convertArrayToDataWithArray:(NSArray *)array {
    NSUInteger len = array.count;
    UInt8 buffer[len];
    for (int i = 0; i < len; i++)
    {
        buffer[i] = [[array objectAtIndex:i] unsignedCharValue];
    }
    NSData *data = [NSData dataWithBytes:buffer length:len];
    return data;
}
  • NSData转NSArray
- (NSArray *)convertDataToArrayWithData:(NSData *)data{

    //把读到的数据复制一份
    NSData *recvBuffer = [NSData dataWithData:data];
    NSUInteger recvLen = [recvBuffer length];
    UInt8 *recv = (UInt8 *)[recvBuffer bytes];
    if (recvLen > 1000) {
        return nil;
    }
    //把接收到的数据存放在recvData数组中
    NSMutableArray *recvData = [[NSMutableArray alloc] init];
    NSUInteger j = 0;
    while (j < recvLen) {
        [recvData addObject:[NSNumber numberWithUnsignedChar:recv[j]]];
        j++;
    }
    return recvData;
}
  • 往数组内添加数据的形式
[dataArr addObject:[NSNumber numberWithUnsignedInteger:0x00]];
  • 数组中的内容进行16进制的比较
[dataArr[0] unsignedIntValue] == 0x81

总结

  • 这里仅仅进行的单设备连接,据说可以进行多设备连接,找机会把坑补上
  • 以上总结的仅仅是我在项目中的用到的状态,还可以监听挺多蓝牙状态的,挖个坑
  • 具体使用上,是封装了一层Manager管理类。