藍(lán)牙(CoreBluetooth)-中心設(shè)備(客戶端)

藍(lán)牙客戶端-中心設(shè)備

主要內(nèi)容

1. 創(chuàng)建`中央管理器`
2. 發(fā)現(xiàn)并且連接外設(shè)
3. 尋找連接上的外設(shè)數(shù)據(jù)
4. 發(fā)送讀或?qū)慲特征值`的請(qǐng)求
5. 訂閱外設(shè)特征值

1. 創(chuàng)建中心管理器

因?yàn)?code>CBCentralManager代表著本地中央設(shè)備,所以你必須先創(chuàng)建一個(gè)中央管理器對(duì)象,通過(guò)CBCentralManagerinitWithDelegate:queue:options: 如:

myCentralManager =
        [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil];```
在上面的例子中,self設(shè)置為中央管理器的代理,它將接收來(lái)自`中央管理器`的事件回調(diào),queue設(shè)置為nil,表示為主隊(duì)列.當(dāng)你創(chuàng)建一個(gè)中心管理器時(shí),就會(huì)調(diào)用它代理的`centralManagerDidUpdateState:` 方法,你必須實(shí)現(xiàn)這個(gè)代理方法來(lái)確保你的設(shè)備支持藍(lán)牙4.0.

####2. 掃描外部設(shè)備

[myCentralManager scanForPeripheralsWithServices:nil options:nil];

1. `注意`:如果第一個(gè)參數(shù)傳入nil,`中央管理器` 返回全部找到的外設(shè),忽略它們所支持的服務(wù),你可以傳入一個(gè)有獨(dú)特UUID的`服務(wù)`數(shù)組,當(dāng)你指定服務(wù)的時(shí)候,`中央管理器` 只返回具擁有這些服務(wù)的外設(shè).
2. 在你調(diào)用` scanForPeripheralsWithServices:options: `方法之后,`中央管理器`就會(huì)調(diào)用它代理的` centralManager:didDiscoverPeripheral:advertisementData:RSSI:`,沒(méi)發(fā)現(xiàn)一個(gè)外設(shè)就會(huì)調(diào)用一次,發(fā)現(xiàn)的外部設(shè)備通過(guò)` CBPeripheral `對(duì)象傳入.你可以實(shí)現(xiàn)這個(gè)方法列出所發(fā)現(xiàn)的外設(shè).
    ```
   - (void)centralManager:(CBCentralManager *)central
    didDiscoverPeripheral:(CBPeripheral *)peripheral
        advertisementData:(NSDictionary *)advertisementData
                     RSSI:(NSNumber *)RSSI {
    
       NSLog(@"Discovered %@", peripheral.name);
       ...

當(dāng)你找到你需要的外設(shè)后,你需要停止搜索.

3. 連接外部設(shè)備

當(dāng)你找到自己需要的外設(shè)后,你應(yīng)該請(qǐng)求連接外部設(shè)備,通過(guò)調(diào)用BCentralManagerconnectPeripheral:options:方法.如:

[myCentralManager connectPeripheral:peripheral options:nil];
假如連接外設(shè)成功,中央管理器就會(huì)調(diào)用它代理的centralManager:didConnectPeripheral:方法,

- (void)centralManager:(CBCentralManager *)central
 didConnectPeripheral:(CBPeripheral *)peripheral {

   NSLog(@"Peripheral connected");
   ...```
在與外設(shè)進(jìn)行交互之前你應(yīng)該首先設(shè)置外設(shè)的代理

####4. 發(fā)現(xiàn)已經(jīng)連接設(shè)備上的服務(wù).
當(dāng)你連接上一個(gè)外設(shè),你就可以開(kāi)始檢索數(shù)據(jù)了,第一步,檢索一個(gè)外設(shè)上都提供什么服務(wù),通過(guò)下面的方法你可以檢索出,所有的外設(shè)提供的所有的服務(wù)

[peripheral discoverServices:nil];```

注意:盡管你這么做可以反問(wèn)這個(gè)外設(shè)上的所有服務(wù),但是在一個(gè)真實(shí)的App中你通常不傳入一個(gè)nil,因?yàn)橐粋€(gè)外設(shè)可能非常多的服務(wù),這些服務(wù)并不是你需要的,發(fā)現(xiàn)他們?nèi)靠赡芸s短電池的使用時(shí)間并且浪費(fèi)時(shí)間.更多情況你需要制定服務(wù)UUID來(lái)檢索你感興趣的服務(wù).

但發(fā)現(xiàn)指定的服務(wù)后,將會(huì)調(diào)用CBPeripheral 對(duì)象的代理方法peripheral:didDiscoverServices:,核心藍(lán)牙框架會(huì)把所發(fā)現(xiàn)的服務(wù)放到一個(gè)數(shù)組中,設(shè)置給這個(gè)外設(shè)對(duì)象.你可以實(shí)現(xiàn)這個(gè)代理方法,訪問(wèn)這些服務(wù)

- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverServices:(NSError *)error {
 
    for (CBService *service in peripheral.services) {
        NSLog(@"Discovered service %@", service);
        ...
    }
    ...```

