iOS藍芽4.0協議簡單介紹

來源:互聯網
上載者:User

標籤:

iOS開發藍芽4.0的架構是CoreBluetooth,本文主要介紹CoreBluetooth的使用,關於本文中的程式碼片段大多來自github上的一個demo,地址是myz1104/Bluetooth。
在CoreBluetooth中有兩個主要的部分,Central和Peripheral,有一點類似Client Server。CBPeripheralManager 作為周邊裝置是伺服器。CBCentralManager作為中心裝置是用戶端。所有可用的iOS裝置可以作為周邊(Peripheral)也可以作為中央(Central),但不可以同時既是周邊也是中央。

一般手機是用戶端, 裝置(比如手環)是伺服器,因為是手機去串連手環這個伺服器。周邊(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的實現之前,我們添加以下的代碼:

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方法。這個時候就可以開始廣播我們剛剛建立的服務了。

- (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方法可以給中央產生動態資料的地方。

- (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走一遍下面的代理方法

- (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更新----");    }}

這樣,中央裝置也實現了讀寫資料的功能了。

另外,github上有一個封裝的第三方開源藍芽架構,地址是kickingvegas/YmsCoreBluetooth

iOS藍芽4.0協議簡單介紹

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.