import
导入框架,本文仅介绍以下功能:
- 蓝牙状态回调
- 扫描设备
- 连接设备
- 查找服务
- 查找特征
- 订阅特征
- 写入数据
- 读取RSSI值
- 断开重连
- 后台持续使用蓝牙
即只说明如何使用该框架。
初始化ble对象
遵循代理
@property(nonatomic,strong) CBCentralManager *centralManager;
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
蓝牙状态检测
当蓝牙状态发生变化时,会回调该函数
- (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"); //开启
break;
}
}
}
扫描设备
serviceUUIDs:只扫描出含有该UUID的设备,即过滤设备
options:扫描模式,一般有两种:
CBCentralManagerScanOptionAllowDuplicatesKey:是否重复扫描已扫描到的设备
CBCentralManagerScanOptionSolicitedServiceUUIDsKey:蓝牙未打开时是否显示弹框
if (self.centralManager.state == CBManagerStatePoweredOn) {
[self.centralManager scanForPeripheralsWithServices:serviceUUIDs options:options];
}
//options的写法为
NSDictionary *option = @{CBCentralManagerScanOptionAllowDuplicatesKey : [NSNumber numberWithBool:NO],CBCentralManagerOptionShowPowerAlertKey:YES};
停止扫描
[self.centralManager stopScan];
扫描设备成功后回调函数
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
//peripheral: 设备
//advertisementData: 广播包
//RSSI:RSSI信号值
}
连接设备
/*
options:
CBConnectPeripheralOptionNotifyOnConnectionKey —— 在连接成功后,程序被挂起,给出系统提示。
CBConnectPeripheralOptionNotifyOnDisconnectionKey —— 在程序挂起,蓝牙连接断开时,给出系统提示。
CBConnectPeripheralOptionNotifyOnNotificationKey —— 在程序挂起后,收到 peripheral 数据时,给出系统提示。
*/
[self.centralManager connectPeripheral:peripheral options:options];
断开设备:
[self.centralManager cancelPeripheralConnection:peripheral];
代理回调
//连接成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
// NSLog(@"didConnectPeripheral...");
[self.centralManager stopScan];
}
//连接失败
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
// NSLog(@"didFailToConnectPeripheral");
}
//连接断开
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
// NSLog(@"didDisconnectPeripheral");
}
查找服务
连接设备后可以查找该设备支持的服务,遵循代理。
serviceUUIDs:扫描指定服务,为nil时说明扫描所有服务
peripheral.delegate = self;
[peripheral discoverServices:serviceUUIDs];
代理回调
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(nullable NSError *)error {
// NSLog(@"didDiscoverServices...");
}
查找特征
characteristicUUIDs:扫描指定特征的UUID
service:传入服务对象
[peripheral discoverCharacteristics:characteristicUUIDs forService:service];
代理回调
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
// NSLog(@"didDiscoverCharacteristicsForService");
}
订阅特征
enabled:特征有消息时是否进行通知
[peripheral setNotifyValue:enabled forCharacteristic:characteristic];
代理回调
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
// NSLog(@"didUpdateValueForCharacteristic");
//NSData *data = characteristic.value; //回调值
}
写入数据
写入数据到ble设备
data:要写入的数据
characteristic:通过该特征写入
type:哪一种类型的写入,有一下两种,默认填第一个:
CBCharacteristicWriteWithResponse = 0,
CBCharacteristicWriteWithoutResponse,
在选择哪一种类型之前,可以先判断特征Characteristic.properties属性,尝试进去看他的API,会发现
typedef NS_OPTIONS(NSUInteger, CBCharacteristicProperties) {
CBCharacteristicPropertyBroadcast = 0x01,
CBCharacteristicPropertyRead = 0x02,
CBCharacteristicPropertyWriteWithoutResponse = 0x04,
CBCharacteristicPropertyWrite = 0x08,
CBCharacteristicPropertyNotify = 0x10,
CBCharacteristicPropertyIndicate = 0x20,
CBCharacteristicPropertyAuthenticatedSignedWrites = 0x40,
CBCharacteristicPropertyExtendedProperties = 0x80,
CBCharacteristicPropertyNotifyEncryptionRequired NS_ENUM_AVAILABLE(10_9, 6_0) = 0x100,
CBCharacteristicPropertyIndicateEncryptionRequired NS_ENUM_AVAILABLE(10_9, 6_0) = 0x200
};
当你发现写入不成功时,查看下是否对应上该特征的写入类型。
[peripheral writeValue:data forCharacteristic:characteristic type:type];
代理回调
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
// NSLog(@"didWriteValueForCharacteristic");
}
读取RSSI值
RSSI值表示蓝牙信号强度,可以通过该值大致判断设备与自身的距离,不过计算不是很准确罢了,RSSI转距离可以参考该链接
[peripheral readRSSI];
代理回调
- (void)peripheral:(CBPeripheral *)peripheral didReadRSSI:(NSNumber *)RSSI error:(NSError *)error {
}
断开重连
这里说一下,iOS是无法获取ble设备的mac地址的,要实现重连,可以记录扫描到的设备的UUID,然后在重新开始扫描的时候,在扫到设备中判断UUID值即可。
记录设备的UUID:
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
[self.centralManager stopScan];
//在连接成功的时候记录UUID
NSLog(@"设备UUID: %@",peripheral.identifier.UUIDString);
}
//在扫描设备的时候检测重连
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
if ([peripheral.identifier.UUIDString isEqualToString:@"记录的UUID"]) {
//连接...
}
}
后台持续使用蓝牙
iOS是提供后台使用蓝牙的。
默认情况下,iOS程序在后台时还会运行5-10秒,之后就会被系统冻结,不会再运行。如果要让蓝牙在后台依旧能够使用,需要在info.plist中添加UIBackgroundModes这个Key,这个一个数组,然后在这个数组内添加:
bluetooth-central —— 即 Central。
bluetooth-peripheral —— 即 Peripheral。
从上面可以看出,添加的是对应角色,如果你的ble设备两者皆是的话就都添加吧。
此时当你的程序进入后台后且被系统冻结后,当系统蓝牙检测到已连接过的蓝牙发生变化,如ble设备断电、断开、发送数据给应用等,都会将相应的被冻结住的应用进行激活,激活时间同样是5-10秒,在这点时间内已经可以做到足够多的事了,但是有时候5-10秒依旧不足以应对需求,那么我们可以在这5-10秒内向系统提交一个申请,请求多一段后台使用时间,大概是10-20分钟,这样就更加足够做需求了,关于申请后台运行时间可以参考该链接
上面的代码我进行了block封装
github地址