iOS蓝牙开发

一、框架

基于 <CoreBluetooth/CoreBluetooth.h> 框架

不要试图继承CoreBluetooth中的任何类,因为重载会导致未知的结果

有两种开发方案,一种是以本地作为中心设备,一种是已远端设备作为中心设备

包含类

外围设备:通常用于发布服务、生成数据、保存数据。外围设备发布并广播服务,告诉周围的中央设备它的可用服务特征

中心设备:中心设备扫描到外围设备后会视图建立连接,连接成功后可用使用外围设备的服务和特征

外围设备中心设备直接交换的桥梁是服务(CBService)和特征(CBCharacteristic),二者都拥有一个唯一的标识(CBUUID)来确定唯一的服务和特征。每个服务可以有多个特征。

  • CBPeripheral 外围设备

  • CBPeripheralManager 外围设备管理类

  • CBMutableService 外围设备的服务

  • CBMutableCharacteristic 外围设备的特征

  • CBUUID 外围设备服务特征的唯一标志

  • CBCentral 中心设备

  • CBCentralManager 中心设备管理类

  • CBService 外围设备的服务

  • CBCharacteristic 外围设备的特征

  • CBATTRequest 中心设备读写数据的请求

申请权限

iOS 10以后,所有的蓝牙开发都要申请蓝牙权限,在项目的info.plist中设置NSBluetoothPeripheralUsageDescription,对应的key为Privacy - Bluetooth Always Usage DescriptionPrivacy - Bluetooth Peripheral Usage Description

二、中心开发模式

以中心设备CBCentral作为本地,外网设备CBPeripheral作为远端

初始化

// 初始化选项,设置YES时,如果用户蓝牙关闭,会弹出一个提示框
NSDictionary *options = @{CBCentralManagerOptionShowPowerAlertKey: @YES};

CBCentralManager* tM = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue() options:options];

self.cbcManager = tM;

扫描外围设备

//判断当前蓝牙工作状态是否开启
if (self.cbcManager.state == CBManagerStatePoweredOn) {
    //记录当前过滤条件
    self.fliterName = fliterName;
    //优先查找系统已经连接上的PV蓝牙设备
    self.sysConnectArrs = [self.cbcManager retrieveConnectedPeripheralsWithServices:@[[CBUUID UUIDWithString:PVMG10BluetoothServiceUUID]]];
    for (CBPeripheral * cbp in self.sysConnectArrs) {
        [self centralManager:self.cbcManager didDiscoverPeripheral:cbp advertisementData:@{} RSSI:cbp.RSSI];
    }
    
    //开始搜索设备
    NSDictionary * option = @{
        // CBCentralManagerScanOptionAllowDuplicatesKey 指示是否过滤重复情况
        CBCentralManagerScanOptionAllowDuplicatesKey:[NSNumber numberWithBool:NO],
        // 蓝牙未开启情况下是否显示提示框
        CBCentralManagerOptionShowPowerAlertKey:@0
    };
    
    // services和option都可以传nil
    // services传对应的UUIDstring则扫描指定id的设备
    [self.cbcManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:BluetoothServiceUUID]] options:option];
}
else{
    // TODO:返回蓝牙未打开状态
    
}

扫描结果回调

蓝牙状态监听

- (void)centralManagerDidUpdateState:(nonnull CBCentralManager *)central {
    switch (central.state) {
        case CBManagerStateUnknown:
            NSLog(@">>>CBCentralManagerStateUnknown");
            break;
        case CBManagerStateResetting:
            NSLog(@">>>CBCentralManagerStateResetting");
            break;
        case CBManagerStateUnsupported:
            NSLog(@">>>CBCentralManagerStateUnsupported");
            break;
        case CBManagerStateUnauthorized:
            NSLog(@">>>CBCentralManagerStateUnauthorized");
            break;
        case CBManagerStatePoweredOff:
            NSLog(@">>>CBCentralManagerStatePoweredOff");
        {
            //手动断开设备连接
            for (NSString * pcDeviceName in self.connectedDeviceMap) {
                PVBluetoothDevice * device = self.connectedDeviceMap[pcDeviceName];
                [self centralManager:self.cbcManager didDisconnectPeripheral:device.peripheral error:nil];
            }
        }
            break;
        case CBManagerStatePoweredOn:
        {
            NSLog(@">>>CBCentralManagerStatePoweredOn");
            
        }
            break;
        default:
            break;
    }
    if (self.delegate && [self.delegate respondsToSelector:@selector(pvBluetoothToolsUpdateManagerStaus:)]) {
        [self.delegate pvBluetoothToolsUpdateManagerStaus:central.state];
    }
}

发现设备回调

