iOS 蓝牙4.0 开发体会

来源:互联网 发布:seo常用的工具 编辑:程序博客网 时间:2024/05/29 04:41
  1. 前言

从刚接触到BLE到开发使用接近一个月了,从项目中学到不少新的东西,了解BLE之前推荐看下
蓝牙官方文档
或者参考
蓝牙官方文档翻译
因为我所要用的是 模式是手机端是中心设备,蓝牙设备是外围设备。所有协议部分中用到了 CBCentralManagerDelegate和CBPeripheralDelegate 。而且是全局 监控蓝牙状态 所以有必要把蓝牙管理类封装出来 ,并制定协议 ,以便把相关蓝牙的协议给抛给自己的代理。
先看BLECentralManager .h部分

extern BOOL IsBlueToothOpen;/** *  设备连接状态 */typedef NS_ENUM(NSInteger, BleManagerState) {    /**     * 未连接     */    BleManagerStateDisconnect = 0,    /**     * 已连接     */    BleManagerStateConnect,};@protocol CentralManagerDelegate;@interface CentralManager : NSObject{    CBPeripheral *_devicePeripheral;    //设备    CBCharacteristic *_deviceCharacteristic;    //设备服务特征 (用来发送指令)    CBCentralManager *_manager; //    NSMutableArray *_deviceArray;}+ (BOOL)isBlueOpen;/** * 设备管理 单利 */+ (CentralManager *)sharedManager;/** *  验证蓝牙是否可用 */- (BOOL)verifyCentralManagerState;/** * 连接状态 */@property (assign, nonatomic) BleManagerState deviceBleState;@property (assign,nonatomic) CBPeripheral *deviceTied;@property CTCallCenter *callCentter;/** * 添加监听 */- (void)addEventListener:(id <CentralManagerDelegate>)listener;/** * 删除监听 */- (void)removeEventListener:(id <CentralManagerDelegate>)listener;/** *  删除所有监听 */- (void)removeAllEventListener;/** * 取消所有蓝牙连接 */- (void)cancelPeripheralConnection;/** * 取消蓝牙搜索 */- (void)stopManagerScan;//***************************//****设备//***************************/** * 搜索设备 */- (void)searchDeviceModule;/** *  连接设备 * *  @param peripheral 设备 */- (void)connectDevicePeripheralWithPeripheral:(CBPeripheral *)peripheral;/** *  开始扫描服务 * *  @param peripheral 设备 */- (void)startdiscoverSerVices:(CBPeripheral*)peripheral WithUUID:(NSArray<CBUUID*>*)aryUUID;- (void)startdiscoverSerVices:(CBPeripheral*)peripheral;@end@protocol CentralManagerDelegate <NSObject>@optional/** *  蓝牙未开启 或 不可用 */- (void)centralManagerStatePoweredOff;//***************************//****设备//***************************/** *  发现设备 */- (void)didDiscoverDevicePeripheral:(CBPeripheral *)peripheral devices:(NSMutableArray *)deviceArray;  //发现设备/** *  开始连接 */- (void)didStartConnectDevicePeripheral;/** *  断开连接 */- (void)didCancelDevicePeripheralConnection;/** *  发现的特征值 */- (void)didDiscoverDevicePeripheral:(CBPeripheral *)peripheral service:(CBService *)service;/** *  连接成功 */- (void)didConnectDevicePeripheral:(CBPeripheral *)peripheral;/** *  连接失败 */- (void)didFailToConnectDevicePeripheral:(CBPeripheral *)peripheral;/** *  断开连接 */- (void)didDisconnectDevicePeripheral:(CBPeripheral *)peripheral;/** *  连接超时 */- (void)didConnectionDeviceTimeOut;- (void)didDiscoverCharacteristicsForperipheral:(CBPeripheral *)peripheral Service:(CBService *)service error:(NSError *)error;/** *  接收到数据 */- (void)didUpdateDeviceValueForCharacteristic:(CBCharacteristic *)characteristic ; // deviceData:(NSData *)deviceData;/** *  如果一个特征的值被更新,然后周边代理接收 * *  @param characteristic  */- (void)didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic;

.m 部分

BOOL IsBlueToothOpen = NO;@interface CentralManager ()<CBCentralManagerDelegate, CBPeripheralDelegate,CentralManagerDelegate>{//    short ecgNum[500];//    unsigned char hr;}@end@implementation CentralManager{    NSMutableArray *_listener;  //观察者           //设备数组}#pragma mark - 单例+ (CentralManager *)sharedManager {    static CentralManager *sharedManager = nil;    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{        sharedManager = [[self alloc] init];    });    return sharedManager;}- (instancetype)init {    if (self = [super init]) {        [self customInit];    }    return self;}- (void)customInit {    _listener = [NSMutableArray array];    _deviceArray = [NSMutableArray array];    _deviceBleState = BleManagerStateDisconnect;    //建立中心角色    _manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];    }//添加监听- (void)addEventListener:(id <CentralManagerDelegate>)listener {    [_listener addObject:listener];}//删除监听- (void)removeEventListener:(id <CentralManagerDelegate>)listener {    [_listener removeObject:listener];}/** *  删除所有监听 */- (void)removeAllEventListener {    [_listener removeAllObjects];}/** *  取消所有蓝牙连接 */- (void)cancelPeripheralConnection {    if (self.deviceTied) {        [_manager cancelPeripheralConnection:self.deviceTied];        self.deviceTied = nil;    }    _deviceBleState = BleManagerStateDisconnect;    [self stopManagerScan];    for (id listener in _listener) {        if ([listener respondsToSelector:@selector(didCancelDevicePeripheralConnection)]) {            [listener didCancelDevicePeripheralConnection];        }    }}/** *  取消蓝牙搜索 */- (void)stopManagerScan {    if (_manager) {        [_manager stopScan];    }}+ (BOOL)isBlueOpen{    return IsBlueToothOpen;}- (void)centralManagerDidUpdateState:(CBCentralManager *)central {    NSString *stateStr;    switch (central.state) {        case CBCentralManagerStateUnknown :            IsBlueToothOpen = NO;            stateStr = @"当前蓝牙状态未知,请重试";            break;        case CBCentralManagerStateUnsupported:            IsBlueToothOpen = NO;            stateStr = @"当前设备不支持蓝牙设备连接";            break;        case CBCentralManagerStateUnauthorized:            IsBlueToothOpen = NO;            stateStr = @"请前往设置开启蓝牙授权并重试";            break;        case CBCentralManagerStatePoweredOff:            IsBlueToothOpen = NO;            stateStr = @"蓝牙关闭,请开启";            break;        case CBCentralManagerStateResetting:            IsBlueToothOpen = NO;            break;        case CBCentralManagerStatePoweredOn:        {            IsBlueToothOpen = YES;            stateStr = @"正常";            //扫描外设(discover)            DDLog(@"扫描外设");//            NSDictionary *options = @{CBCentralManagerScanOptionAllowDuplicatesKey : [NSNumber numberWithBool:YES]};            //开始扫描设备            [self searchDeviceModule];//            [_manager scanForPeripheralsWithServices:nil options:nil];        }            break;        default:            stateStr = [NSString stringWithFormat:@"蓝牙异常 %d",(int)central.state];            break;    }}/** *  验证蓝牙是否可用 */- (BOOL)verifyCentralManagerState {    if (_manager.state != CBCentralManagerStatePoweredOn) {        for (id listener in _listener) {            if ([listener respondsToSelector:@selector(centralManagerStatePoweredOff)]) {                [listener centralManagerStatePoweredOff];            }        }        return NO;    }    return YES;}//***************************//****设备//***************************//搜索设备- (void)searchDeviceModule {//    if (![self verifyCentralManagerState]) {//        return;//    }    DDLog(@"搜索设备");    [_manager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey:[NSNumber numberWithBool:NO]}];    //}//连接蓝牙设备- (void)connectDevicePeripheralWithPeripheral:(CBPeripheral *)peripheral {    if (![self verifyCentralManagerState]) {        return;    }    if (peripheral == nil) {        return;    }    self.deviceTied = peripheral;    [_manager connectPeripheral:peripheral options:@{ CBConnectPeripheralOptionNotifyOnConnectionKey : @YES}];}#pragma mark - *******************/** *  这里开始蓝牙的代理方法 */#pragma mark - >> 发现蓝牙设备- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI {    if (!peripheral.name) {        return;    }    NearbyPeripheralInfo *infoModel = [[NearbyPeripheralInfo alloc] init];    infoModel.peripheral = peripheral;    infoModel.advertisementData = advertisementData;    infoModel.RSSI = RSSI;    //设备    DDLog(@"蓝牙管理者 发现设备Device:%@, %.2f", peripheral.name, RSSI.floatValue);    if (_deviceArray.count == 0) {        [_deviceArray addObject:infoModel];    }else {        BOOL isExist = NO;        for (int i = 0; i < _deviceArray.count; i++) {            NearbyPeripheralInfo *model = _deviceArray[i];            if ([model.peripheral isEqual:peripheral]) {                isExist = YES;                _deviceArray[i] = infoModel;            }        }        if (!isExist) {            [_deviceArray addObject:infoModel];        }    }    for (id listener in _listener) {        if ([listener respondsToSelector:@selector(didDiscoverDevicePeripheral:devices:)]) {            [listener didDiscoverDevicePeripheral:peripheral devices:_deviceArray];        }    }}#pragma mark - >> 连接成功- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {    NSLog(@"连接成功:%@", peripheral.name);    AppDelegate *myDelegate = [[UIApplication sharedApplication]delegate];    myDelegate.devicesTied = peripheral;    [self stopManagerScan];   //停止扫描设备       _deviceBleState = BleManagerStateConnect;    self.deviceTied = peripheral;    for (id listener in _listener) {        if ([listener respondsToSelector:@selector(didConnectDevicePeripheral:)]) {            [listener didConnectDevicePeripheral:peripheral];                    }    }    //因为在后面我们要从外设蓝牙那边再获取一些信息,并与之通讯,这些过程会有一些事件可能要处理,所以要给这个外设设置代理    peripheral.delegate = self;    //找到该设备上的指定服务 调用完该方法后会调用代理CBPeripheralDelegate(现在开始调用另一个代理的方法了)//    [peripheral discoverServices:nil];}- (void)startdiscoverSerVices:(CBPeripheral *)peripheral WithUUID:(NSArray<CBUUID *> *)aryUUID{    [peripheral discoverServices:aryUUID];}- (void)startdiscoverSerVices:(CBPeripheral*)peripheral{//    [peripheral discoverServices:nil];}#pragma mark - >> 连接失败- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {    _deviceBleState = BleManagerStateDisconnect;    for (id listener in _listener) {        if ([listener respondsToSelector:@selector(didFailToConnectDevicePeripheral:)]) {            [listener didFailToConnectDevicePeripheral:peripheral];        }    }    NSLog(@"连接失败:%@", peripheral.name);}#pragma mark - >> 断开连接- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {    NSLog(@"断开连接:%@", peripheral.name);    for (id listener in _listener) {        if ([listener respondsToSelector:@selector(didDisconnectDevicePeripheral:)]) {            [listener didDisconnectDevicePeripheral:peripheral];        }    }    // 重连//    [self connectDevicePeripheralWithPeripheral:peripheral];}#pragma mark - >> CBPeripheralDelegate#pragma mark - >> 发现服务- (void)peripheral:(CBPeripheral *)peripheraldidDiscoverServices:(NSError *)error{    if (error) {        DDLog(@"  发现服务时发生错误: %@",error);        return;    }    NSLog(@" 发现服务 ..");    for (CBService *service in peripheral.services) {        [peripheral discoverCharacteristics:nil forService:service];    }}//- (void)didDiscoverCharacteristicsForServiceperipheral:(CBPeripheral *)peripheral :(CBService *)service error:(NSError *)error;#pragma mark - >> 发现特征值- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{    DDLog(@" 蓝牙管理页面 》》》》》 发现服务 %@, 特性数: %ld", service.UUID, [service.characteristics count]);//    for (id listener in _listener) {//        if ([listener respondsToSelector:@selector(didDiscoverCharacteristicsForperipheral:Service:error:)]) {//            [listener didDiscoverCharacteristicsForperipheral:peripheral Service:service error:error];//        }//    }    for (CBCharacteristic *c in service.characteristics) {//        [peripheral readValueForCharacteristic:c]; 这句话千万不要写,会出错        //在这里 打开蓝牙外设的某些功能的notify通道        DDLog(@" 蓝牙管理页面特征UUID:%@", [c.UUID UUIDString]);        if([[c.UUID UUIDString] isEqualToString:HEART_READ_UUID])        {            [peripheral setNotifyValue:YES forCharacteristic:c];        }        NSLog(@"特性值: %@",c.UUID);    }}#pragma mark - >> 如果一个特征的值被更新,然后周边代理接收- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{    DDLog(@"蓝牙管理页面 》》》》》 update Notification");    for (id listener in _listener) {        if ([listener respondsToSelector:@selector(didUpdateNotificationStateForCharacteristic:)]) {            [listener didUpdateNotificationStateForCharacteristic:characteristic];        }    }}#pragma mark - >> 读数据-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{    for (id listener in _listener) {        if ([listener respondsToSelector:@selector(didUpdateDeviceValueForCharacteristic:)]) {            [listener didUpdateDeviceValueForCharacteristic:characteristic];        }    }}- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {    DDLog(@"did write value For Characteristic");    DDLog(@"value:%@ error:%@", characteristic.value,error);}- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error {    DDLog(@"did Write Value For Descriptor");}

2、具体的步骤
1)、先连接外设

[self connectDevicePeripheralWithPeripheral:peripheral];

连接成功后会响应CBCentralManagerDelegate的方法

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;

2)、扫描外设中的服务

 [peripheral discoverServices:nil];

