CoreBluetooth.framework(二)
1、通过扫描寻找服务
//允许iOS设备作为客户端从一个蓝牙设备读取数据
self.manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:@{CBCentralManagerOptionShowPowerAlertKey:@(NO)}];
首先扫描外围设备
//从一个蓝牙设备读取数据 开始扫描蓝牙 是否允许中央设备多次收到曾经监听到的设备的消息,这样来监听外围设备联接的信号强度,以决定是否增大广播强度,为YES时会多耗电
[self.manager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:_serviceUUID]] options:@{CBCentralManagerScanOptionAllowDuplicatesKey : [NSNumber numberWithBool:YES]}];
scanForPeripheralsWithServices:方法使用了一个服务数组作为参数,扫描周边地区广播这些服务的外围设备,如果使用Nil作为参数,会扫描所有可用的外围设备,不过这样会很慢。
CBCentralManager这个类有一个委托CBCentralManagerDelegate这个委托可以通知你已发现的外围设备、服务、服务的特性和数值变化。如果你的蓝牙么有打开,会在CBCentralManagerDelegate的centralManagerDidUpdateState方法中收到回调,这个方法也要开始扫描外围设备。
#pragma mark - CBCentralManagerDelegate
/**
*当蓝牙状态改变的时候就会调用这个方法
*/
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
switch (central.state) {
case CBManagerStatePoweredOn:
//正在重置状态 可以使用GCD
case CBManagerStateResetting:
{
dispatch_async(dispatch_get_main_queue(), ^{
if (self.connectState == DoorOpenStateScanning)
[self starScanPeripheral];
});
}
break;
//
case CBManagerStateUnknown:
{
}
break;
default:
{
[self stopConnect];
}
break;
}
}
找到外围设备后,通过CBCentralManagerDelegate的didDiscoverPeripheral:方法可以获取外围设备的详细信息。
2.连接设备
找到外围设备后,下一步就是连接外围设备并发现他提供的服务。
/**
*发现服务
*/
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
//处理业务逻辑
//连接外围设备
[central connectPeripheral:peripheral options:nil];
}
在连接外围设备之前应该先保留之,因为ARC编译器会释放外围设备对象而导致其无法连接。可以加入到一个数组里面来保留。
3.直接获取外围设备
如果你知道外围设备的标识符,可以使用这个方法扫描。这个方法是iOS7加入的。
先把外围设备列表加到数组,保存这个数组,每次扫描设备之前先尝试连接已知外围设备是个好习惯。扫描比较费电,应该避免。拿到外围设备的指针后,就可以直接连接了。
- (NSArray<CBPeripheral *> *)retrievePeripheralsWithIdentifiers:(NSArray<NSUUID *> *)identifiers NS_AVAILABLE(NA, 7_0);
4.发现服务
建立连接的尝试可能成功也可能失败,如果成功就会调用这个委托方法。下一步是发现外围设备提供的服务。
/**
*连接成功之后调用的方法,然后开始扫描
*peripheral 成功 扫描外设中的服务和特征,连接上外围设备的时候回调用这个方法
* NSLog(@">>>连接到名称为(%@)的设备-成功",peripheral.name);
*/
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
self.peripheral = peripheral;
_isConnect = YES;
self.connectState = DoorOpenStateConnected;
//设置的peripheral委托CBPeripheralDelegate
[peripheral setDelegate:self]; //查找服务
//扫描外设Services,成功后会进入方法
[peripheral discoverServices:nil];
}
外围设备提供的服务列表是通过CBPeripheralDelegate一个委托方法通知的,从外围设备的services属性中可以获取服务列表。
#pragma mark - CBPeripheralDelegate
/**
* 扫描外设Services,成功后会进入方法
* 发现外围设备的服务会来到该方法(扫描到服务之后直接添加peripheral的services)
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
if (error)
{
if ([self.delegate respondsToSelector:@selector(openDoorFailed:error:)]) {
[self.delegate openDoorFailed:self.curDoor error:error];
}
[self stopConnect];
return;
}
BOOL bFind = NO;
for (CBService *service in peripheral.services)
{
//发现服务
if ([service.UUID.UUIDString isEqualToString:@"FFF0"])
{
NSLog(@"====%@------%@+++++++",service.UUID.UUIDString,self.peripheral.identifier);
// characteristicUUIDs : 可以指定想要扫描的特征(传nil,扫描所有的特征)
_service = service;
[peripheral discoverCharacteristics:nil forService:service];
bFind = YES;
break;
}
}
if (!bFind) {
[self stopConnect];
if ([self.delegate respondsToSelector:@selector(openDoorFailed:error:)]) {
NSError *error1 = [NSError errorWithDomain:@"openDoorFailed" code:LeEGNotDiscoverServices userInfo:@{NSLocalizedDescriptionKey:@"没有找到指定蓝牙服务"}];
[self.delegate openDoorFailed:self.curDoor error:error1];
}
}
}
5.发现特征
特性:打开/关闭服务或者是读取服务的当前值。(如上)返回已经发现的特性的委托方法。
/**
* 找到了设备的服务然后扫描特征
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(nullable NSError *)error {
NSLog(@"发现外围设备的特征");
for (CBCharacteristic *characteristic in service.characteristics)
{
NSLog(@"====%@------+",characteristic.UUID.UUIDString);
//发现特征
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"FFF1"]]) {
// NSLog(@"监听:%@",characteristic);//监听特征
// 拿到特征,和外围设备进行交互
[self.peripheral setNotifyValue:YES forCharacteristic:characteristic];
self.charWrite = characteristic;
} else if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"FFF4"]]) {
[self.peripheral setNotifyValue:YES forCharacteristic:characteristic];
self.charRead = characteristic;
}
}
if (self.charRead && self.charWrite) {
if (![self need3DES:self.curDoor]) {
[self sendOpenDoorCommand];
} else {
// 拿到特征,和外围设备进行交互 保存写的特征
[self WriteValue:@"BB"];
self.connectState = DoorOpenStateWaitKey;
}
} else {
if ([self.delegate respondsToSelector:@selector(openDoorFailed:error:)]) {
NSError *error1 = [NSError errorWithDomain:@"openDoorFailed" code:LeEGNotDiscoverCharacteristics userInfo:@{NSLocalizedDescriptionKey:@"特征值缺失"}];
[self.delegate openDoorFailed:self.curDoor error:error1];
}
[self stopConnect];
return;
}
}
在下面的方法里面,我们会接收到数据更新或者改变的消息
/**
* 设置通知,数据通知会进入:didUpdateValueForCharacteristic方法
*/
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error {}
数值变化已NSData形式发送过来的。需要根据情况进行转换实际的数据。
6.创建自己的外围设备
CoreBluetooth.framework在iOS7中增加了 CBPeripheralManager 和 CBCentral两个类。