基于蓝牙4.0(btle)的简单通讯流程

基于蓝牙4.0进行通讯,以手机为CentralManager,简单串一下通讯流程如下:

在iOS10以后,需要在 Info.plist 文件里面设置 NSBluetoothPeripheralUsageDescription 字段,添加访问蓝牙权限的描述,否则程序会崩溃,且上传程序是会被拒的。

1、扫描

(1)初始化一个CentralManager

CBCentralManager 的创建是异步的,如果初始化完成之后没有被当前创建它的类所持有,控制台会报错(说白了如果是局部变量就会在控制台报错)
btle[3800:1288058] [CoreBluetooth] XPC connection invalid

self.centralManager = [[CBCentralManager alloc]initWithDelegate:self queue:nil options:@{CBCentralManagerOptionShowPowerAlertKey:@YES}];
  • queue:指明在哪个队列处理事件,为nil时表示在主线程处理
  • options:这个字典有俩个官方的key
    CBCentralManagerOptionShowPowerAlertKey:提示蓝牙开关未打开时会弹出警告框
    CBCentralManagerOptionRestoreIdentifierKey:一个指定中央管理器的uid(和蓝牙程序进入后台有关,没有多做研究)

(2)监听CentralManager蓝牙状态

当创建CentralManager成功后,系统就会回调CBCentralManagerDelegate的代理方法

- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
    switch (central.state) {
        case CBManagerStatePoweredOn:
            //打开状态
            if (self.centralManager.state == CBCentralManagerStatePoweredOn) {

                //开始扫描
                [self.centralManager scanForPeripheralsWithServices:self.deviceServiceArray options:nil];
            }
            break;
        case CBManagerStatePoweredOff:
            //关闭状态
            break;
        case CBManagerStateResetting:
            //复位
            break;
        case CBManagerStateUnsupported:
            //表明设备不支持蓝牙低功耗
            break;
        case CBManagerStateUnauthorized:
            //该应用程序是无权使用蓝牙低功耗
            break;
        case CBManagerStateUnknown:
            //未知
            break;
        default:
            break;
    }
}

(3)开始扫描

只有当蓝牙状态为CBManagerStatePoweredOn的时候,才可以扫描周边设备,否则控制台报错
btle[3815:1292851] [CoreBluetooth] API MISUSE: can only accept this command while in the powered on state

    if (self.centralManager.state == CBCentralManagerStatePoweredOn) {
        //开始扫描
        [self.centralManager scanForPeripheralsWithServices:self.deviceServiceArray options:nil];
    }
  • serviceUUIDs:为nil时,会扫描正在广播的所有Peripheral。如果你指定某个Service或者一组Service,只能扫描提供这些Service的Peripheral。(Service里面放的是CBUUID)
  • options:这个字典有俩个官方的key
    CBCentralManagerScanOptionAllowDuplicatesKey:为NO,表示不会重复扫描已经发现的设备。为YES,扫描中会出现已经扫到的设备。默认为NO
    CBCentralManagerScanOptionSolicitedServiceUUIDsKey:以一个数组的形式存在,指定这个选项后central便会找指定的服务的CBUUID

(3)扫描成功

每当扫描到一个外设,系统就会回调CBCentralManagerDelegate的代理方法

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *, id> *)advertisementData RSSI:(NSNumber *)RSSI{

    if (advertisementData[CBAdvertisementDataLocalNameKey] == nil || advertisementData[CBAdvertisementDataServiceUUIDsKey] == nil) return;

    if (![self.connectedPeripheralArray containsObject:peripheral]) {
         //停扫
        [self.centralManager stopScan];
        self.currentPeripheral = [peripheral copy];
        //设备连接
        [self.centralManager connectPeripheral:self.currentPeripheral options:nil];
    }
}

连接

(1)设备连接

当系统扫描到的peripheral进行连接,成功与失败都会有相应的回调方法响应,没有连接超时的回调,苹果官方文档说明,只有连接失败

  self.currentPeripheral = [peripheral copy];       
  //设备连接
  [self.centralManager connectPeripheral:self.currentPeripheral options:nil];
  • peripheral:将要连接的peripheral,需要保持一下peripheral
  • options:这个字典有俩个官方的key
    这些key值和蓝牙后台有关,没有多做研究
    CBConnectPeripheralOptionNotifyOnConnectionKey
    CBConnectPeripheralOptionNotifyOnDisconnectionKey
    CBConnectPeripheralOptionNotifyOnNotificationKey

(2)当设备连接成功

