03-iOS蓝牙架构搭建

来源:互联网 发布:java调用外部http接口 编辑:程序博客网 时间:2024/06/05 08:44

蓝牙架构的搭建

  • 前言:笔者认为,如果只是单纯的传授大家代码怎么敲,那么大家很有可能在实际开发中难以运用。刚好本人曾经参与过多款智能硬件开发的架构搭建,本小节本人就现场带领大家开发出一个通用的蓝牙工具类

    • 既然是工具类,虽然大家以后可以在开发中直接拿去用,但是我的目的是想要传授给大家架构的思想,而不是教大家如何偷懒
    • 为了能够让大家对蓝牙通讯理解的更加的透彻,本人专门买了一个小米手环,并且经过大量的测试,破解了部分小米的蓝牙协议(小米手环蓝牙数据是没有加密的)
      • 只有对技术执着的追求,才能造就更高的品质
  • 目前该工具类由于时间原因,主要是想让大家熟悉蓝牙开发的流程,并没有对更深层次的架构做研究

    • 1.只支持蓝牙与外设一对一连接,一对多未做复杂处理
      • 一般开发中,一对一够用了
    • 2.对API接口的架构没有做深入的探讨研究
      • 关于类的接口设计,将会在下一个课程阶段实用技术项目阶段再给大家重点介绍,目前大家也很难吸收太难的知识点
    • 3.本人将会在后期继续优化我们的框架,并且放入github供全球的iOS开发朋友们使用
      • 中国软件的下一步发展就是要走向国际一流
  • 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
原创粉丝点击