03-iOS蓝牙架构搭建
来源:互联网 发布:java调用外部http接口 编辑:程序博客网 时间:2024/06/05 08:44
蓝牙架构的搭建
前言:笔者认为,如果只是单纯的传授大家代码怎么敲,那么大家很有可能在实际开发中难以运用。刚好本人曾经参与过多款智能硬件开发的架构搭建,本小节本人就现场带领大家开发出一个通用的蓝牙工具类
- 既然是工具类,虽然大家以后可以在开发中直接拿去用,但是我的目的是想要传授给大家架构的思想,而不是教大家如何偷懒
- 为了能够让大家对蓝牙通讯理解的更加的透彻,本人专门买了一个小米手环,并且经过大量的测试,破解了部分小米的蓝牙协议(小米手环蓝牙数据是没有加密的)
- 只有对技术执着的追求,才能造就更高的品质
目前该工具类由于时间原因,主要是想让大家熟悉蓝牙开发的流程,并没有对更深层次的架构做研究
- 1.只支持蓝牙与外设一对一连接,一对多未做复杂处理
- 一般开发中,一对一够用了
- 2.对API接口的架构没有做深入的探讨研究
- 关于类的接口设计,将会在下一个课程阶段
实用技术项目阶段
再给大家重点介绍,目前大家也很难吸收太难的知识点
- 关于类的接口设计,将会在下一个课程阶段
- 3.本人将会在后期继续优化我们的框架,并且放入
github
供全球的iOS开发朋友们使用- 中国软件的下一步发展就是要走向国际一流
- 1.只支持蓝牙与外设一对一连接,一对多未做复杂处理
HMBluetoothManager.h文件
#import <Foundation/Foundation.h>#import <CoreBluetooth/CoreBluetooth.h>#define kHMBluetoothManager [HMBluetoothManager shareInstance]@interface HMBluetoothManager : NSObject//单利类实现+(HMBluetoothManager*)shareInstance;//蓝牙中心@property(nonatomic,strong)CBCentralManager *CB_central;//蓝牙外设数组,蓝牙支持一对多连接(一个中心 多个外设)//扫描到的外设数组@property(nonatomic,strong)NSMutableArray <CBPeripheral *>*scanArr;//已经连接的外设数组@property(nonatomic,strong)NSMutableArray <CBPeripheral *>*connectArr;//扫描外设成功回调@property(nonatomic,copy)void(^scanPeripheralUpdate)(CBPeripheral *peripheral);//连接外设成功回调@property(nonatomic,copy)void(^connectedPeripheral)(CBPeripheral *peripheral,NSString *connectState);//当前激活的外设(目前的架构暂时只支持一对一连接)@property(nonatomic,strong)CBPeripheral *currentPeripheral;//当前蓝牙特征(发送数据)@property (strong ,nonatomic) CBCharacteristic *currentCharacteristic;//当前发送数据的UUID@property(nonatomic,strong)NSString *UUID;/** 检测蓝牙是否可用 @param completion 错误表示 可用标签 @return 可用标签 */- (BOOL)isDeviceBluetoothAvaliable:(void(^)(NSError *error,BOOL flag))completion;/** 开始扫描 */- (void)BeginScanPeripheral:(void(^)(CBPeripheral *peripheral))scanPeripheralUpdate;/** 连接外设 @param peripheral 外设 @param connectedPeripheral 连接回调 */- (void)connectPeripheral:(CBPeripheral *)peripheral Completion:(void(^)(CBPeripheral *peripheral,NSString *connectState))connectedPeripheral;/** 发送数据 @param value 数据 @param peripheral 外设 @param characteristic 特征 */- (void)writeValue:(NSData *)value toPeripheral:(CBPeripheral *)peripheral characteristic:(CBCharacteristic *)characteristic;@end
- HMBluetoothManager.m文件
#import "HMBluetoothManager.h"//蓝牙框架#import <CoreBluetooth/CoreBluetooth.h>#define kDisconnectPeripheralNotification @"kDisconnectPeripheralNotification"const NSString *connectStateSuccess = @"连接成功";const NSString *connectStateRepeat = @"外设已经在连接列表中";const NSString *connectStateFaild = @"连接失败";@interface HMBluetoothManager ()<CBCentralManagerDelegate,CBPeripheralDelegate>@end@implementation HMBluetoothManager//单利类实现+(HMBluetoothManager*)shareInstance{ static HMBluetoothManager *manager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ manager = [[HMBluetoothManager alloc] init]; }); return manager;}- (instancetype)init{ self = [super init]; //初始化数组 self.scanArr = [NSMutableArray array]; self.connectArr = [NSMutableArray array]; return self;}#pragma mark - 检测蓝牙是否可用/** 检测蓝牙是否可用 @param completion 错误表示 可用标签 @return 可用标签 */- (BOOL)isDeviceBluetoothAvaliable:(void(^)(NSError *error,BOOL flag))completion{ NSString * state = nil; BOOL flag = NO; switch ([self.CB_central state]) { case CBCentralManagerStateUnsupported: state = @"系统不支持蓝牙."; break; case CBCentralManagerStateUnauthorized: state = @"手机蓝牙未开启"; break; case CBCentralManagerStatePoweredOff: state = @"Bluetooth is currently powered off."; break; case CBCentralManagerStatePoweredOn: state = @"蓝牙可用"; flag = YES; break; case CBCentralManagerStateUnknown: flag = YES; state = @"未知错误"; break; default: break; } if ([state isEqualToString:@"未知错误"]) { //第一次开启扫描可能会出现未知错误,只需要再次调用扫描即可 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self.CB_central scanForPeripheralsWithServices:nil options:nil]; }); } /**创建error *domain:作用域,表示error报错的位置 * code:错误码 * userInfo:错误描述键值对,key一般使用系统默认NSLocalizedDescriptionKey */ NSError *error = [NSError errorWithDomain:@"HMBluetoothManager" code:-1 userInfo:@{NSLocalizedDescriptionKey:state}]; //回调block,非空判断不要忘记 if (completion) { completion(error,flag); } return flag;}#pragma mark - 1.开始扫描- (void)BeginScanPeripheral:(void(^)(CBPeripheral *peripheral))scanPeripheralUpdate{ //1.创建蓝牙中心 if (!self.CB_central) { //参数是代理 和线程) self.CB_central = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()]; } //2.判断当前设备是否支持蓝牙 //NSAssert:第一个参数condition表示判断条件 第二个参数desc表示描述。当判断条件不成立时程序会崩溃并且打印描述 NSAssert([self isDeviceBluetoothAvaliable:nil], @"手机不支持蓝牙"); self.scanPeripheralUpdate = scanPeripheralUpdate; //3.开始扫描 /** Services:查找指定的外设,不设置表示查找所有的外设 options:查找方式,一般设为nil使用系统默认 */ [self.CB_central scanForPeripheralsWithServices:nil options:nil];}#pragma mark -3.连接外设- (void)connectPeripheral:(CBPeripheral *)peripheral Completion:(void(^)(CBPeripheral *peripheral,NSString *connectState))connectedPeripheral{ self.connectedPeripheral = connectedPeripheral; //如果是已经连接,则直接返回 if (peripheral.state == CBPeripheralStateConnected) { connectedPeripheral(peripheral,connectStateRepeat); } else { [self.CB_central connectPeripheral:peripheral options:nil]; }}#pragma mark -蓝牙中心代理//蓝牙中心有更新状态- (void)centralManagerDidUpdateState:(CBCentralManager *)central{}#pragma mark - 2.扫描到外设//查到外设后,停止扫描,连接设备-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{ //外设相关数据 NSLog(@"%@",advertisementData); //外设唯一标识符 NSLog(@"%@",peripheral.identifier); //外设的名称 NSLog(@"%@",peripheral.name); //与外设的信号强度 NSLog(@"%@",RSSI); self.scanPeripheralUpdate(peripheral); //添加到扫描数组(工具类的封装,不应该在内部处理与自身无关的业务逻辑,所以这里不要连接设备,应该封装连接方法让外部调用) //添加之前做一个重复判断,避免同一外设被多次添加 if (![self.scanArr containsObject:peripheral]) { [self.scanArr addObject:peripheral]; }}#pragma mark - 4.连接外设成功,开始寻找服务//连接外设成功,开始发现服务- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { self.connectedPeripheral(peripheral,connectStateSuccess); //设为当前连接的外设 self.currentPeripheral = peripheral; //添加到已经连接的数组 [self.connectArr addObject:peripheral]; //设置代理 [peripheral setDelegate:self]; //发现服务 [peripheral discoverServices:nil];}//连接外设失败-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{ self.connectedPeripheral(peripheral,connectStateFaild);}//连接断开- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{ //这里应该主动发送通知告知外部 [[NSNotificationCenter defaultCenter] postNotificationName:kDisconnectPeripheralNotification object:nil userInfo:@{@"key":peripheral}]; //断开连接之后,应当从连接列表中移除外设 [self.connectArr removeObject:peripheral]; // We're disconnected, so start scanning again}#pragma mark CBPeripheralDelegate 外设代理#pragma mark- 5.发现服务,搜索特征-(void) peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{ if (error) { NSLog(@"Error discovering services: %@", [error localizedDescription]); return; } int i=0; // for (CBService *s in peripheral.services) { // [self.nServices addObject:s]; // } //遍历服务,发现特征 for (CBService *s in peripheral.services) { NSLog(@"%@",[NSString stringWithFormat:@"%d :服务 UUID: %@(%@)",i,s.UUID.data,s.UUID]); i++; [peripheral discoverCharacteristics:nil forService:s]; }}#pragma mark- 6.已搜索到某个服务的特征Characteristics-(void) peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{ // Deal with errors (if any) if (error) { NSLog(@"Error discovering characteristics: %@", [error localizedDescription]); return; } //从服务中遍历特征 for (CBCharacteristic *c in service.characteristics) { NSLog(@"%@",[NSString stringWithFormat:@"发现特征的服务UUID:%@ 该特征UUID:%@",service.UUID ,c.UUID]); //如果是当前发送数据的UUID,则保存该特征 if ([[c.UUID UUIDString] isEqual:self.UUID]) { self.currentCharacteristic = c; } //开启与特征之间的通知(中心与外设长连接,当特征发送数据过来时,能够及时收到) [peripheral setNotifyValue:YES forCharacteristic:c]; //读取特征服务,一次性 // [peripheral readValueForCharacteristic:c]; }}#pragma mark- 获取外设发来的数据,不论是read和notify,获取数据都是从这个方法中读取。- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{ NSLog(@"外设发送过来的数据:%@",characteristic.value.description );}#pragma mark- 中心读取外设实时数据- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { if (error) { } // Notification has started if (characteristic.isNotifying) { //读取外设数据 [peripheral readValueForCharacteristic:characteristic]; NSLog(@"%@",characteristic.value); } else { // Notification has stopped // so disconnect from the peripheral // NSLog(@"Notification stopped on %@. Disconnecting", characteristic); }}#pragma mark - 7.给特征发送数据//把数据写到哪个外设的哪个特征里面- (void)writeValue:(NSData *)value toPeripheral:(CBPeripheral *)peripheral characteristic:(CBCharacteristic *)characteristic { //写入数据 [peripheral writeValue:value forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];}@end
0 0
- 03-iOS蓝牙架构搭建
- iOS蓝牙架构搭建-2
- ios 蓝牙
- ios 蓝牙
- iOS蓝牙
- iOS 蓝牙
- iOS 蓝牙
- iOS蓝牙
- iOS 蓝牙
- iOS蓝牙
- IOS-蓝牙
- IOS 蓝牙
- Ios蓝牙
- iOS 蓝牙
- iOS 蓝牙
- iOS蓝牙
- iOS 蓝牙
- iOS蓝牙
- C++学习一静态成员与静态成员函数
- 01-iOS蓝牙开发简介
- 02-iOS蓝牙连接流程介绍
- iOS开发之block解析
- 学习TDD(5)--实例2:基于ZooKeeper的服务器注册和探测类[实战ServerDetector]
- 03-iOS蓝牙架构搭建
- android远程服务
- [10]项目实战-PC 端固定布局(10)
- 51871791
- 04-iOS蓝牙传输数据演示
- 05-iOS蓝牙开发总结
- hadoop编程工具类
- HDU 3966 Aragorn's Story (树链剖分)
- 超详细 Ubuntu / Ubuntu Kylin 16.04 + OpenCV 2.4 + CUDA 8.0 + cuDNN 5.0 + Caffe_SSD 安装教程