iOS封装蓝牙中心管理者类

承接上文iOS蓝牙中心端开发

目前github上有很多封装的iOS蓝牙库,稍微改改就可以拿来直接使用,不必在控制器中实现那一套的<CBCentralManagerDelegate><CBPeripheralDelegate>协议中的方法。
本篇文章记一下我是如何一步步进行封装蓝牙中心管理者类的,也让看客能够很快上手,自己封装一个,毕竟自己写的代码改起来顺手。

1、了解其他封装
2、我的封装

1、了解其他封装

我根据封装的库中对数据的处理方式,把库简单地分为三级:

第一级:CJBlueTooth这种,就是简单的封装了个中心管理类,把两个协议的方法实现了,还加上了SVProgressHUD。
数据处理方面,在didUpdateValueForCharacteristic方法中用的属性。把外设发送的数据存为属性,然后在使用蓝牙的控制器中用一个dispatch_after访问属性拿到数据。

第二级: ALBLEFramework这种,在第一级的基础上,加了协议,设置了代理。
数据处理方面,在didUpdateValueForCharacteristic方法中用的代理。让使用蓝牙的控制器成为代理,实现协议中的方法来拿到外设发送的数据。

第三级:BabyBluetooth这种,在第一级的基础上,把代理方法中各值用block传了出去,还可以使用链式语法,很直观。
数据处理方面,在didUpdateValueForCharacteristic方法中是用的通知以及block。

BabyBluetooth这个库在github上是star最多的库,但我并没有用,除非你真的很赶时间,可以直接拿来用。
因为在我从零开始做蓝牙的时候,原生的代理方法虽然繁琐,但一系列方法反而比较易懂,建议刚开始做蓝牙的小伙伴先把原生的各个方法搞明白,在实现功能的基础上,有时间了再去研究这个库,模仿封装一个。
而我自己是封装第二级的这种,我认为已经够用了,对于一个APP来说,没必要像第三级那样。


2、我的封装
第一步:新建一个NSObject类,实现<CBCentralManagerDelegate><CBPeripheralDelegate>协议中的方法

1、新建一个NSObject类,我起的名字是OSZBLECenterManager
2、引入框架#import <CoreBluetooth/CoreBluetooth.h>
3、遵循协议@interface OSZBLECenterManager : NSObject<CBCentralManagerDelegate, CBPeripheralDelegate>
4、设置属性。主要是保存外设和特征。
5、暴露方法。比如初始化,开始连接,写入数据等需要在控制器中使用的方法。

第二步:创建协议,设置代理

创建一个协议,主要包括在实现<CBCentralManagerDelegate><CBPeripheralDelegate>协议中的方法时外面控制器要实现的方法。

肯定要有更新控制器UI的方法,例如等待指示器的显示与消失。
肯定还要包括一个把数据传给外面控制器的方法。
因为在监听外设发送数据的时候,需要把数据实时传给外面的控制器,而不是让外面的控制器主动访问外设传了哪些数据,这点很重要。

也可以使用通知和block,通知还需要移除,block稍微有些麻烦,我这里就是简单的用下代理,不想用代理也可以。

OSZBLECenterManager.h

#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>

@protocol OSZBLECenterManagerDelegate <NSObject>

@optional
//点击连接按钮
- (void)didClickStart;
//连接成功
- (void)BLEConnectSucceed;
//收到的数据
- (void)receivedValue:(NSData *)data;

@end

@interface OSZBLECenterManager : NSObject<CBCentralManagerDelegate, CBPeripheralDelegate>
//代理
@property (nonatomic, weak) id<OSZBLECenterManagerDelegate> delegate;
//中心
@property (nonatomic,strong) CBCentralManager *centralManager;
//外设
@property (nonatomic,strong) CBPeripheral *peripheral;
//特征
@property (nonatomic, strong) CBCharacteristic *characteristic;

//初始化
+ (instancetype)sharedInstance;
//开始连接
- (void)startConnect;
//断开连接
- (void)endConnect;
//读数据
- (void)readFromPeripheral;
//写数据
- (void)writeToPeripheralWith:(NSString *)name;
//监听数据
- (void)notifyPeripheral;

@end

OSZBLECenterManager.m

#import "OSZBLECenterManager.h"
@implementation OSZBLECenterManager

+ (instancetype)sharedInstance
{
    static OSZBLECenterManager *manager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[OSZBLECenterManager alloc]init];
    });
    return manager;
}


- (void)startConnect
{
    if (self.delegate && [self.delegate respondsToSelector:@selector(didClickStart)])
    {
        //控制器更新UI
        [self.delegate didClickStart];
    }
    
    //初始化中心端,开始蓝牙模块
    self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
    self.centralManager.delegate = self;
}

//断开连接
- (void)endConnect
{
    [self.centralManager cancelPeripheralConnection:self.peripheral];
}


#pragma mark - CBCentralManagerDelegate
// 状态更新后触发
-(void)centralManagerDidUpdateState:(CBCentralManager *)central
{
    switch (central.state) {
        case CBCentralManagerStatePoweredOff:
            break;
        case CBCentralManagerStatePoweredOn:
            break;
        case CBCentralManagerStateResetting:
            break;
        case CBCentralManagerStateUnauthorized:
            break;
        case CBCentralManagerStateUnknown:
            break;
        case CBCentralManagerStateUnsupported:
            break;
        default:
            break;
    }
    [central scanForPeripheralsWithServices:nil options:nil];
}


