iOS蓝牙4.0协议简单介绍

iOS开发蓝牙4.0的框架是CoreBluetooth,本文主要介绍CoreBluetooth的使用,关于本文中的代码片断大多来自github上的一个demo,地址是myz1104/Bluetooth
git

在CoreBluetooth中有两个主要的部分,Central和Peripheral,有一点相似Client Server。CBPeripheralManager 做为周边设备是服务器。CBCentralManager做为中心设备是客户端。全部可用的iOS设备能够做为周边(Peripheral)也能够做为中央(Central),但不能够同时既是周边也是中央。
github

通常手机是客户端, 设备(好比手环)是服务器,由于是手机去链接手环这个服务器。周边(Peripheral)是生成或者保存了数据的设备,中央(Central)是使用这些数据的设备。你能够认为周边是一个广播数据的设备,他广播到外部世界说他这儿有数据,而且也说明了能提供的服务。另外一边,中央开始扫描附近有没有服务,若是中央发现了想要的服务,而后中央就会请求链接周边,一旦链接创建成功,两个设备之间就开始交换传输数据了。
除了中央和周边,咱们还要考虑他俩交换的数据结构。这些数据在服务中被结构化,每一个服务由不一样的特征(Characteristics)组成,特征是包含一个单一逻辑值的属性类型。数组

Peripheral的实现步骤

首先是建立一个周边服务器

_peripheralManager = [[CBPeripheralManager alloc]initWithDelegate:self queue:nil];

接下来它就会响应代理的peripheralManagerDidUpdateState方法,能够得到peripheral的状态等信息,数据结构

- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {     switch (peripheral.state)     {         case CBPeripheralManagerStatePoweredOn:         {             [self setupService];         }             break;                      default:         {             NSLog(@"Peripheral Manager did change state");         }             break;     } }

当发现周边设备的蓝牙是能够的时候,这就须要去准备你须要广播给其余中央设备的服务和特征了,这里经过调用setupService方法来实现。
每个服务和特征都须要用一个UUID(unique identifier)去标识,UUID是一个16bit或者128bit的值。若是你要建立你的中央-周边App,你须要建立你本身的128bit的UUID。你必需要肯定你本身的UUID不能和其余已经存在的服务冲突。若是你正要建立一个本身的设备,须要实现标准委员会需求的UUID;若是你只是建立一个中央-周边App,我建议你打开Mac OS X的Terminal.app,用uuidgen命令生成一个128bit的UUID。你应该用该命令两次,生成两个UUID,一个是给服务用的,一个是给特征用的。而后,你须要添加他们到中央和周边App中。如今,在view controller的实现以前,咱们添加如下的代码:app

static NSString * const kServiceUUID = @"1C85D7B7-17FA-4362-82CF-85DD0B76A9A5"; static NSString * const kCharacteristicUUID = @"7E887E40-95DE-40D6-9AA0-36EDE2BAE253";

下面就是setupService方法框架

- (void)setupService {     CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID];          self.customCharacteristic = [[CBMutableCharacteristic alloc] initWithType:characteristicUUID properties:CBCharacteristicPropertyNotify value:nil permissions:CBAttributePermissionsReadable];          CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID];          self.customService = [[CBMutableService alloc] initWithType:serviceUUID primary:YES];     [self.customService setCharacteristics:@[self.customCharacteristic]];     [self.peripheralManager addService:self.customService];          }

当调用了CBPeripheralManager的addService方法后,这里就会响应CBPeripheralManagerDelegate的- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error方法。这个时候就能够开始广播咱们刚刚建立的服务了。ide

- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error {     if (error == nil)     {         [self.peripheralManager startAdvertising:@{ CBAdvertisementDataLocalNameKey : @"ICServer", CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:kServiceUUID]] }];     } }

固然到这里,你已经作完了peripheralManager的工做了,中央设备已经能够接受到你的服务了。不过这是静止的数据,你还能够调用- (BOOL)updateValue:(NSData *)value forCharacteristic:(CBMutableCharacteristic *)characteristic onSubscribedCentrals:(NSArray *)centrals方法能够给中央生成动态数据的地方。ui

- (void)sendToSubscribers:(NSData *)data {   if (self.peripheral.state != CBPeripheralManagerStatePoweredOn) {     LXCBLog(@"sendToSubscribers: peripheral not ready for sending state: %d", self.peripheral.state);     return;   }   BOOL success = [self.peripheral updateValue:data                             forCharacteristic:self.characteristic                          onSubscribedCentrals:nil];   if (!success) {     LXCBLog(@"Failed to send data, buffering data for retry once ready.");     self.pendingData = data;     return;   } }

central订阅了characteristic的值,当更新值的时候peripheral会调用updateValue: forCharacteristic: onSubscribedCentrals:(NSArray*)centrals去为数组里面的centrals更新对应characteristic的值,在更新事后peripheral为每个central走一遍下面的代理方法spa

- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic

peripheral接受到一个读或者写的请求时,会响应如下两个代理方法

- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request - (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests

那么如今peripheral就已经建立好了。

建立一个中央

建立中央而且链接周边
如今,咱们已经有了一个周边,让咱们建立咱们的中央。中央就是那个处理周边发送来的数据的设备。

self.manager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];

当Central Manager被初始化,咱们要检查它的状态,以检查运行这个App的设备是否是支持BLE。实现CBCentralManagerDelegate的代理方法:

