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更新----");     } }
相關文章
相關標籤/搜索