中央模式下CoreBluetooth框架的使用

最近公司在做蓝牙项目,网上查了查资料,结合了自己的一些理解,整理了一下CoreBluetooth框架的基本使用步骤,因为项目是手机作为中心连接其他外设备,所以下面的示例代码仅限于中央模式下。

首先导入框架并导入头文件

1.创建一个中央管理者对象 和 一个保存设备的可变数组 以及 一个CBCharacteristic类型的属性

@interface ViewController ()

@property (strong, nonatomic)CBCentralManager *centralManager;

@property (strong, nonatomic)NSMutableArray *peripherals;

@property (strong, nonatomic)CBCharacteristic *characteristic;

2.在点击事件里初始化中心管理者对象并将设置delegate属性为自己,并遵守CBCentralManagerDelegate协议

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    self.centralManager = [[CBCentralManager alloc]initWithDelegate:self queue:nil];
}

以下为以下方法为CentrolManager的代理方法:

3.调用CBCentralManagerDelegate代理必须实现的centralManagerDidUpdateState:(CBCentralManager*)central方法,并且在方法里判断蓝牙的状态,如果是CBCentralManagerStatePoweredOn的状态表示可以开始扫描设备。

- (void)centralManagerDidUpdateState:(CBCentralManager *)central {

    switch (central.state) {
        case CBCentralManagerStatePoweredOn:          
            [self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:@"FFE0"]] options:nil];
            break;
        default:
            NSLog(@"蓝牙状态有误");
            break;
    }
}

这里要注意的是scanForPeripheralsWithServices: options: 这个方法的第一个参数,这个参数的类型应该为一个非空的CBUUID数组,里面存放的是ServicesUUID,也就是说通过支持服务的类型来寻找设备。如果你想你的手机只能和特定的设备进行连接这里可以填写参数来实现。如果想扫描所有的设备这里填nil就可以(如示例)。

4.扫描完成后就会调用centralManager:(CBCentralManager)central didDiscoverPeripheral:(CBPeripheral)peripheral advertisementData:(NSDictionary )advertisementData RSSI:(NSNumber)RSSI这个方法,将发现的所有设备存放到内存中,也就是我们所创建的Peripherals数组中,并调用连接设备方法,示例如下:

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
    
    //将设备保存到数组里并设置该设备的代理
    if (![self.peripherals containsObject:peripheral]) {
        
        [self.peripherals addObject:peripheral];
        
        [self.centralManager connectPeripheral:peripheral options:nil];
    }

}

这里需要注意的是,一定要持有搜索到的设备,如果发现自己的程序不能调用CentralDelegate的连接成功方法,那么问题很大可能是你搜索到设备却没有持有。

5.如果一切顺利接下来我们就来到成功连接的方法,在这个方法里我们如果需要向蓝牙设备读写数据,那么需要将连接的设备的代理属性设置好,并遵守设备代理协议,调用发现服务的方法。示例如下:

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {

    NSLog(@"已经连接设备%@",peripheral.name);

    [peripheral setDelegate:self];
    
    [peripheral discoverServices:nil];
    
}

6.连接失败和连接断开的代理方法,你可以通过连接已经断开方法来判断连接是否存在,可以通过打印连接失败的error来判断为什么会连接失败:

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {

    NSLog(@"设备断开连接");
}

- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    NSLog(@"连接设备失败");
}

下面为下面是PeripheralDelegate方法:

7.在调用发现服务方法后,回来到设备的已经发现服务方法,你可以遍历并且打印该设备所包含的服务以及服务UUID,找出你想要读取的服务。如果已知需要读取的服务UUID那么可以通过判断直接找到它并读取他所包含的特性。

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {

    for (CBService *service in peripheral.services) {
        
        if ([service.UUID isEqual:[CBUUID UUIDWithString:@"FFE0"]]) {
            
            [peripheral discoverCharacteristics:nil forService:service];        
        }
    }
}

8.接着调用已经发现特性方法,这个方法里你可以遍历该服务所包含的所有特性,和上个方法一样,如果你知道需要读写的特性UUID那么可以通过判断找到他 ,订阅或者读取它的值:

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
    //遍历该服务所包含的所有特性
    for (CBCharacteristic *characteristic in service.characteristics) {
        
        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"FFE1"]]) {
            
            //将这个特征保存起来
            self.characteristic = characteristic;
            //订阅特征
            [peripheral setNotifyValue:YES forCharacteristic:characteristic];
        }        
    }
    NSLog(@"%@",peripheral.identifier);
}

9.读取特征值,有些设备不需要你写入数据,它本身会向外广播那么调用下面这个方法就可以得到他的值了,当然如果你需要监听他的值是否改变,那么记得在上一个(发现特性)方法中订阅他的特征:

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {

    if (characteristic.value.length>2) {
        
        NSLog(@"%@",characteristic.value);
    }    
}

10.写入并读取特征值,有一些设备需要你写入数据,他才会返回你需要的数据,那么我们写入数据的方法需要用到三个参数:需要写入的设备、向哪个特征写入数据、还有一十六进制的NSData数据,在写入之前记得判断该特征是否可以写入哦:

//写入数据按钮点击方法
- (IBAction)writeDataBtnClick:(id)sender {
    
    CBPeripheral *peripheral = self.peripherals.lastObject;
    
    unsigned char byte[5] = {0xAA,0x55,0x01,0x42,0xC2};
    
    NSData *charData = [NSData dataWithBytes:byte length:sizeof(byte)];
    
    [self writeData:peripheral ToCharacteristic:self.characteristic WithData:charData];
    
}
//写入数据方法
- (void)writeData:(CBPeripheral *)peripheral ToCharacteristic:(CBCharacteristic *)characteristic WithData:(NSData *)data {

    if (characteristic.properties & CBCharacteristicPropertyWrite) {
        
        [peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
    }

}
//写入数据回调方法
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {

    if (error) {
        
        NSLog(@"Error writing characteristic value: %@",
              
              [error localizedDescription]);
    }

    [peripheral readValueForCharacteristic:characteristic];
}

以上是一个简单的中央模式下的CoreBluetooth框架的调用流程,但是对于新手来说有一些概念是要分清楚的,比如UUID,一个设备包含:设备UUID(也就是设备的唯一标示符)、ServiceUUID(服务UUID)、CharacteristicUUID(特性UUID。弄清楚这三个UUID的区别那么整个蓝牙的调用顺序就会很清晰。对了,示例中写入的数据是这个:0xAA554211,如果想要写入数据可以参考示例的格式将Byte数组通过NSData的对象方法转换成NSData。

参考文章:
http://liuyanwei.jumppo.com/2015/07/17/ios-BLE-1.html
http://liuyanwei.jumppo.com/2015/08/14/ios-BLE-2.html

在使用中发现什么问题欢迎加QQ:1025978218 互相交流学习~ 感谢参观 _

你可能感兴趣的:(中央模式下CoreBluetooth框架的使用)