0
点赞
收藏
分享

微信扫一扫

iOS蓝牙(BLE)

前言

目前iOS的蓝牙智能硬件都是基于低功耗的蓝牙4.0技术(Bluetooth Low Energy),使用的是系统自带的蓝牙库<CoreBluetooth/CoreBluetooth.h>

蓝牙的核心有两个概念:一个是中心:(Central);一个是外设(Peripheral)。中心是获取数据的,外设是发送数据的,比如手环和手机进行连接,手机就是中心设备,手环就是外设设备。

蓝牙设备有若干个服务(service),把数据分成一个个的独立逻辑项,每个服务里面包含若干个特征(characteristic),特征是最小的逻辑数据单元。

工作模式

蓝牙可以分为两种工作模式:一种是中心模式:以手机作为中心,连接其他外设;另外一种为外设模式,已手机作为外设连接其他中心设备。一般使用中心模式居多。

蓝牙数据接收流程:

1、创建中心角色CBCentralManager,开启扫描

2、在中心角色CBCentralManager的回调中发现正在广播信号的设备

3、连接我们需要的外围设备(可根据设备的唯一标志来辨别)

4、连接成功后外围设备开始寻找服务

5、遍历查找到的服务里的特征

6、与外设进行交互(写入数据、监听等)

代码实现

注:使用蓝牙需要设置系统使用蓝牙权限

Privacy - Bluetooth Always Usage Description

Privacy - Bluetooth Peripheral Usage Description

导入头文件

#import <CoreBluetooth/CoreBluetooth.h>

设置代理

<CBCentralManagerDelegate, CBPeripheralDelegate>

创建蓝牙管理者

/// 蓝牙管理者 
@property (nonatomic, strong) CBCentralManager *centralManager; 
/// 存储匹配成功的外设 
@property (nonatomic, strong) CBPeripheral *peripheral; 
/// 存储扫描到的所有外设 
@property (nonatomic, strong) NSMutableArray *peripherals;

self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];

CBCentralManager 代理方法

// 扫描外设
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {

    switch (central.state) {
        case CBManagerStateUnknown:
            NSLog(@"未知");
            break;
        case CBManagerStateResetting:
            NSLog(@"重置");
            break;
        case CBManagerStateUnsupported:
            NSLog(@"设备不支持");
            break;
        case CBManagerStateUnauthorized:
            NSLog(@"设备未授权");
            break;
        case CBManagerStatePoweredOff:
            NSLog(@"设备关闭");
            break;
        case CBManagerStatePoweredOn:
            NSLog(@"设备打开");
            // 开始扫描外设,然后会进入didDisvoverPeripheral方法
            /**
             1,两个参数为nil表示默认扫描所有可见的蓝牙设备
             2,第一个参数用来设置扫描有指定服务的外设
             3,第二个参数用来设置是否重复扫描已经发现的设备
             NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBCentralManagerScanOptionAllowDuplicatesKey];
             Bool 值为Yes,表示重复扫描,反之表示不会重复扫描
             */
            [self.centralManager scanForPeripheralsWithServices:nil options:nil];
            break;
        default:
            break;
    }
}

/// 发现外围设备
/// @param central 中心设备
/// @param peripheral 外围设备
/// @param advertisementData 特征数据
/// @param RSSI 信号质量(信号强度)
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI {
    // 发现外围设备
    NSLog(@"发现外围设备");

    // 停止扫描
    [self.centralManager stopScan];

    // 连接外围设备
    if (peripheral) {
        // 添加保存外围设备,注意如果这里不保存外围设备(或者说peripheral没有一个强引用,无法到达连接成功(或失败)的代理方法,因为在此方法调用完就会被销毁)
        if ([self.peripherals containsObject:peripheral]) {
            [self.peripherals addObject:peripheral];
        }
        NSLog(@"开始连接外围设备...");
        [self.centralManager connectPeripheral:peripheral options:nil];
    }
}

// 连接到Peripherals-成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
    NSLog(@"连接到名称为(%@)的设备-成功", peripheral.name);
    // 这个方法调用发现服务协议
    // 设置外围设备的代理为当前manager
    peripheral.delegate = self;
    // 外围设备开始寻找服务
    [peripheral discoverServices:nil];
}

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

// Peripherals 断开连接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {

    NSLog(@"外设连接断开连接:%@: %@ \n", [peripheral name], [error localizedDescription]);

}

CBPeripheral 代理方法

// 扫描到服务
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
    NSLog(@"扫描到服务:%@", peripheral.services);
    if (error) {
        NSLog(@"Discover services for %@ with error: %@", peripheral.name, [error localizedDescription]);
        return;
    }
    // 遍历查找到的服务
    for (CBService *service in [peripheral services]) {
        [peripheral discoverCharacteristics:nil forService:service];
    }
}

// 扫描到特征
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(nonnull CBService *)service error:(nullable NSError *)error {
    // 已发现可用特征
    if (error) {
        NSLog(@"error Discovered characteristics for %@ with error: %@", service.UUID, [error localizedDescription]);
        return;
    }
    
    // 遍历服务中的特征
    for (CBCharacteristic *characteristic in service.characteristics) {
        NSLog(@"服务: %@ 的特征: %@", service.UUID, characteristic.UUID);
        // 筛选你需要的UUID,进行连接
//        if ([characteristic.UUID isEqual: yourUUID]) {
        // 情景一:通知
//            // 订阅,实时接收
//            [peripheral setNotifyValue:YES forCharacteristic:characteristic];
        // 情景二:读取
//        [peripheral readValueForCharacteristic:characteristic];
//        if (characteristic.value) {
//            NSString *value = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
//            NSLog(@"读取到特征值: %@", value);
//        }
//        }
    }
}

// 特征值被更新后
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error {
    NSLog(@"收到特征更新通知。。。");
    if (error) {
        NSLog(@"更新通知状态时发生错误,错误信息为: %@", error.localizedDescription);
    }

    /*
    // 给特征值设置新的值
    CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID];
    if ([characteristic.UUID isEqual:characteristicUUID]) {
        if (characteristic.isNotifying) {
            if (characteristic.properties == CBCharacteristicPropertyNotify) {
                NSLog(@"已订阅特征通知");
                return;
            }else if (characteristic.properties == CBCharacteristicPropertyRead) {
                // 从外围设备读取新值,调用此方法会触发代理方法:didupdatevalueforcharacteristic:
                [peripheral readValueForCharacteristic:characteristic];
            }
        }else {
            NSLog(@"已停止");
            // 取消连接
            [self.centralManager cancelPeripheralConnection:peripheral];
        }
    }
     */
}

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error {
    if (error) {
        NSLog(@"更新特征值时发生错误,错误信息为:%@", error.localizedDescription);
        return;
    }

    if (characteristic.value) {
        NSString *value = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
        NSLog(@"读取到特征值%@", value);
    }else {
        NSLog(@"未发现特征值");
    }
}

// 读取数据
// 获取指定特性的数据
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    if (error) {
        NSLog(@"error Discovered characteristics for %@ with error: %@", characteristic.UUID, [error localizedDescription]);
        return;
    }

    // 接收蓝牙发来的数据
    NSLog(@"characteristic uuid: %d value: %@", characteristic.UUID, characteristic.value);

}

写数据

[self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];

断开连接

[self.centralManager cancelPeripheralConnection:self.peripheral];

举报

相关推荐

0 条评论