####5. 發(fā)現(xiàn)一個(gè)服務(wù)上的特征.

假設(shè)你已經(jīng)找到了你需要的服務(wù),下一步就是檢索該服務(wù)上的特征,檢索服務(wù)上的所有特征你只需要調(diào)用` CBPeripheral` 方法 ` discoverCharacteristics:forService: ` 并指定服務(wù)

NSLog(@"Discovering characteristics for service %@", interestingService);
[peripheral discoverCharacteristics:nil forService:interestingService];```

注意: 盡管你這么做可以反問(wèn)這個(gè)服務(wù)上的所有特征,但是在一個(gè)真實(shí)的App中你通常不要出入一個(gè)nil,因?yàn)橐粋€(gè)服務(wù)可能非常多的特征,這些特征并不是你需要的,發(fā)現(xiàn)他們?nèi)靠赡軙?huì)縮短電池的使用時(shí)間并且浪費(fèi)時(shí)間.更多情況你需要制定特征UUID來(lái)檢索你感興趣的 特征.

當(dāng)外設(shè)檢索到指定服務(wù)的特征后,就會(huì)調(diào)用代理對(duì)象的peripheral:didDiscoverCharacteristicsForService:error: 核心藍(lán)牙會(huì)把所發(fā)現(xiàn)的特征放到數(shù)組中設(shè)置給服務(wù)的characteristics 屬性,你可以實(shí)現(xiàn)這個(gè)代理方法,獲取檢索到的特征

- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverCharacteristicsForService:(CBService *)service
             error:(NSError *)error {
 
    for (CBCharacteristic *characteristic in service.characteristics) {
        NSLog(@"Discovered characteristic %@", characteristic);
        ...
    }
    ...

6. 取出一個(gè)特征的值

一個(gè)特征包含一個(gè)單獨(dú)的,這個(gè)代表著外設(shè)提供的服務(wù)的詳細(xì)信息.例如在一個(gè)體溫計(jì)中的一個(gè)溫度的特征有一個(gè)值代表著攝氏度的溫度.你可以可以直接讀取這個(gè)值或訂閱這個(gè)值

1. 讀出一個(gè)特征的值

當(dāng)你找到需要的服務(wù)的一個(gè)特征后,你可以讀取這個(gè)特征的值,通過(guò)調(diào)用CBPeripheralreadValueForCharacteristic: 傳入那個(gè)特征.像這樣

  NSLog(@"Reading value for characteristic %@", interestingCharacteristic);
    [peripheral readValueForCharacteristic:interestingCharacteristic];```