- (void)centralManagerDidUpdateState:(CBCentralManager *)central {     switch (central.state)     {         case CBCentralManagerStatePoweredOn:         {             [self.manager scanForPeripheralsWithServices:@[ [CBUUID UUIDWithString:kServiceUUID]]                                                  options:@{CBCentralManagerScanOptionAllowDuplicatesKey : @YES }];         }             break;         default:         {             NSLog(@"Central Manager did change state");         }             break;     } }

当app的设备是支持蓝牙的时候,须要调用CBCentralManager实例的- (void)scanForPeripheralsWithServices:(NSArray *)serviceUUIDs options:(NSDictionary *)options方法,用来寻找一个指定的服务的peripheral。一旦一个周边在寻找的时候被发现,中央的代理会收到如下回调:

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {          NSString *UUID = [peripheral.identifier UUIDString];     NSString *UUID1 = CFBridgingRelease(CFUUIDCreateString(NULL, peripheral.UUID));     NSLog(@"----发现外设----%@%@", UUID,UUID1);     [self.manager stopScan];          if (self.peripheral != peripheral)     {         self.peripheral = peripheral;         NSLog(@"Connecting to peripheral %@", peripheral);         [self.manager connectPeripheral:peripheral options:nil];     } }

这个时候一个附带着广播数据和信号质量(RSSI-Received Signal Strength Indicator)的周边被发现。这是一个很酷的参数,知道了信号质量,你能够用它去判断远近。任何广播、扫描的响应数据保存在advertisementData 中,能够经过CBAdvertisementData 来访问它。
这个时候你用能够链接这个周边设备了,

[self.manager connectPeripheral:peripheral options:nil];

它会响应下面的代理方法,

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {     NSLog(@"----成功链接外设----");     [self.peripheral setDelegate:self];     [self.peripheral discoverServices:@[ [CBUUID UUIDWithString:kServiceUUID]]]; }

访问周边的服务
上面的CBCentralManagerDelegate代理会返回CBPeripheral实例,它的- (void)discoverServices:(NSArray *)serviceUUIDs方法就是访问周边的服务了,这个方法会响应CBPeripheralDelegate的方法。

- (void)peripheral:(CBPeripheral *)aPeripheral didDiscoverServices:(NSError *)error {     NSLog(@"----didDiscoverServices----Error:%@",error);     if (error)     {         NSLog(@"Error discovering service: %@", [error localizedDescription]);         [self cleanup];         return;     }          for (CBService *service in aPeripheral.services)     {         NSLog(@"Service found with UUID: %@", service.UUID);         if ([service.UUID isEqual:[CBUUID UUIDWithString:kServiceUUID]])         {             [self.peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:kCharacteristicUUID],[CBUUID UUIDWithString:kWrriteCharacteristicUUID]] forService:service];         }     } }

在上面的方法中若是没有error,能够调用discoverCharacteristics方法请求周边去寻找它的服务所列出的特征,它会响应下面的方法

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {     if (error)     {         NSLog(@"Error discovering characteristic: %@", [error localizedDescription]);         return;     }     if ([service.UUID isEqual:[CBUUID UUIDWithString:kServiceUUID]])     {         for (CBCharacteristic *characteristic in service.characteristics)         {             NSLog(@"----didDiscoverCharacteristicsForService---%@",characteristic);             if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kCharacteristicUUID]])             {                 [peripheral readValueForCharacteristic:characteristic];                 [peripheral setNotifyValue:YES forCharacteristic:characteristic];             }                          if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kWrriteCharacteristicUUID]])             {                 writeCharacteristic = characteristic;             }                      }     } }

这个时候peripheral能够调用两个方法,
[peripheral readValueForCharacteristic:characteristic]这个是读特征值的,会响应- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;

[peripheral setNotifyValue:YES forCharacteristic:characteristic];会响应- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;

- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {     if (error)     {         NSLog(@"Error changing notification state: %@", error.localizedDescription);     }          // Exits if it's not the transfer characteristic     if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kCharacteristicUUID]] )     {         // Notification has started         if (characteristic.isNotifying)         {             NSLog(@"Notification began on %@", characteristic);             [peripheral readValueForCharacteristic:characteristic];         }         else         { // Notification has stopped             // so disconnect from the peripheral             NSLog(@"Notification stopped on %@.  Disconnecting", characteristic);             [self.manager cancelPeripheralConnection:self.peripheral];         }     } } - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {     NSLog(@"----Value---%@",characteristic.value);     if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kCharacteristicUUID]])     {         if (writeCharacteristic)         {             Byte ACkValue[3] = {0};             ACkValue[0] = 0xe0; ACkValue[1] = 0x00; ACkValue[2] = ACkValue[0] + ACkValue[1];             NSData *data = [NSData dataWithBytes:&ACkValue length:sizeof(ACkValue)];             [self.peripheral writeValue:data                       forCharacteristic:writeCharacteristic                                    type:CBCharacteristicWriteWithoutResponse];         }     } }

在上面的方法中,- (void)writeValue:(NSData *)data forCharacteristic:(CBCharacteristic *)characteristic type:(CBCharacteristicWriteType)type是一个对周边设备写数据的方法,它会响应下面的方法

- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {     NSLog(@"---didWriteValueForCharacteristic-----");     if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kWrriteCharacteristicUUID]])     {         NSLog(@"----value更新----");     } }
相关文章
相关标签/搜索