学习ios蓝牙技术,仿写lightblue
bluetooth
上一次我們研究完iBeacon,發現iBeacon是基于藍牙4.0的一個封裝而已。那么,今天我們來研究ios的藍牙4.0的應用。最出名的app當屬lightblue,我們不妨來仿寫一個lightblue,這樣基本的ios藍牙編程就算入門了。
基本理論
框架與概念
在ios中使用藍牙技術,會用到CoreBluetooth框架。
里面對設備有2個定義:周邊(peripeheral)設備 與 中央(central)設備。發送藍牙信號的是周邊設備,接收藍牙信號的是中央設備。
可以這樣理解,周邊設備是服務端,中央設備是客戶端。中央設備可以去搜索周邊有哪些服務端,可以選擇連接上其中一臺,進行信息獲取。
支持藍牙4.0的手機,可以作為周邊設備,也可以作為中央設備,但是不能同時既為周邊設備又為中央設備。
類解讀
中央設備用?CBCentralManager?這個類管理。
周邊設備用?CBPeripheralManager?這個類管理;
周邊設備里面還有服務類?CBService,服務里面有各種各樣的特性類?CBCharacteristic。
仿寫lightblue
基本流程
至此,lightblue基本的仿寫思路就清晰列出來了。
1. 掃描設備
先包含頭文件
| 1 | #import <CoreBluetooth/CoreBluetooth.h> | 
然后添加協議?CBCentralManagerDelegate
接著定義2個屬性, CBCentralManager用來管理我們的中央設備,NSMutableArray用來保存掃描出來的周邊設備。
| 1 2 | @property (nonatomic, strong) CBCentralManager *centralMgr; @property (nonatomic, strong) NSMutableArray *arrayBLE; | 
中央設備創建很簡單,第一個參數代表?CBCentralManager?代理,第二個參數設置為nil,因為Peripheral Manager將Run在主線程中。如果你想用不同的線程做更加復雜的事情,你需要創建一個隊列(queue)并將它放在這兒。
| 1 2 | self.centralMgr = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; self.arrayBLE = [[NSMutableArray alloc] init]; | 
實現centralManagerDidUpdateState。當Central Manager被初始化,我們要檢查它的狀態,以檢查運行這個App的設備是不是支持BLE。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | - (void)centralManagerDidUpdateState:(CBCentralManager *)central { switch (central.state) { case CBCentralManagerStatePoweredOn: [self.centralMgr scanForPeripheralsWithServices:nil options:nil]; break; default: NSLog(@"Central Manager did change state"); break; } } | 
-scanForPeripheralsWithServices:options:方法是中央設備開始掃描,可以設置為特定UUID來指,來差找一個指定的服務了。我們需要掃描周邊所有設備,第一個參數設置為nil。
當發起掃描之后,我們需要實現?centralManager:didDiscoverPeripheral:advertisementData:RSSI:?通過該回調來獲取發現設備。
這個回調說明著廣播數據和信號質量(RSSI-Received Signal Strength Indicator)的周邊設備被發現。通過信號質量,可以用判斷周邊設備離中央設備的遠近。
| 1 2 3 4 5 6 7 8 9 | - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI { BLEInfo *discoveredBLEInfo = [[BLEInfo alloc] init]; discoveredBLEInfo.discoveredPeripheral = peripheral; discoveredBLEInfo.rssi = RSSI; // update tableview [self saveBLE:discoveredBLEInfo]; } | 
BLEInfo是我新建的一個類,用來存儲周邊設備信息的,具體如下:
| 1 2 3 4 5 6 | @interface BLEInfo : NSObject @property (nonatomic, strong) CBPeripheral *discoveredPeripheral; @property (nonatomic, strong) NSNumber *rssi; @end | 
保存周邊設備信息,并把它們顯示到UITableView上:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | - (BOOL)saveBLE:(BLEInfo *)discoveredBLEInfo { for (BLEInfo *info in self.arrayBLE) { if ([info.discoveredPeripheral.identifier.UUIDString isEqualToString:discoveredBLEInfo.discoveredPeripheral.identifier.UUIDString]) { return NO; } } [self.arrayBLE addObject:discoveredBLEInfo]; [self.tableView reloadData]; return YES; } | 
掃描到的周邊設備展示如下:
掃描到的周邊設備
2. 連接設備
當我們點擊其中一個設備,嘗試進行連接。lightblue是點擊后就立馬連接的,然后在下一個UITableView來展示該周邊設備的服務與特性。
而我是進入下一頁UITableView才開始連接,差別不大。但是注意的是,一定要把我們之前的self.centralMgr傳遞到下一頁的UITableView來使用,并且重新設置delegate。
用來展示服務和特性的UITableViewController:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #import <UIKit/UIKit.h> #import <CoreBluetooth/CoreBluetooth.h> @interface BLEInfoTableViewController : UITableViewController < CBPeripheralManagerDelegate, CBCentralManagerDelegate, CBPeripheralDelegate > @property (nonatomic, strong) CBCentralManager *centralMgr; @property (nonatomic, strong) CBPeripheral *discoveredPeripheral; // tableview sections,保存藍牙設備里面的services字典,字典第一個為service,剩下是特性與值 @property (nonatomic, strong) NSMutableArray *arrayServices; // 用來記錄有多少特性,當全部特性保存完畢,刷新列表 @property (atomic, assign) int characteristicNum; @end | 
記得把之前的centrlMgr傳過來,記得要重新設置delegate:
| 1 2 3 4 5 6 7 8 9 10 11 12 | - (void)viewDidLoad { [super viewDidLoad]; [_centralMgr setDelegate:self]; if (_discoveredPeripheral) { [_centralMgr connectPeripheral:_discoveredPeripheral options:nil]; } _arrayServices = [[NSMutableArray alloc] init]; _characteristicNum = 0; } | 
其中,
[centralMgr connectPeripheral:discoveredPeripheral options:nil];
就是中央設備向周邊設備發起連接。
我們可以實現下面的函數,如果連接失敗,就會得到回調:
| 1 2 3 4 | - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { NSLog(@"didFailToConnectPeripheral : %@", error.localizedDescription); } | 
我們必須實現didConnectPeripheral,只要連接成功,就能回調到該函數,開始獲取服務。
| 1 2 3 4 5 6 7 8 9 | - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { [self.arrayServices removeAllObjects]; [_discoveredPeripheral setDelegate:self]; [_discoveredPeripheral discoverServices:nil]; } | 
discoverServices就是查找該周邊設備的服務。
3. 獲取服務
當找到了服務之后,就能進入didDiscoverServices的回調。我們把全部服務都保存起來。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error { if (error) { NSLog(@"didDiscoverServices : %@", [error localizedDescription]); // [self cleanup]; return; } for (CBService *s in peripheral.services) { NSLog(@"Service found with UUID : %@", s.UUID); NSMutableDictionary *dic = [[NSMutableDictionary alloc] initWithDictionary:@{SECTION_NAME:s.UUID.description}]; [self.arrayServices addObject:dic]; [s.peripheral discoverCharacteristics:nil forService:s]; } } | 
4. 獲取特性
我們通過discoverCharacteristics來獲取每個服務下的特性,通過下面的回調來獲取。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error { if (error) { NSLog(@"didDiscoverCharacteristicsForService error : %@", [error localizedDescription]); return; } for (CBCharacteristic *c in service.characteristics) { self.characteristicNum++; [peripheral readValueForCharacteristic:c]; } } | 
5. 獲取特性值
readValueForCharacteristic可以讀取特性的值。
通過下面的回調,就能得到特性值。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { self.characteristicNum--; if (self.characteristicNum == 0) { [self.tableView reloadData]; } if (error) { NSLog(@"didUpdateValueForCharacteristic error : %@", error.localizedDescription); return; } NSString *stringFromData = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding]; if ([stringFromData isEqualToString:@"EOM"]) { NSLog(@"the characteristic text is END"); // [peripheral setNotifyValue:NO forCharacteristic:characteristic]; // [self.centralMgr cancelPeripheralConnection:peripheral]; } for (NSMutableDictionary *dic in self.arrayServices) { NSString *service = [dic valueForKey:SECTION_NAME]; if ([service isEqual:characteristic.service.UUID.description]) { NSLog(@"characteristic.description : %@", characteristic.UUID.description); [dic setValue:characteristic.value forKey:characteristic.UUID.description]; } } } | 
連接到周邊設備獲得的藍牙信息
其它
本來蘋果是提供了xcode5.0加ios7的模擬器來實現模擬器開啟藍牙的,本來連文章都給出了:https://developer.apple.com/library/ios/technotes/tn2295/_index.html
后來蘋果把這文章給刪了,還把ios7模擬器支持開啟藍牙給去掉。
那么,可以通過這個文章http://blog.csdn.net/zhenyu5211314/article/details/24399887,使用6.0的模擬器來調試。
參考文章
iOS CoreBluetooth 教程
藍牙 BLE CoreBluetooth 初探
藍牙4.0 For IOS
總結
以上是生活随笔為你收集整理的学习ios蓝牙技术,仿写lightblue的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        