藍(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ò)CBCentralManager
的initWithDelegate: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)用BCentralManager
的connectPeripheral: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)用CBPeripheral
的readValueForCharacteristic:
傳入那個(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)用CBPeripheral
的setNotifyValue: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)