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