iOS轻松搞定蓝牙开发

最近刚做了一个蓝牙开发的项目,要求通过蓝牙接收数据和写入数据,下面将蓝牙开发的流程做一个简单的介绍。

概念理解

开发蓝牙之前,通过看看官方文档和网上查看资料了解了蓝牙开发的大体流程,首先得理解关于蓝牙开发中的一些概念。我们都是通过基于蓝牙4.0的低功耗蓝牙进行开发,开发用到的框架是CoreBluetooth。下面解释几个概念:

中心者模式和管理者模式

中心者模式:这个使用的很普遍,就是手机作为主机,蓝牙作为外设。
管理者模式:我们手机自己作为外设,自己创建服务和特征,然后有其他的设备连接我们的手机。

中心CBCentral和外设CBPeripheral

BLE中的交互涉及两个重要角色:中心CBCentral和外围设备(简称外设)CBPeripheral。外设通常具有其他设备所需要的数据,中心通常使用外设提供的信息来实现特定的功能。

服务CBService和特征CBCharacteristic

每个外设CBPeripheral中包含一个或者多个服务CBService以及有关其连接信号的信息。服务是实现一个函数或者功能的设备的数据采集和相关行为的集合。每个服务下面又有很多特征CBCharacteristic,特征提供了这些服务的详细内容。我们在进行BLE蓝牙开发的时候,就需要通过特定服务下面的特定特征来获取想要的数据和内容,特征是与外界交互的最小单位。

iOS轻松搞定蓝牙开发_第1张图片

UUID

关于UUID,暂时可以理解为蓝牙的唯一标识,每个服务和特征都会有相应的UUID,可以通过UUID来代表特定的服务和特征。

步骤:

  1. 导入头文件#import
  2. 遵守协议CBCentralManagerDelegate,CBPeripheralDelegate
  3. 建立中心管理者CBCentralManager对蓝牙进行管理
  4. 扫描外设,使用方法scanForPeripheralsWithServices
  5. 连接扫描到的外设
  6. 扫描并获取外设的服务CBService
  7. 扫描并获取外射服务下面的特征CBCharacteristic
  8. 获取特征的值,即从外围设备读取数据,用didUpdateValueForCharacteristic方法
  9. 订略特征的通知,实现当连接蓝牙成功之后以通知的方式实现对特征里面数据的读写。需要调用- (void)setNotifyValue:(BOOL)enabled forCharacteristic:(CBCharacteristic *)characteristic方法
  10. 写入数据,调用writeValue:forCharacteristic:type:方法

示例代码

  1. 建立中心管理者和外设
/** 主设备(可以扫描和链接外设备) */
@property (nonatomic, strong) CBCentralManager * centeralManger;
/** 外设备 */
@property (nonatomic, strong) CBPeripheral * peripheral;
/** 用于保存被发现的设备 */
@property (nonatomic, strong) NSMutableArray * discoverPeripherals;

2.初始化中心管理者并设置委托

    // 初始化并设置委托和线程
    self.centeralManger = [[CBCentralManager alloc]initWithDelegate:self queue:nil];
    self.discoverPeripherals = [[NSMutableArray alloc]init];

将queue的参数设置为nil,默认就是在住线程中执行。

3.初始化中心管理者之后,用代理方法监听主设备状态的改变,当检测到蓝牙打开以后,调用扫描外设的方法:

#pragma mark - CBCentralManagerDelegate
/**
 * 主设备状态改变
 */
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
    
    switch (central.state) {
        case CBManagerStateUnknown:
            NSLog(@">>>CBManagerStateUnknown");
            break;
        case CBManagerStateResetting:
            NSLog(@">>>CBManagerStateResetting");
        case CBManagerStateUnsupported:
            NSLog(@">>>CBManagerStateUnsupported");
        case CBManagerStateUnauthorized:
            NSLog(@">>>CBManagerStateUnauthorized");
        case CBManagerStatePoweredOff:
            NSLog(@">>>CBManagerStatePoweredOff");
            
//            [SVProgressHUD setBackgroundColor:[UIColor yellowColor]];
            [SVProgressHUD showErrorWithStatus:@"请打开手机蓝牙开关!"];
            break;
            
        case CBManagerStatePoweredOn:
            NSLog(@">>>CBManagerStatePoweredOn");
            
            // 开始扫描外围设备
            /**
             * 第一个参数为nil就是扫描周围所有的外设,扫描后会进入
             */
            [self.centeralManger scanForPeripheralsWithServices:nil options:nil];
            break;
        default:
            break;
    }
}
  1. 在扫描到外设的代理方法里面持有外设
