蓝牙
概述
蓝牙开发主要用的是系统提供的core Bluetooth 这个框架,在该框架下有两种模式,一种是以应用为核心连接别的外设,另一种是手机作为外设让其他设备连接。我的项目是模式一,核心内容是蓝牙中心和外设,也就是框架中CBCentralManager和CBPeripheral这两个类。
实现流程
- 创建中心管理者
- 判断蓝牙状态是否可用
- 可用,就扫描外设
- 连接外设
- 查找服务,获取服务的 UUID
- 查找特征,获取特征的 UUID
- 订阅通知
- 更新数据
具体代码
创建一个蓝牙工具类,继承 NSObject,这个工具类用单例来实现,因为单例是一个类只有一个实例,然后提供一个全局访问入口访问这个实例。在整个应用程序中只需要一个蓝牙管理者,不需要多个。
+(instancetype)shareBLPenManager{
static BLPenManager *manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[BLPenManager alloc]init];
});
return manager;
}
我的项目需求是点击连接按钮后展示外设列表,选中外设列表后连接外设。所以在工具类中在提供三个方法:扫描外设、连接外设、断开连接来管理蓝牙。
/*** 扫描外设 */
- (void)searchPer:(void(^)(NSArray *peripheralArr))peripheral;
/*** 连接外设 */
- (void)connectPer:(CBPeripheral *)peripheral Completion:(void(^)(NSError *error))completionBlock;
/*** 断开连接 */
- (void)cancelConnect;
根据实现流程创建中心管理者,判断状态,搜索外设
/*** 搜索外设 */
- (void)searchPer:(void (^)(NSArray *))peripheral{
// 判断蓝牙状态
BOOL result = [self blueToothIsAvailable];
if (result) {
[self.centerManager scanForPeripheralsWithServices:nil options:nil];
self.scanBlock = peripheral;
}else{
return;
}
}
/*** 取消连接 */
- (void)cancelConnect{
[self.centerManager cancelPeripheralConnection:self.peripheral];
}
扫描外设之后后执行 CBCentralManagerDelegate 的代理方法。
// 扫描到设备
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{
NSLog(@"---------------");
NSLog(@"唯一标识符:%@",peripheral.identifier);//设备唯一标识符
NSLog(@"外设:%@",peripheral);
NSLog(@"外设广告语:%@",advertisementData);
NSLog(@"当前外设信号:%@",RSSI);
//扫描到设备之后添加到扫描设备数组,用于界面显示
//同一个设备会重复扫描,添加到数组中,所以要做一个去重复的判断
if (self.scanArr == nil) {
self.scanArr = [[NSMutableArray alloc]init];
}
//如果设备已经添加到数组中则不添加,否则添加
if (![self.scanArr containsObject:peripheral]) {
[self.scanArr addObject:peripheral];
}
//送出回调,刷新UI
if (self.scanBlock) {
self.scanBlock([self.scanArr copy]);
}
}
根据外设列表选择需要连接的外设
/*** 连接外设 */
- (void)connectPer:(CBPeripheral *)peripheral Completion:(void (^)(NSError *))completionBlock{
[self.centerManager connectPeripheral:peripheral options:nil];
self.connectBlok = completionBlock;
}
连接之后,继续执行代理方法。我根据项目需求对外设作了筛选
// 连接外设
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
NSString *perName = peripheral.name;
// 连接筛选.
if ([perName hasPrefix:@"ET"] || [perName hasPrefix:@"H"]) {
if (self.connectBlok) {
self.connectBlok(nil);
}
// 停止扫描
[self.centerManager stopScan];
self.peripheral = peripheral;
self.peripheral.delegate = self;
// 查找服务
[self.peripheral discoverServices:nil];
}else{
NSLog(@"选择错误");
}
}
连接成功和失败的代理方法
// 连接失败后调用
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
NSLog(@"连接失败");
}
// 连接断开
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
NSLog(@"连接断开");
}
连接成功后会执行CBPeripheralDelegate外设的 dial 方法查找服务
// 查找服务
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
for (CBService *service in peripheral.services) {
//Kservice_uuid 根据硬件的功能对应的服务进行修改
if ([service.UUID.UUIDString isEqualToString:Kservice_uuid] || [service.UUID.UUIDString isEqualToString:AKservice_uuid]) {
[peripheral discoverCharacteristics:nil forService:service];
}
}
}
查找服务后执行查找特征的代理方法
// 查找特征
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(nonnull CBService *)service error:(nullable NSError *)error{
// 判断特征
for (CBCharacteristic *characterristic in service.characteristics) {
if ([characterristic.UUID.UUIDString isEqualToString:Kcharacteristic_uuid]||[characterristic.UUID.UUIDString isEqualToString:AKcharacteristic_uuid]) {
// 发现特征后打开通知,用了订阅特征值
[peripheral setNotifyValue:YES forCharacteristic:characterristic];
}
}
}
特征之后执行更新数据的代理方法
// 更新数据的时候调用
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
// NSLog(@"更新后的数据 %@",characteristic.value);
NSData *data = characteristic.value;
// 传出数据
}
总结
以上就是以应用为中心以其他设备为外设的模式的蓝牙开发大致步骤。主要的点就是以单例为工具管理类,注意CBCentralManagerDelegate 和 CBPeripheralDelegate两代理方法的使用。