iOS蓝牙BLE4.0通信功能
概述
详细
一、蓝牙常见名称和缩写
-
BLE:(Bluetooth low energy)蓝牙4.0设备因为低耗电
-
BLE:(Bluetooth low energy)蓝牙4.0设备因为低耗电
-
Central:中心设备,发起蓝牙连接的设备(一般是指手机)
-
Peripheral:外设,被蓝牙连接的设备(一般是运动手环)
-
Service and Characteristic:服务和特征,每个设备会提供服务和特征,类似于服务端的API,但是结构不同,每个设备会有很多服务,每个服务中包含很多特征,这些特征的权限一般分为读(read),写(write),通知(notify)几种,就是我们连接设备后具体需要操作的内容
-
Description:描述,每个Characteristic可以对应一个或者多个Description用于描述Characteristic的信息或属性
二、蓝牙基础知识
1、CoreBluetooth框架的核心其实是俩东西
-
Peripheral
-
Central
2、这两组api分别对应不同的业务常见
-
左侧叫中心模式,就是以你的app作为中心,连接其他的外设的场景
-
右侧称为外设模式,使用外设连接其他中心设备操作的场景
3、服务和特征(service and characteristic)
-
每个设备都会有1个or多个服务
-
每个服务里都会有1个or多个特征
-
特征就是具体键值对,提供数据的地方
-
每个特征属性分为:读,写,通知等等
外设,服务,特征的关系
三、BLE中心模式流程
1、建立中心角色
2、扫描外设(Discover Peripheral)
3、连接外设(Connect Peripheral)
4、扫描外设中的服务和特征(Discover Services And Characteristics)
4.1 获取外设的services
4.2 获取外设的Characteristics,获取characteristics的值
4.3 获取Characteristics的Descriptor和Descriptor的值
5、利用特征与外设做数据交互
6、订阅Characteristic的通知
7、断开连接(Disconnect)
四、准备工作
1、一台苹果设备,进行真机测试
2、一个蓝牙模块或者外设
五、程序实现
项目代码截图:
以下是实现的过程:
1、导入依赖库、声明委托、定义变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #import "ViewController.h" #import <CoreBluetooth/CoreBluetooth.h> #define mBLEName @"ZJ2" @interface ViewController () <CBCentralManagerDelegate, CBPeripheralDelegate> //手机设备 @property (nonatomic, strong) CBCentralManager *mCentral; //外设设备 @property (nonatomic, strong) CBPeripheral *mPeripheral; //特征值 @property (nonatomic, strong) CBCharacteristic *mCharacteristic; //服务 @property (nonatomic, strong) CBService *mService; //描述 @property (nonatomic, strong) CBDescriptor *mDescriptor; @end |
2、程序开始时初始化设备
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | - (CBCentralManager *)mCentral { if (!_mCentral) { _mCentral = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue() options:nil]; } return _mCentral; } - ( void )viewDidLoad { [super viewDidLoad]; //中心管理者初始化 [self mCentral]; } |
3、当程序退出时,记得断开连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | - ( void )viewDidDisappear:( BOOL )animated { [super viewDidDisappear:animated]; // 停止扫描 if ([self.mCentral isScanning]){ NSLog(@ "stopScan" ); [self.mCentral stopScan]; } //停止连接 if (nil != self.mPeripheral && self.mPeripheral.state == CBPeripheralStateConnecting){ NSLog(@ "cancelPeripheralConnection" ); [self.mCentral cancelPeripheralConnection:self.mPeripheral]; } } |
4、扫描外设
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | //只要中心管理者初始化,就会触发此代理方法 - ( void )centralManagerDidUpdateState:(CBCentralManager *)central { switch (central.state) { case CBManagerStateUnknown: NSLog(@ "CBManagerStateUnknown" ); break ; case CBManagerStateResetting: NSLog(@ "CBManagerStateResetting" ); break ; case CBManagerStateUnsupported: NSLog(@ "CBManagerStateUnsupported" ); break ; case CBManagerStateUnauthorized: NSLog(@ "CBManagerStateUnauthorized" ); break ; case CBManagerStatePoweredOff: NSLog(@ "CBManagerStatePoweredOff" ); break ; case CBManagerStatePoweredOn: { NSLog(@ "CBManagerStatePoweredOn" ); //搜索外设 [self.mCentral scanForPeripheralsWithServices:nil // 通过某些服务筛选外设 options:nil]; // dict,条件 } break ; default : break ; } } |
5、连接外设
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //发现外设后调用的方法 - ( void )centralManager:(CBCentralManager *)central // 中心管理者 didDiscoverPeripheral:(CBPeripheral *)peripheral // 外设 advertisementData:(NSDictionary *)advertisementData // 外设携带的数据 RSSI:(NSNumber *)RSSI // 外设发出的蓝牙信号强度 { NSLog(@ "搜索到设备名:%@,设备ID:%@" ,peripheral.name,peripheral.identifier); //(ABS(RSSI.integerValue) > 35) //发现完之后就是进行连接 if ([peripheral.name isEqualToString:mBLEName]){ self.mPeripheral = peripheral; self.mPeripheral.delegate = self; [self.mCentral connectPeripheral:peripheral options:nil]; } } |
6、获取服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //中心管理者连接外设成功 - ( void )centralManager:(CBCentralManager *)central // 中心管理者 didConnectPeripheral:(CBPeripheral *)peripheral // 外设 { NSLog(@ "设备连接成功,设备名:%@" , peripheral.name); //7、外设发现服务,传nil代表不过滤 [self.mPeripheral discoverServices:nil]; } // 外设连接失败 - ( void )centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { NSLog(@ "设备连接失败,设备名:%@" , peripheral.name); } // 丢失连接 - ( void )centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { NSLog(@ "设备丢失连接,设备名:%@" , peripheral.name); } |
7、获取服务中的特征
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //发现外设的服务后调用的方法 - ( void )peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error { // 是否获取失败 if (error) { NSLog(@ "设备获取服务失败,设备名:%@" , peripheral.name); return ; } for (CBService *service in peripheral.services) { self.mService = service; NSLog(@ "设备获取服务成功,服务名:%@,服务UUID:%@,服务数量:%lu" ,service,service.UUID,peripheral.services.count); //外设发现特征 [peripheral discoverCharacteristics:nil forService:service]; } } |
8、获取特征中的值和描述
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | //从服务中发现外设特征的时候调用的代理方法 - ( void )peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error { if (error){ NSLog(@ "设备获取特征失败,设备名:%@" , peripheral.name); return ; } /** CBCharacteristicPropertyRead = 0x02, CBCharacteristicPropertyWriteWithoutResponse = 0x04, CBCharacteristicPropertyWrite = 0x08, CBCharacteristicPropertyNotify = 0x10, */ for (CBCharacteristic *cha in service.characteristics) { if (cha.properties & CBCharacteristicPropertyWrite){ NSLog(@ "CBCharacteristicPropertyWrite" ); NSLog(@ "%lu" ,cha.properties & CBCharacteristicPropertyWrite); self.mCharacteristic = cha; } else if (cha.properties & CBCharacteristicPropertyWriteWithoutResponse){ NSLog(@ "CBCharacteristicPropertyWriteWithoutResponse" ); } else if (cha.properties & CBCharacteristicPropertyRead){ NSLog(@ "CBCharacteristicPropertyRead" ); } else if (cha.properties & CBCharacteristicPropertyNotify){ NSLog(@ "CBCharacteristicPropertyNotify" ); } else if (cha.properties & CBCharacteristicPropertyIndicate){ NSLog(@ "CBCharacteristicPropertyIndicate" ); } NSLog(@ "设备获取特征成功,服务名:%@,特征值名:%@,特征UUID:%@,特征数量:%lu" ,service,cha,cha.UUID,service.characteristics.count); //获取特征对应的描述 会回调didDiscoverDescriptorsForCharacteristic [peripheral discoverDescriptorsForCharacteristic:cha]; //获取特征的值 会回调didUpdateValueForCharacteristic [peripheral readValueForCharacteristic:cha]; } if (nil != self.mCharacteristic){ //打开外设的通知,否则无法接受数据 [peripheral setNotifyValue:YES forCharacteristic:self.mCharacteristic]; } } |
9、读取特征中的值和描述
1 2 3 4 5 6 7 8 9 10 11 12 | //更新特征值的时候调用,可以理解为获取蓝牙发回的数据 - ( void )peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { NSString *value = [[NSString alloc] initWithData:characteristic.value encoding:NSASCIIStringEncoding]; NSLog(@ "特征名:%@,特征值:%@" ,characteristic,value); if ([value isEqualToString:@ "open" ]){ } else if ([value isEqualToString:@ "close" ]){ } } |
10、状态改变和发现描述
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | //通知状态改变时调用 -( void )peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{ if (error){ NSLog(@ "特征名:%@,改变通知状态失败" ,characteristic); } NSLog(@ "特征名:%@,改变了通知状态" ,characteristic); } //发现外设的特征的描述数组 - ( void )peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error { if (error){ NSLog(@ "设备获取描述失败,设备名:%@" , peripheral.name); return ; } for (CBDescriptor *descriptor in characteristic.descriptors) { self.mDescriptor = descriptor; [peripheral readValueForDescriptor:descriptor]; NSLog(@ "设备获取描述成功,描述名:%@" ,descriptor); } } |
11、发送数据
1 2 3 4 5 6 7 8 9 10 11 | //发送数据 -( void )sendDataToBLE:(NSString *)data{ NSData* myData = [data dataUsingEncoding:NSUTF8StringEncoding]; [self.mPeripheral writeValue:myData // 写入的数据 forCharacteristic:self.mCharacteristic // 写给哪个特征 type:CBCharacteristicWriteWithResponse]; // 通过此响应记录是否成功写入 } -( void )peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{ NSLog(@ "数据发送成功" ); } |
六、运行效果
从电脑串口助手可以看到,发送了两次的D3数据,手机也收到了两次11的数据
这里使用的是蓝牙模块Risym cc2541和苹果手机实现两者的通信功能,根据BLE中心模式流程走就可以了
下面是手机设备NSLog打印输出的结果,从连接到发送数据和接收数据的过程。
(查看大图)
可以发现连接成功后,设备有两个服务,第一个服务对应有九个特征值,第二个服务对应有一个特征值,验证了上面的原理是正确的
(查看大图)
七、其他补充
CSDN博客地址:http://blog.csdn.net/qq_30379689/article/details/61413950
CSDN课程地址:http://edu.csdn.net/course/detail/4534
注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?