或者

[peripheral discoverServices:aryUUID];//扫描指定的服务

之后便会调用CBPeripheralDelegate 的代理
方法 :已经发现服务

- (void)peripheral:(CBPeripheral *)peripheraldidDiscoverServices:(NSError *)error;

在 这里调用

[peripheral discoverCharacteristics:nil forService:service];

发现服务中的特征值
找到特征值之后便会调用CBPeripheralDelegate 的代理的
方法:已经发现特征值

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error;

在这里 打开通道

[peripheral setNotifyValue:YES forCharacteristic:c];

这个时候就可以进行对外设的写入操作:

+ (void)writeToperipheral:(CBPeripheral *)peripheral Service:(NSString *)serviceUUID characteristic:(NSString *)characteristicUUID data:(NSData *)data{    CBUUID *servUUID = [CBUUID UUIDWithString:serviceUUID];    CBUUID *charUUID = [CBUUID UUIDWithString:characteristicUUID];    CBService *service = nil;    CBCharacteristic *characteristic = nil;    for (CBService *ser in peripheral.services) {        if ([ser.UUID isEqual:servUUID]) {            service = ser;            break;        }    }    if (service) {        for (CBCharacteristic *charac in service.characteristics) {            if ([charac.UUID isEqual:charUUID]) {                characteristic = charac;                break;            }        }    }    if (characteristic) {        [peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];    }    else{        NSLog(@"not found that characteristic");    }}

当外设中的数据发生变化 也就是写入值以后会触发CBPeripheralDelegate 的代理的方法:

#pragma mark - >> 如果一个特征的值被更新,然后周边代理接收- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;

若有数据从蓝牙中广播的时候
触发

#pragma mark - >> 读数据-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;

3、这个是本人的一点心得体会,新手刚接触有关蓝牙4.0的开发,若有哪些言论有误,还请各路大神不吝赐教,谢谢。

                                                By:帅哥
0 0