// 扫描到设备会进入方法
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{
    
    [SVProgressHUD dismiss];
    
    NSLog(@"扫描到设备名字:%@", peripheral.name);
    
    for (CBPeripheral * thePeripheral in self.discoverPeripherals) {
        
        if ([thePeripheral.name isEqual:peripheral.name]) return;
        
    }
    
    if (peripheral) {
        
        //找到设备必须持有他,否者CBCentralManager也不会保存peripheral
        [self.discoverPeripherals addObject:peripheral];
        
        
        NSLog(@"discoverPeripherals - %@", self.discoverPeripherals);
        
        [self.BLEtableView reloadData];
        
        // 如果在这停止扫描 那么就每次就只能扫描到一个外设备
//        [self.centeralManger stopScan];
    }else{
        
        [SVProgressHUD showErrorWithStatus:@"没有扫描到蓝牙设备!"];
    }   
}

5.用代理方法实现连接蓝牙,在连接成功的方法里面实现读取数据的通知,并设置外设的代理

// 连接成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
    
    NSLog(@">>>连接到名称为(%@)的设备 - 成功", peripheral.name);
    
    [SVProgressHUD showSuccessWithStatus:@"连接成功!"];
    
    
    peripheral.delegate = self;
    
    //扫描外设备的services
    [peripheral discoverServices:nil];
    

        
        //发送通知
        [self notifyCharacteristic:peripheral characteristic:self.characteristic];

    [self.centeralManger stopScan];
}


// 连接到peripherals - 失败
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
    
    NSLog(@">>>连接到名称为(%@)的设备-失败,原因:%@",[peripheral name],[error localizedDescription]);
    [SVProgressHUD showErrorWithStatus:@"连接失败!"];
}

// peripherals连接断开
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
    
    NSLog(@">>>外设连接断开连接 %@: %@\n", [peripheral name], [error localizedDescription]);
    
    [SVProgressHUD showErrorWithStatus:@"连接断开!"];
}

6.用外设的代理方法扫描服务和特征

#pragma mark  - CBPeripheralDelegate

// 扫描到services
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
    
    
    
    if (error) {
        NSLog(@"扫描失败原因 - %@", error.localizedDescription);
        return;
    }
    
    NSLog(@"扫描到服务 - %@", peripheral.services);
    
    // 扫描每个服务的特征
    for (CBService * service in peripheral.services) {
        
        NSLog(@"service 的 UUID : %@", service.UUID);
        
        // 扫描每个service的characteristics
        [peripheral discoverCharacteristics:nil forService:service];
        
    }
}

// 扫描到characteristics
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
    
    if (error) {
        NSLog(@"error Discovered characteristics for %@ with error:%@", service.UUID, error.localizedFailureReason);
        return;
    }
    
    
    
    for (CBCharacteristic * characteristics in service.characteristics) {
        
        NSLog(@"services:%@ 的 characteristics:%@", service.UUID, characteristics.UUID);
        
        
    }
    
    // 获取characteristics的值
    for (CBCharacteristic * characteristics in service.characteristics) {
        
        [peripheral readValueForCharacteristic:characteristics];
        
    }
    
    // 搜索characteristics的description
    for (CBCharacteristic * characteristics in service.characteristics) {
        
        [peripheral discoverDescriptorsForCharacteristic:characteristics];
        
        [peripheral setNotifyValue:YES forCharacteristic:characteristics];
    }
    
    
}

7.读取特征的值(即读取数据)

// 获取characteristics的值 - 从外围设备读数据
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
   
 NSLog(@"characteristic 的 uuid:%@--value:%@",characteristic.UUID,characteristic.value);

 if (error) {
        NSLog(@"Error changing notification state: %@", [error localizedDescription]);
    }
    self.characteristic = characteristic;   
}

8.实现写入数据的方法

// 写数据 - 将数据写入特征
- (void)writeCharactereristic:(CBPeripheral *)peripheral characteristic:(CBCharacteristic *)characteristic value:(NSData *)value{
    
    NSLog(@"------------%lu", (unsigned long)characteristic.properties);
    
    //只有 characteristic.properties 有write的权限才可以写
    if(characteristic.properties & CBCharacteristicPropertyWrite){
        /*
         最好一个type参数可以为CBCharacteristicWriteWithResponse或type:CBCharacteristicWriteWithResponse,区别是是否会有反馈
         */
        [peripheral writeValue:value forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
    }else{
        NSLog(@"该字段不可写!");
    }
    
}

8 征订通知和取消通知

// 6.订阅特征的通知
//设置通知
-(void)notifyCharacteristic:(CBPeripheral *)peripheral
             characteristic:(CBCharacteristic *)characteristic{
    //设置通知,数据通知会进入:didUpdateValueForCharacteristic方法
    [peripheral setNotifyValue:YES forCharacteristic:characteristic];
    
}

//取消通知
-(void)cancelNotifyCharacteristic:(CBPeripheral *)peripheral
                   characteristic:(CBCharacteristic *)characteristic{
    
    [peripheral setNotifyValue:NO forCharacteristic:characteristic];
}

如果将扫描到的蓝牙用tebleView来显示,就会得到如下效果:


iOS轻松搞定蓝牙开发_第2张图片

你可能感兴趣的:(iOS轻松搞定蓝牙开发)