//搜索到设备
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{
    
    //通过名称过滤设备是否为过滤设备
    for (NSString * fliter in self.fliterName) {
        if ([peripheral.name hasPrefix:fliter]) {
            [self.discoverDevices addObject:peripheral];
            
            //把系统扫描出来的一起回调
            [self.discoverDevices addObjectsFromArray:self.sysConnectArrs];
            if (self.delegate && [self.delegate respondsToSelector:@selector(pvBluetoothToolsUpdateSerchDevice:sysConnected:)]){
                //查看下新搜索出来的设备系统是不是已经连接了
                NSArray * sysconnectedDeviceArr = [self.cbcManager retrieveConnectedPeripheralsWithServices:@[[CBUUID UUIDWithString:PVMG10BluetoothServiceUUID]]];
                BOOL sysConnected = [sysconnectedDeviceArr containsObject:peripheral];
                [self.delegate pvBluetoothToolsUpdateSerchDevice:peripheral sysConnected:sysConnected];
            }
        }
    }
}

连接设备

//CBConnectPeripheralOptionNotifyOnConnectionKey 表示应用被挂起时,系统应该为给定的外设显示警报
[self.cbcManager connectPeripheral:peripheral options:@{CBConnectPeripheralOptionNotifyOnConnectionKey:[NSNumber numberWithBool:YES]}];

连接结果回调

设备连接成功

//
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
    [self.connectedDeviceMap setObject:peripheral forKey:peripheral.name];
    
    //开始搜索服务
    [peripheral discoverServices:@[[CBUUID UUIDWithString:BluetoothUartServiceUUID]]];
}

连接失败

//连接失败
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
    
    NSLog(@"%@",error.localizedDescription);
}

连接断开

-(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
    NSLog(@"设备断开");
    [self.connectedDeviceMap removeObjectForKey:peripheral.name];
}

扫描外围设备的服务

//  uuid需要约定好
[peripheral discoverServices:@[[CBUUID UUIDWithString:BluetoothUartServiceUUID]]];

扫描结果回调

//发现服务服务
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
    for (CBService * service in peripheral.services) {
        if ([service.UUID.UUIDString isEqualToString:BluetoothUartServiceUUID]) {//确定串口服务
            这里查找特征
        }
    }

查询服务的特征

//开始查找特征
[peripheral discoverCharacteristics:NULL forService:service];

发现服务特征回调

//发现特征
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
    for (CBCharacteristic *characteristic in service.characteristics) {
        // 遍历获取对应的特征值
        // 获取约定的发送特征
        if ([characteristic.UUID.UUIDString isEqualToString:BluetoothSendcharacteristicUUID]) {
            BluetoothDevice * device = self.connectedDeviceMap[peripheral.name];
            device.sendCharacteristic = characteristic;
        }
        // 获取约定的接收特征
        else if ([characteristic.UUID.UUIDString isEqualToString:BluetoothReceivedcharacteristicUUID]){
            BluetoothDevice * device = self.connectedDeviceMap[peripheral.name];
            device.receivedCharacteristic = characteristic;
            [device.peripheral setNotifyValue:YES forCharacteristic:characteristic];
        }
        
        /**a
         -- 当发现characteristic有descriptor,回调didDiscoverDescriptorsForCharacteristic
         */
        [peripheral discoverDescriptorsForCharacteristic:characteristic];
    }
}

注册特征

// 注册了特征值后,就可以通过特征值来读取数据了。
[peripheral setNotifyValue:YES forCharacteristic:characteristic];

特征注册结果回调

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

通过特征读取数据

//收到数据
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    NSLog(@"%@",characteristic.value);
    if (self.delegate && [self.delegate respondsToSelector:@selector(pvBluetoothToolsReceiveData:)]) {
        [self.delegate pvBluetoothToolsReceiveData:characteristic.value];
    }
}

通过特征发送数据

type有两个值:

  • CBCharacteristicWriteWithResponse 需要返回发送数据的结果
  • CBCharacteristicWriteWithoutResponse 不需要返回发送数据的结果
[device.peripheral writeValue:data forCharacteristic:device.sendCharacteristic type:CBCharacteristicWriteWithoutResponse];

发送数据结果回调

如果需要返回发送结果,会调用当前回调

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

关闭蓝牙设备

- (void)closeBlueTooth {
    //停止扫描
    [self.centralManager stopScan];
    if (self.peripheral) {
        //断开当前的连接
        [self.centralManager cancelPeripheralConnection:self.peripheral];
    }
    self.centralManager = nil;
    self.peripheral = nil;
    self.characteristic = nil;
}
posted @ 2021-01-06 17:15  absty_guo  阅读(1203)  评论(0编辑  收藏  举报