iOS蓝牙开发CoreBluetooth快速入门
在iOS開發(fā)中,實(shí)現(xiàn)藍(lán)牙通信有兩種方式,一種是使用傳統(tǒng)的GameKit.framework,另一種就是使用在iOS 5中加入的CoreBluetooth.framework。
利用CoreBluetooth框架,我們可以輕松實(shí)現(xiàn)兩個iOS設(shè)備、iOS設(shè)備與非iOS藍(lán)牙設(shè)備的交互。要注意的一點(diǎn)是目前這個框架只能支持藍(lán)牙4.0BLE標(biāo)準(zhǔn),所以對硬件上是有一定要求的,iPhone 4S及以后的設(shè)備,第三代iPad及以后的設(shè)備是支持這一標(biāo)準(zhǔn)的。
術(shù)語解釋
我們首先看一下CoreBluetooth框架的結(jié)構(gòu)。這是CoreBluetooth/CoreBluetooth.h文件中的聲明。
| 1 2 3 4 | #ifndef?_CORE_BLUETOOTH_H_ #define?_CORE_BLUETOOTH_H_ #endif #import?#import?#import?#import?#import?#import?#import?#import?#import?#import?#import |
其中,CBCentral開頭的都是中心設(shè)備類,CBPeripheral開頭的都是外設(shè)類。這就要講到藍(lán)牙設(shè)備的兩個角色了。
-
中心設(shè)備:中心設(shè)備可以理解為是處理數(shù)據(jù)的iOS設(shè)備,比如你的 iPhone、iPad 等。
-
外設(shè):外設(shè)顧名思義,就是產(chǎn)生數(shù)據(jù)的外部設(shè)備。這個外部設(shè)備可以是單片機(jī)、嵌入式設(shè)備甚至是另一個iOS設(shè)備等等。外設(shè)可以通過其傳感器等產(chǎn)生有用數(shù)據(jù),數(shù)據(jù)后通過藍(lán)牙傳給中心設(shè)備使用。
在建立連接的之前,外設(shè)向外發(fā)出廣播數(shù)據(jù)(advertisementData,官方描述“A dictionary containing any advertisement and scan response data.”),廣播數(shù)據(jù)是一個字典類數(shù)據(jù),中心設(shè)備可以獲取一定范圍內(nèi)的外設(shè)發(fā)出的廣播數(shù)據(jù)。
現(xiàn)在開始
初始化
為了使用CoreBluetooth框架中的回調(diào)方法,我們要使用CBCentralManagerDelegate、CBPeripheralDelegate這兩個協(xié)議。
我們先要初始化一個CBCentralManager類的對象。代碼如下:
| 1 2 3 4 5 6 7 | @interface?SKBluetoothManager?:?NSObject{ ????CBCentralManager?*manager; ????id?delegate; } manager?=?[[CBCentralManager?alloc]?initWithDelegate:self?queue:nil]; manager.delegate?=?self; |
掃描外設(shè)
初始化完成,我們就可以讓管理器開始掃描外設(shè)了:
| 1 | [manager?scanForPeripheralsWithServices:nil?options:nil]; |
在設(shè)備發(fā)現(xiàn)周圍外設(shè)的advertisementData后,會回調(diào)這個方法:
| 1 | -?(void)centralManager:(CBCentralManager?*)central?didDiscoverPeripheral:(CBPeripheral?*)peripheral?advertisementData:(NSDictionary?*)advertisementData?RSSI:(NSNumber?*)RSSI; |
其中參數(shù)central指回調(diào)這個方法的中心設(shè)備,peripheral指發(fā)現(xiàn)的外設(shè)對象CBPeripheral,advertisementData就是前面說的字典類型廣播數(shù)據(jù),RSSI是當(dāng)前外設(shè)的信號強(qiáng)度,單位是dbm。
剛開始對陌生的藍(lán)牙設(shè)備調(diào)試時(shí),建議我們先用一個數(shù)組NSArray將所掃描到的外設(shè)進(jìn)行保存:
| 1 | [_peripherals?addObject:peripheral]; |
連接外設(shè)
保存后,可根據(jù)設(shè)備的UUID來確定該設(shè)備是否為我們需要進(jìn)行操作的藍(lán)牙設(shè)備,在確認(rèn)外設(shè)身份后,即可發(fā)起對外設(shè)的連接操作:
| 1 2 3 4 5 6 | if?([peripheral.identifier.UUIDString?isEqualToString:kPeripheralUUID])?{ ????[manager?stopScan]; ????[manager?connectPeripheral:peripheral?options:nil]; ????NSLog(@"連接外設(shè):%@",peripheral.description); ????self.peripheral?=?peripheral; } |
在此步操作后,我們完成了對藍(lán)牙設(shè)備的掃描工作,接下來的回調(diào)方法分為兩種情況:
連接到外設(shè)后
| 1 2 3 4 5 6 | -?(void)centralManager:(CBCentralManager?*)central?didConnectPeripheral:(CBPeripheral?*)peripheral{ ????NSLog(@"已經(jīng)連接到:%@",?peripheral.description); ????peripheral.delegate?=?self; ????[central?stopScan]; ????[peripheral?discoverServices:nil]; } |
一旦連接好外設(shè),我們就可以馬上停止掃描。然后發(fā)起對服務(wù)的搜索:
| 1 | -?(void)discoverServices:(NSArray?*)serviceUUIDs; |
此處參數(shù)位需要掃描的服務(wù)的UUID的數(shù)組。文檔中特別提到,若該參數(shù)為nil,將會掃描所有的服務(wù)。
連接失敗后
在連接外設(shè)失敗的回調(diào)方法中,提供了error參數(shù),可根據(jù)實(shí)際需要來做異常處理,在此不做過多說明
| 1 2 3 | -?(void)centralManager:(CBCentralManager?*)central?didFailToConnectPeripheral:(CBPeripheral?*)peripheral?error:(NSError?*)error?{ ????NSLog(@"連接%@失敗",peripheral); } |
在搜索到藍(lán)牙設(shè)備的服務(wù)后,將會回調(diào)
| 1 | -?(void)peripheral:(CBPeripheral?*)peripheral?didDiscoverServices:(NSError?*)error |
若有錯誤發(fā)生,通過NSError異常處理。
掃描服務(wù)
由于服務(wù)在peripheral里是以NSArray的形式存在的,所以我們要對peripheral中的所有服務(wù)進(jìn)行遍歷:
| 1 2 3 4 5 6 7 8 | for?(CBService?*service?in?peripheral.services)?{ ????//發(fā)現(xiàn)服務(wù) ????if?([service.UUID?isEqual:[CBUUID?UUIDWithString:kServiceUUID]])?{ ????????NSLog(@"發(fā)現(xiàn)服務(wù):%@",?service.UUID); ????????[peripheral?discoverCharacteristics:nil?forService:service]; ????????break; ????} } |
掃描特征值
在遍歷中,趁熱打鐵,直接對其特征值進(jìn)行掃描,
| 1 | [peripheral?discoverCharacteristics:nil?forService:service]; |
這里與掃描service是相同的,若掃描所有的特征值,直接傳入nil作為參數(shù)即可。
這里的kServiceUUID是我們根據(jù)藍(lán)牙設(shè)備的具體情況,提前設(shè)置好的UUID常量。本文所有kXxxxxUUID均為預(yù)設(shè)的UUID常量。
同樣的,characteristics也是一個數(shù)組,我們利用像遍歷services一樣的方式來遍歷所有的特征值。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | -?(void)peripheral:(CBPeripheral?*)peripheral?didDiscoverCharacteristicsForService:(CBService?*)service?error:(NSError?*)error?{ ????if?(error)?{ ????????NSLog(@"搜索特征%@時(shí)發(fā)生錯誤:%@",?service.UUID,?[error?localizedDescription]); ????????return; ????} ????NSLog(@"服務(wù):%@",service.UUID); ????for?(CBCharacteristic?*characteristic?in?service.characteristics)?{ //????????NSLog(@"特征:%@",characteristic); ????????//發(fā)現(xiàn)特征 ????????if?([characteristic.UUID?isEqual:[CBUUID?UUIDWithString:kCharacteristicWriteUUID]])?{ ????????????_writeCharacteristic?=?characteristic; ????????} ????????if?([characteristic.UUID?isEqual:[CBUUID?UUIDWithString:kCharacteristicNotifyUUID]])?{ ????????????NSLog(@"監(jiān)聽特征:%@",characteristic);//監(jiān)聽特征 ????????????[self.peripheral?setNotifyValue:YES?forCharacteristic:characteristic]; ????????????_isConnected?=?YES; ????????} ????} } |
特別要提到的是,我們不同的藍(lán)牙設(shè)備有不同的服務(wù)和特征值。我的藍(lán)牙模塊的說明文檔中已經(jīng)說清楚了,write特征、read特征、notify特征,所以在此根據(jù)自身需要,來對不同的特征值進(jìn)行操作。
設(shè)置監(jiān)聽
我在此要解釋一下,當(dāng)我們試圖去讀取藍(lán)牙外設(shè)發(fā)過來的數(shù)據(jù)時(shí),一定要找準(zhǔn)特征值,用這個方法進(jìn)行訂閱。每次特征值變化的時(shí)候,就會有回調(diào)方法執(zhí)行,從而達(dá)到讀取數(shù)據(jù)的目的。容易出錯誤,一定分清楚到底哪個特征值該被訂閱。
在訂閱了特征值后,我們嘗試用藍(lán)牙外設(shè)發(fā)送一些數(shù)據(jù)出來,即可回調(diào)下一階段的方法:
| 1 2 3 4 5 6 7 8 9 | -?(void)peripheral:(CBPeripheral?*)peripheral?didUpdateValueForCharacteristic:(CBCharacteristic?*)characteristic?error:(NSError?*)error?{ ????if?(error)?{ ????????NSLog(@"更新特征值%@時(shí)發(fā)生錯誤:%@",?characteristic.UUID,?[error?localizedDescription]); ????????return; ????} //?收到數(shù)據(jù) ????[delegate?didGetDataForString:[self?hexadecimalString:characteristic.value]]; //????NSLog(@"%@",[self?hexadecimalString:characteristic.value]); } |
數(shù)據(jù)的轉(zhuǎn)換
我們接收到的數(shù)據(jù),正是characteristic.value,這是一個NSData類數(shù)據(jù),我們可以通過UTF8StringEncoding來轉(zhuǎn)化為NSString,為了代碼結(jié)構(gòu)清晰,我專門把NSData和NSString互轉(zhuǎn)寫成了兩個方法:
| 1 2 3 4 5 6 7 8 9 10 | //將傳入的NSData類型轉(zhuǎn)換成NSString并返回 -?(NSString*)hexadecimalString:(NSData?*)data{ ????NSString?*result?=?[[NSString?alloc]?initWithData:data?encoding:NSUTF8StringEncoding]; ????return?result; } //將傳入的NSString類型轉(zhuǎn)換成NSData并返回 -?(NSData*)dataWithHexstring:(NSString?*)hexstring{ ????NSData?*aData; ????return?aData?=?[hexstring?dataUsingEncoding:?NSASCIIStringEncoding]; } |
在拿到字符串后,通過各種回調(diào)方法,處理UI變動。
封裝的 SKBluetooth 的地址:SKBluetooth
轉(zhuǎn)載于:https://www.cnblogs.com/weiboyuan/p/6101296.html
總結(jié)
以上是生活随笔為你收集整理的iOS蓝牙开发CoreBluetooth快速入门的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python基础——元组、文件及其它
- 下一篇: 程序员经典语录笑话