// 扫描到外部设备后触发的代理方法//多次调用的
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(nonnull CBPeripheral *)peripheral advertisementData:(nonnull NSDictionary<NSString *,id> *)advertisementData RSSI:(nonnull NSNumber *)RSSI
{
    //    扫描到的外部设备
    NSString *msg = [NSString stringWithFormat:@"信号强度: %@, 外设: %@", RSSI, peripheral];
    NSLog(@"%@",msg);
    if ([peripheral.name isEqualToString:@"CSR Serial Server"])
    {
        //连接外部设备
        self.peripheral = peripheral;
        [central connectPeripheral:peripheral options:nil];
        //停止搜索
        [central stopScan];
    }
}


//连接失败
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    NSLog(@"%@",error.localizedDescription);
    [self.centralManager connectPeripheral:self.peripheral options:nil];
}


// 当中心端连接上外设时触发
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
    NSLog(@"连接上外设");
    self.peripheral.delegate = self;
    [peripheral discoverServices:nil];
}


//如果连接上的两个设备突然断开了,程序里面会自动回调下面的方法
-   (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    NSLog(@"设备断开重连");
    [self.centralManager connectPeripheral:self.peripheral options:nil];
    //当断开时做缺省数据处理
}


#pragma mark - CBPeripheralDelegate
// 外设端发现了服务时触发
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
    NSLog(@"%@",peripheral.services);
    if (error)
    {
        NSLog(@"%@",error.localizedDescription);
        return;
    }
    for (CBService *service in peripheral.services)
    {
        //只找有用的服务
        if ([service.UUID.description isEqualToString:@"服务UUID名称"])
        {
            [peripheral discoverCharacteristics:nil forService:service];
        }
    }
}


//从服务获取特征
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
    NSLog(@"%@",service.characteristics);
    for (CBCharacteristic *characteristic in service.characteristics)
    {
        // -------- 读特征的处理 --------
        if ([characteristic.UUID.description isEqualToString: @"读特征名称"])
        {
            NSLog(@"处理读特征");
            [self.peripheral readValueForCharacteristic:characteristic];
        }
        
        // -------- 写特征的处理 --------
        if ([characteristic.UUID.description isEqualToString: @"写特征名称"])
        {
            NSLog(@"处理写特征");
            //向外设发送0001命令
            NSData *data = [@"0001" dataUsingEncoding:NSUTF8StringEncoding];
            [self.peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
            self.characteristic = characteristic;
        }
        
        // -------- 订阅特征的处理 --------
        if ([characteristic.UUID.description isEqualToString: @"订阅特征名称"])
        {
            NSLog(@"处理了订阅特征");
            [peripheral setNotifyValue:YES forCharacteristic:characteristic];
        }
    }
}


//收到数据
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
//    NSLog(@"%@",characteristic.value);
    //控制器去处理
    if (self.delegate && [self.delegate respondsToSelector:@selector(receivedValue:)])
    {
        [self.delegate receivedValue:characteristic.value.copy];
    }
    
}


// 写特征CBCharacteristicWriteWithResponse的数据写入的结果回调
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
    if (error) {
        NSLog(@"数据写入失败: %@", error);
    } else {
        NSLog(@"数据写入成功");
        [peripheral readValueForCharacteristic:characteristic];
    }
}

#pragma mark - VCMethod 
//读数据
- (void)readFromPeripheral
{
    NSLog(@"读数据");
    [self.peripheral readValueForCharacteristic:self.characteristic];
}

//写数据
- (void)writeToPeripheralWith:(NSString *)instruct
{
    NSLog(@"写数据");
    NSData *data = [[OSZDataTool sharedTool] hexToBytes:instruct];
    [self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithoutResponse];
}

//监听数据
- (void)notifyPeripheral
{
    NSLog(@"监听数据");
    [self.peripheral setNotifyValue:YES forCharacteristic:self.characteristic];
}

第三步:在控制器中实现

然后在要使用蓝牙的控制器中,设置属性强引用@property (nonatomic, strong) OSZBLECenterManager *manager;
遵循协议<OSZBLECenterManagerDelegate>
在你想要启动蓝牙的方法里加入以下代码(比如“连接外设”按钮),启动蓝牙中心管理类,并设置代理,然后实现代理方法就可以了。

OSZBLECenterManager *manager = [OSZBLECenterManager sharedInstance];
manager.delegate = self;
self.manager = manager;
[manager startConnect];

可以看到我封装的很简单,但主要的功能都有。主要是为了方便理解,可以自行扩展功能。
如果有帮助到你,给个喜欢吧:-D


2018.6.25
这个是我用的数据转化工具类,可能并不是最好的,如果使用中有什么问题请留言给我改进,thanks
OSZDataTool下载地址:https://github.com/oldSixZhu/OSZDataTool

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,165评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,503评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,295评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,589评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,439评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,342评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,749评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,397评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,700评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,740评论 2 313
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,523评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,364评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,755评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,024评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,297评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,721评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,918评论 2 336

推荐阅读更多精彩内容