一、框架
基于 <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 Description
和Privacy - 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;
}