iOS蓝牙开发(4.0)详解
最近由于項目需要, 一直在研究藍牙4.0,在這兒分享給大家, 望共同進步.
一、關于藍牙開發的一些重要的理論概念:
1.當前ios中開發藍牙所運用的系統庫是<CoreBluetooth/CoreBluetooth.h>。
2.藍牙外設必須為4.0及以上(2.0需要MFI認證),否則無法開發,藍牙4.0設備因為低耗電,所以也叫做BLE。
3.CoreBluetooth框架的核心其實是兩個東西,peripheral和central, 可以理解成外設和中心,就是你的蘋果手機就是中心,外部藍牙稱為外設。
4.服務和特征(service and characteristic):簡而言之,外部藍牙中它有若干個服務service(服務你可以理解為藍牙所擁有的能力),而每個服務service下擁有若干個特征characteristic(特征你可以理解為解釋這個服務的屬性)。
5.Descriptor(描述)用來描述characteristic變量的屬性。例如,一個descriptor可以規定一個可讀的描述,或者一個characteristic變量可接受的范圍,或者一個characteristic變量特定的單位。
6.我們使用的藍牙模塊是在淘寶買的, 大概十多元一個, ios大概每次可以接受90個字節, 安卓大概每次可以接收20個字節, 具體數字可能會浮動, 應該是與藍牙模塊有關。
二、藍牙連接的主要步驟
1、創建一個CBCentralManager實例來進行藍牙管理;2、搜索掃描外圍設備;3、連接外圍設備;4、獲得外圍設備的服務;5、獲得服務的特征;6、從外圍設備讀取數據;7、給外圍設備發送(寫入)數據。?
三、代碼
// 加入權限訪問, 否則上傳AppStore會因為權限不足失敗
1. 初始化
#import <CoreBluetooth/CoreBluetooth.h> self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];2. 搜索掃描外圍設備
/*** -- 初始化成功自動調用* -- 必須實現的代理,用來返回創建的centralManager的狀態。* -- 注意:必須確認當前是CBCentralManagerStatePoweredOn狀態才可以調用掃描外設的方法:scanForPeripheralsWithServices*/ - (void)centralManagerDidUpdateState:(CBCentralManager *)central{switch (central.state) {case CBCentralManagerStateUnknown:NSLog(@">>>CBCentralManagerStateUnknown");break;case CBCentralManagerStateResetting:NSLog(@">>>CBCentralManagerStateResetting");break;case CBCentralManagerStateUnsupported:NSLog(@">>>CBCentralManagerStateUnsupported");break;case CBCentralManagerStateUnauthorized:NSLog(@">>>CBCentralManagerStateUnauthorized");break;case CBCentralManagerStatePoweredOff:NSLog(@">>>CBCentralManagerStatePoweredOff");break;case CBCentralManagerStatePoweredOn:{NSLog(@">>>CBCentralManagerStatePoweredOn");// 開始掃描周圍的外設。/*-- 兩個參數為Nil表示默認掃描所有可見藍牙設備。-- 注意:第一個參數是用來掃描有指定服務的外設。然后有些外設的服務是相同的,比如都有FFF5服務,那么都會發現;而有些外設的服務是不可見的,就會掃描不到設備。-- 成功掃描到外設后調用didDiscoverPeripheral*/[self.centralManager scanForPeripheralsWithServices:nil options:nil];}break;default:break;} } #pragma mark 發現外設 - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{NSLog(@"Find device:%@", [peripheral name]);if (![_deviceDic objectForKey:[peripheral name]]) {NSLog(@"Find device:%@", [peripheral name]);if (peripheral!=nil) {if ([peripheral name]!=nil) {if ([[peripheral name] hasPrefix:@"根據設備名過濾"]) {[_deviceDic setObject:peripheral forKey:[peripheral name]];// 停止掃描, 看需求決定要不要加 // [_centralManager stopScan];// 將設備信息傳到外面的頁面(VC), 構成掃描到的設備列表if ([self.delegate respondsToSelector:@selector(dataWithBluetoothDic:)]) {[self.delegate dataWithBluetoothDic:_deviceDic];}}}}} }3.連接外圍設備
// 連接設備(.h中聲明出去的接口, 一般在點擊設備列表連接時調用) - (void)connectDeviceWithPeripheral:(CBPeripheral *)peripheral {[self.centralManager connectPeripheral:peripheral options:nil]; } #pragma mark 連接外設--成功 - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{//連接成功后停止掃描,節省內存 [central stopScan];peripheral.delegate = self;self.peripheral = peripheral;//4.掃描外設的服務/**-- 外設的服務、特征、描述等方法是CBPeripheralDelegate的內容,所以要先設置代理peripheral.delegate = self-- 參數表示你關心的服務的UUID,比如我關心的是"FFE0",參數就可以為@[[CBUUID UUIDWithString:@"FFE0"]].那么didDiscoverServices方法回調內容就只有這兩個UUID的服務,不會有其他多余的內容,提高效率。nil表示掃描所有服務-- 成功發現服務,回調didDiscoverServices*/[peripheral discoverServices:@[[CBUUID UUIDWithString:@"你要用的服務UUID"]]];if ([self.delegate respondsToSelector:@selector(didConnectBle)]) {// 已經連接[self.delegate didConnectBle];} } #pragma mark 連接外設——失敗 - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{NSLog(@"%@", error); } #pragma mark 取消與外設的連接回調 - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{NSLog(@"%@", peripheral); }4. 獲得外圍設備的服務
#pragma mark 發現服務回調 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{//NSLog(@"didDiscoverServices,Error:%@",error);CBService * __nullable findService = nil;// 遍歷服務for (CBService *service in peripheral.services){//NSLog(@"UUID:%@",service.UUID);if ([[service UUID] isEqual:[CBUUID UUIDWithString:@"你要用的服務UUID"]]){findService = service;}}NSLog(@"Find Service:%@",findService);if (findService)[peripheral discoverCharacteristics:NULL forService:findService]; }5、獲得服務的特征
#pragma mark 發現特征回調 /**-- 發現特征后,可以根據特征的properties進行:讀readValueForCharacteristic、寫writeValue、訂閱通知setNotifyValue、掃描特征的描述discoverDescriptorsForCharacteristic。**/ - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{for (CBCharacteristic *characteristic in service.characteristics) {if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"你要用的特征UUID"]]) {/**-- 讀取成功回調didUpdateValueForCharacteristic*/self.characteristic = characteristic;// 接收一次(是讀一次信息還是數據經常變實時接收視情況而定, 再決定使用哪個) // [peripheral readValueForCharacteristic:characteristic];// 訂閱, 實時接收 [peripheral setNotifyValue:YES forCharacteristic:characteristic];// 發送下行指令(發送一條)NSData *data = [@"硬件工程師給我的指令, 發送給藍牙該指令, 藍牙會給我返回一條數據" dataUsingEncoding:NSUTF8StringEncoding];// 將指令寫入藍牙 [self.peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];}/**-- 當發現characteristic有descriptor,回調didDiscoverDescriptorsForCharacteristic*/[peripheral discoverDescriptorsForCharacteristic:characteristic];} }6.從外圍設備讀取數據
#pragma mark - 獲取值 - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{// characteristic.value就是藍牙給我們的值(我這里是json格式字符串)NSData *jsonData = [characteristic.value dataUsingEncoding:NSUTF8StringEncoding];NSDictionary *dataDic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];// 將字典傳出去就可以使用了 }#pragma mark - 中心讀取外設實時數據 - (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{if (characteristic.isNotifying) {[peripheral readValueForCharacteristic:characteristic];} else { NSLog(@"Notification stopped on %@. Disconnecting", characteristic);NSLog(@"%@", characteristic);[self.centralManager cancelPeripheralConnection:peripheral];} }7. 給外圍設備發送(寫入)數據
// 上文中發現特征之后, 發送下行指令的時候其實就是向藍牙中寫入數據 // 例: // 發送檢查藍牙命令 - (void)writeCheckBleWithBle {_style = 1;// 發送下行指令(發送一條)NSData *data = [@"硬件工程師提供給你的指令, 類似于5E16010203...這種很長一串" dataUsingEncoding:NSUTF8StringEncoding];[self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse]; } #pragma mark 數據寫入成功回調 - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{NSLog(@"寫入成功");if ([self.delegate respondsToSelector:@selector(didWriteSucessWithStyle:)]) {[self.delegate didWriteSucessWithStyle:_style];} }8. 另外
// 掃描設備 - (void)scanDevice {if (_centralManager == nil) {self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];[_deviceDic removeAllObjects];} } #pragma mark - 斷開連接 - (void)disConnectPeripheral{/**-- 斷開連接后回調didDisconnectPeripheral-- 注意斷開后如果要重新掃描這個外設,需要重新調用[self.centralManager scanForPeripheralsWithServices:nil options:nil];*/[self.centralManager cancelPeripheralConnection:self.peripheral]; } #pragma mark - 停止掃描外設 - (void)stopScanPeripheral{[self.centralManager stopScan]; }由于硬件方面剛開始用藍牙2.0跟我對接, 導致程序一直搜索不到設備.希望小伙伴們注意一下這個問題. 如果有不清楚的地方歡迎留言探討.
總結
以上是生活随笔為你收集整理的iOS蓝牙开发(4.0)详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 对象属性和类属性
- 下一篇: 机器学习之数理统计与参数估计的相关知识总