当你调用设备连接的时候,成功就会回调CBCentralManagerDelegate的代理方法,这里我们需要去发现CBPeripheral的一些相关服务

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
    if (![self.connectedPeripheralArray containsObject:peripheral]){
        [self.connectedPeripheralArray addObject:peripheral];
        //设置代理发现服务
        [peripheral setDelegate:self];
        [peripheral discoverServices:nil];
    }
}

(3)设备连接失败

当你调用设备连接的时候,失败就会回调CBCentralManagerDelegate的代理方法,可以再次连接外设

- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error{
    //重新开扫
    [self startScan];
}

(4)设备断开

当你调用设备连接成功后,又断开的时候就会回调CBCentralManagerDelegate的代理方法

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error{
    if([self.connectedPeripheralArray containsObject:peripheral]){
        [self.connectedPeripheralArray removeObject:peripheral];
    }
    //重新开扫
    [self startScan];
}

发现服务

(1)发现CBPeripheral的Services

当CBPeripheral连接成功后,需要设置CBPeripheralDelegate代理方法去发现CBPeripheral的相关服务

//设置代理发现服务
[peripheral setDelegate:self];
[peripheral discoverServices:nil];
  • serviceUUIDs:可以添加一组CBUUID的service,这样就可以发现指定的Services(官方推荐),如果为nil,则去发现所有有效的Services(相对较慢,不推荐)

(2)发现Services成功

成功发现Services,就会回调CBPeripheralDelegate的代理方法,需要通过peripheral的services属性去获取发现的CBService。同时,我们需要在此去发现每一个CBService下的characteristics

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
    if (error == nil){
        for (CBService *aService in peripheral.services) {

            //发现特征
            [peripheral discoverCharacteristics:nil forService:aService];
        }
    }else{
        //如果有错,则主动断开,然后会走(centralManager:didDisconnectPeripheral:error:)
        [self.centralManager cancelPeripheralConnection:peripheral];
    }
}

发现特征

(1)发现Characteristics

 for (CBService *aService in peripheral.services) {
            //发现特征
            [peripheral discoverCharacteristics:nil forService:aService];
        }
}
  • characteristicUUIDs:可以添加一组CBService的characteristic,这样就可以发现指定的characteristic(官方推荐),如果为nil,则去发现所有有效的characteristic(相对较慢,不推荐)
  • service:被发现Characteristics的CBService

(2)发现Characteristics成功

成功发现Characteristics就会回调CBPeripheralDelegate的代理方法,通常会有两中characteristics:CBCharacteristicPropertyRead和CBCharacteristicPropertyWrite。

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{

    if (error == nil) {

        for (CBCharacteristic *aChar in service.characteristics){

            //判断Characteristic属性类型
            if ((aChar.properties & CBCharacteristicPropertyRead)){
                self.readCharacteristic = aChar;
                [peripheral readValueForCharacteristic:aChar];
            }
            if ((aChar.properties & CBCharacteristicPropertyWrite)){

                self.writeCharacteristic = aChar;
                [peripheral setNotifyValue:YES forCharacteristic:aChar];
                NSLog(@"----%@",aChar);
            }
        }
    }
    else{
        //如果有错,则主动断开,然后会走(centralManager:didDisconnectPeripheral:error:)
        [self.centralManager cancelPeripheralConnection:peripheral];

    }
}

(3)写使能

对于Characteristic是CBCharacteristicPropertyNotify的写使能,就会回调CBPeripheralDelegate的代理方法

[peripheral setNotifyValue:YES forCharacteristic:aChar];

(4)判断使能是否写成功

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

    if (characteristic.isNotifying) {
        NSLog(@"成功");
    }
}

(5)从Peripheral读取数据

对于Characteristic是CBCharacteristicPropertyRead的写使能,就会回调CBPeripheralDelegate的代理方法

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

    NSData *responseData = characteristic.value;
    NSLog(@"data--%@",responseData);
}

实现通讯

(1)写入数据

写入数据时,当你把type设置为CBCharacteristicWriteWithResponse,就会回调CBPeripheralDelegate的代理方法,如果为CBCharacteristicWriteWithoutResponse则不会

- (void)sendData{

    uint8_t sendData[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,};
    NSMutableData *data=[[NSMutableData alloc]init];
    [data appendBytes:(void *)(&sendData[0]) length:sizeof(sendData)];
    //写入数据
    [self.currentPeripheral writeValue:data.copy forCharacteristic:self.writeCharacteristic type:CBCharacteristicWriteWithResponse];

}

(2)写入成功

- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    NSLog(@"成功");
}

(3)接收数据

当你写入成功数据成功之后,CBPeripheral收到后若有返回的数据则继续会出现在(5)从Peripheral读取数据中,以此返回进行通信。。。。

你可能感兴趣的:(iOS-蓝牙)