前言
目前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];