iOS 蓝牙4.0 开发体会

15 篇文章 0 订阅
2 篇文章 0 订阅
  1. 前言
    Info中添加 Privacy - Bluetooth Peripheral Usage Description
    从刚接触到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 *)peripheral
didDiscoverServices:(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 *)peripheral
didDiscoverServices:(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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值