當(dāng)你試圖讀取一個(gè)特征的值的時(shí)候,外設(shè)就會(huì)調(diào)用它代理的`peripheral:didUpdateValueForCharacteristic:error: ` 方法,如果這個(gè)被成功的獲取,你就可訪問(wèn)`特征`的`value`屬性獲取這個(gè)值,像這樣
  • (void)peripheral:(CBPeripheral *)peripheral
    didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
    error:(NSError *)error {

    NSData *data = characteristic.value;
    // parse the data as needed
    ...```

注意: 并不是所有的特征都有讀的權(quán)限,你要檢測(cè)這個(gè)特征是否有讀的權(quán)限可以通過(guò)特征的properties屬性中CBCharacteristicPropertyRead Key ,如果你試圖讀取一個(gè)不可度的特征值,那么在peripheral:didUpdateValueForCharacteristic:error: 方法中將會(huì)傳入一個(gè)合適的 錯(cuò)誤

2. 訂閱一個(gè)特征的值

盡管在某些情況下你可以通過(guò)readValueForCharacteristic: 很方便的讀取一個(gè)特征的值,但是對(duì)于一個(gè)經(jīng)常變化的值這不是一中高效的方式.大部分特征的值的變化的--例如心率是每時(shí)每刻都在變化,此時(shí)你應(yīng)該訂閱它.當(dāng)你訂閱一個(gè)特征的值的時(shí)候,你將會(huì)收到一個(gè)通知,當(dāng)外設(shè)的值改變的時(shí)候

你可以訂閱一個(gè)特征的值,通過(guò)調(diào)用CBPeripheralsetNotifyValue:forCharacteristic: 第一個(gè)參數(shù)傳入YES,像這樣

 [peripheral setNotifyValue:YES forCharacteristic:interestingCharacteristic];```

當(dāng)你嘗試訂閱(或取消訂閱)一個(gè)特征的值時(shí),外設(shè)的代理方法`peripheral:didUpdateNotificationStateForCharacteristic:error: ` 就會(huì)被調(diào)用.如果訂閱請(qǐng)求因任何原因失敗,這個(gè)代理方法中都會(huì)通過(guò)`error`告訴你錯(cuò)誤的原因.例如:
  • (void)peripheral:(CBPeripheral *)peripheral
    didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic
    error:(NSError *)error {

    if (error) {
    NSLog(@"Error changing notification state: %@",
    [error localizedDescription]);
    }
    ...


> `注意:` 不是所有特征都可以訂閱他們的值,你可以通過(guò)` Characteristic ` 的`Properties` 屬性來(lái)判斷這個(gè)特征是否支持訂閱.


當(dāng)你成功訂閱一個(gè)特征的值后,外設(shè)將會(huì)在它的值改變的時(shí)候通知你.每次值的改變都會(huì)調(diào)用代理的`peripheral:didUpdateValueForCharacteristic:error: `方法,為了獲取這個(gè)這你需要實(shí)現(xiàn)這個(gè)代理方法.

####7.寫入一個(gè)特征的值

有些時(shí)候可能需要需要寫入一個(gè)特征的值,比如你app和基于藍(lán)牙4.0的自動(dòng)溫度調(diào)節(jié)器交互,你可能需要提供一個(gè)值來(lái)設(shè)置室內(nèi)溫度,如果這個(gè)特征值是可寫的,你通過(guò)`CBPeripheral ` 的 ` writeValue:forCharacteristic:type: ` 方法,第一個(gè)參數(shù)傳入一個(gè)`NSData`對(duì)象,像這樣:
NSLog(@"Writing value for characteristic %@", interestingCharacteristic);
[peripheral writeValue:dataToWrite forCharacteristic:interestingCharacteristic
    type:CBCharacteristicWriteWithResponse];
當(dāng)你寫入特征的值時(shí),你需要指定按照什么類型寫入,在上面的例子中指定是`CBCharacteristicWriteWithResponse` 它告訴外設(shè)需要讓你的app知道是否寫入成功.

外設(shè)通過(guò)調(diào)用代理對(duì)象的` peripheral:didWriteValueForCharacteristic:error: ` 來(lái)響應(yīng)指定類型參數(shù)`CBCharacteristicWriteWithResponse`寫入請(qǐng)求.任何原因?qū)е碌膶懭胧?你都會(huì)收到一個(gè)錯(cuò)誤對(duì)象,它描述了錯(cuò)誤的原因,例如
  • (void)peripheral:(CBPeripheral *)peripheral
    didWriteValueForCharacteristic:(CBCharacteristic *)characteristic
    error:(NSError *)error {
    if (error) {
    NSLog(@"Error writing characteristic value: %@",
    [error localizedDescription]);
    }
    ...
> `注意:`特征可能只允許以特定的類類型寫入,想知道特征都支持那種類型的寫入可以遍歷`Characteristic`的 `properties` 屬性.
####附錄. 中心設(shè)備流程
![中心設(shè)備流程.jpg](http://upload-images.jianshu.io/upload_images/321489-76d3201f640ad14e.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市青抛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌耘子,老刑警劉巖碳默,帶你破解...
    沈念sama閱讀 211,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異璧尸,居然都是意外死亡剔应,警方通過(guò)查閱死者的電腦和手機(jī)睡腿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)峻贮,“玉大人席怪,你說(shuō)我怎么就攤上這事∠丝兀” “怎么了挂捻?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,435評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)船万。 經(jīng)常有香客問(wèn)我刻撒,道長(zhǎng),這世上最難降的妖魔是什么耿导? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,509評(píng)論 1 284
  • 正文 為了忘掉前任声怔,我火速辦了婚禮,結(jié)果婚禮上舱呻,老公的妹妹穿的比我還像新娘醋火。我一直安慰自己,他們只是感情好箱吕,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,611評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布芥驳。 她就那樣靜靜地躺著,像睡著了一般茬高。 火紅的嫁衣襯著肌膚如雪兆旬。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,837評(píng)論 1 290
  • 那天怎栽,我揣著相機(jī)與錄音丽猬,去河邊找鬼宿饱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛宝鼓,可吹牛的內(nèi)容都是我干的刑棵。 我是一名探鬼主播巴刻,決...
    沈念sama閱讀 38,987評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼愚铡,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了胡陪?” 一聲冷哼從身側(cè)響起沥寥,我...
    開(kāi)封第一講書(shū)人閱讀 37,730評(píng)論 0 267
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎柠座,沒(méi)想到半個(gè)月后邑雅,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,194評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡妈经,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,525評(píng)論 2 327
  • 正文 我和宋清朗相戀三年淮野,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吹泡。...
    茶點(diǎn)故事閱讀 38,664評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡骤星,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出爆哑,到底是詐尸還是另有隱情洞难,我是刑警寧澤,帶...
    沈念sama閱讀 34,334評(píng)論 4 330
  • 正文 年R本政府宣布揭朝,位于F島的核電站队贱,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏潭袱。R本人自食惡果不足惜柱嫌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,944評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望屯换。 院中可真熱鬧编丘,春花似錦、人聲如沸趟径。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,764評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蜗巧。三九已至掌眠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間幕屹,已是汗流浹背蓝丙。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,997評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工级遭, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人渺尘。 一個(gè)月前我還...
    沈念sama閱讀 46,389評(píng)論 2 360
  • 正文 我出身青樓挫鸽,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親鸥跟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子丢郊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,554評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容