iOS藍牙知識快速入門(詳盡版)

2021-02-16 二進位小鎮


作者:勇闖天涯茉莉花茶

地址:www.jianshu.com/p/f7a53b3a0fc8

以前寫過幾篇藍牙相關的文章,但是沒有涉及掃描、收發指令這些基礎功能的實現。所以打算寫一篇儘可能詳盡的藍牙知識匯總,一方面給有需要的同學看,一方面是對自己學習藍牙的一個總結。

這篇文章的目的:教你實現設備的掃描,連接,數據收發,藍牙數據解析。如果在實現上面任一功能遇到問題時,歡迎留下你的問題,我將進行補充,對於說法有誤的地方也請老司機予以指正。

0、思維導圖
1、蘋果對藍牙設備有什麼要求
2、操作藍牙設備使用什麼庫
3、如何掃描
4、如何連接
5、如何發送數據和接收數據
6、如何解析數據
7、擴展



第一次做圖,大家湊合著看哈。這張是我總結的藍牙知識的結構圖,下面的內容將圍繞這些東西展開進行。


連接設備流程


這張是藍牙連接發送數據的流程圖,下文進入coding階段的講解順序,大家先有個大概印象,等閱讀完本文再回來看這張圖將理解的更深一些。

BLE:bluetouch low energy,藍牙4.0設備因為低功耗,所有也叫作BLE。蘋果在iphone4s及之後的手機型號開始支持藍牙4.0,這也是最常見的藍牙設備。低於藍牙4.0協議的設備需要進行MFI認證,關於MFI認證的申請工作可以看這裡:關於MFI認證你所必須要知道的事情(http://www.jianshu.com/p/b90b0c45398d )

在進行操作藍牙設備前,我們先下載一個藍牙工具LightBlue,它可以輔助我們的開發,在進行藍牙開發之前建議先熟悉一下LightBlue(https://itunes.apple.com/us/app/lightblue-explorer-bluetooth/id557428110?mt=8 )這個工具。


蘋果自身有一個操作藍牙的庫CoreBluetooth.framework,這個是大多數人員進行藍牙開發的首選框架,除此之外目前github還有一個比較流行的對原生框架進行封裝的三方庫BabyBluetooth,它的機制是將CoreBluetooth中眾多的delegate寫成了block方法,有興趣的同學可以了解下。下面主要介紹的是原生藍牙庫的知識。



central-peripheral

如圖所示,電腦、Pad、手機作為中心,心跳監聽器作為外設,這種中心外設模式是最常見的。簡單理解就是,發起連接的是中心設備(Central),被連接的是外圍設備(Peripheral),對應傳統的客戶機-伺服器體系結構。Central能夠掃描偵聽到,正在播放廣告包的外設。


外設可以包含一個或多個服務(CBService),服務是用於實現裝置的功能或特徵數據相關聯的行為集合。
而每個服務又對應多個特徵(CBCharacteristic),特徵提供外設服務進一步的細節,外設,服務,特徵對應的數據結構如下所示


CBService-CBCharacteristic


在進行掃描之前我們需要,首先新建一個類作為藍牙類,例如FYBleManager,寫成單例,作為處理藍牙操作的管理類。引入頭文件#import <CoreBluetooth/CoreBluetooth.h>
CBCentralManager是藍牙中心的管理類,控制著藍牙的掃描,連接,藍牙狀態的改變。


  dispatch_queue_t centralQueue = dispatch_queue_create(「centralQueue",DISPATCH_QUEUE_SERIAL);    

    NSDictionary *dic = @{CBCentralManagerOptionShowPowerAlertKey : YES,

    CBCentralManagerOptionRestoreIdentifierKey : @"unique identifier"

    };

    self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:centralQueue options:dic];

CBCentralManagerOptionShowPowerAlertKey對應的BOOL值,當設為YES時,表示CentralManager初始化時,如果藍牙沒有打開,將彈出Alert提示框
CBCentralManagerOptionRestoreIdentifierKey對應的是一個唯一標識的字符串,用於藍牙進程被殺掉恢復連接時用的。


//不重複掃描已發現設備        

NSDictionary *option = @{CBCentralManagerScanOptionAllowDuplicatesKey : [NSNumber numberWithBool:NO],CBCentralManagerOptionShowPowerAlertKey:YES};        

[self.centralManager scanForPeripheralsWithServices:nil options:option];

- (void)scanForPeripheralsWithServices:(nullable NSArray<CBUUID *> *)serviceUUIDs options:(nullable NSDictionary<NSString *, id> *)options;

掃面方法,serviceUUIDs用於第一步的篩選,掃描此UUID的設備
options有兩個常用參數:CBCentralManagerScanOptionAllowDuplicatesKey設置為NO表示不重複掃瞄已發現設備,為YES就是允許。CBCentralManagerOptionShowPowerAlertKey設置為YES就是在藍牙未打開的時候顯示彈框

3、CBCentralManagerDelegate代理方法

在初始化的時候我們調用了代理,在CoreBluetooth中有兩個代理,

CBCentralManagerDelegate

CBPeripheralDelegate

iOS的命名很友好,我們通過名字就能看出,上面那個是關於中心設備的代理方法,下面是關於外設的代理方法。我們這裡先研究CBCentralManagerDelegate中的代理方法

- (void)centralManagerDidUpdateState:(CBCentralManager *)central;

這個方法標了@required是必須添加的,我們在self.centralManager初始換之後會調用這個方法,回調藍牙的狀態。狀態有以下幾種:

typedef NS_ENUM(NSInteger, CBCentralManagerState{

CBCentralManagerStateUnknown = CBManagerStateUnknown,//未知狀態

CBCentralManagerStateResetting = CBManagerStateResetting,//重啟狀態

CBCentralManagerStateUnsupported = CBManagerStateUnsupported,//不支持

CBCentralManagerStateUnauthorized = CBManagerStateUnauthorized,//未授權

CBCentralManagerStatePoweredOff = CBManagerStatePoweredOff,//藍牙未開啟

CBCentralManagerStatePoweredOn = CBManagerStatePoweredOn,//藍牙開啟

} NS_DEPRECATED(NA, NA, 5_0, 10_0, "Use CBManagerState instead」);

該枚舉在iOS10之後已經廢除了,系統推薦使用CBManagerState,類型都是對應的

typedef NS_ENUM(NSInteger, CBManagerState{

    CBManagerStateUnknown = 0,

    CBManagerStateResetting,

    CBManagerStateUnsupported,

    CBManagerStateUnauthorized,

    CBManagerStatePoweredOff,

    CBManagerStatePoweredOn,

} NS_ENUM_AVAILABLE(NA, 10_0);

- (void)centralManager:(CBCentralManager *)central 

    didDiscoverPeripheral:(CBPeripheral *)peripheral 

    advertisementData:(NSDictionary<NSString *, id> *)advertisementData

     RSSI:(NSNumber *)RSSI;

peripheral是外設類
advertisementData是廣播的值,一般攜帶設備名,serviceUUIDs等信息
RSSI絕對值越大,表示信號越差,設備離的越遠。如果想裝換成百分比強度,(RSSI+100)/100,(這是一個約數,藍牙信號值並不一定是-100 - 0的值,但近似可以如此表示)

- (void)centralManager:(CBCentralManager *)central 

    willRestoreState:(NSDictionary<NSString *, id> *)dict;

在藍牙於後臺被殺掉時,重連之後會首先調用此方法,可以獲取藍牙恢復時的各種狀態


在掃面的代理方法中,我們連接外設名是MI的藍牙設備

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{    

    NSLog(@"advertisementData:%@,RSSI:%@",advertisementData,RSSI);      

    if([peripheral.name isEqualToString:@"MI"]){        

      [self.centralManager connectPeripheral:peripheral options:nil];//發起連接的命令       

      self.peripheral = peripheral;     

    }

}

連接的狀態
對應另外的CBCentralManagerDelegate代理方法
連接成功的回調

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;

連接失敗的回調

- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error;

連接斷開的回調

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error;

連接成功之後並沒有結束,還記得CBPeripheral中的CBService和CBService中的CBCharacteristic嗎,對數據的讀寫是由CBCharacteristic控制的。我們先用lightblue連接小米手環為例,來看一下,手環內部的數據是不是我們說的那樣。


lightblue

其中ADVERTISEMENT DATA顯示的就是廣播信息。

iOS藍牙無法直接獲取設備藍牙MAC地址,可以將MAC地址放到這裡廣播出來

FEEO是ServiceUUIDs,裡面的FF01、FF02是CBCharacteristic的UUID

Properties是特徵的屬性,可以看出FF01具有讀的權限,FF02具有讀寫的權限。特徵擁有的權限類別有如下幾種:

typedef NS_OPTIONS(NSUInteger, CBCharacteristicProperties{

CBCharacteristicPropertyBroadcast = 0x01,

CBCharacteristicPropertyRead = 0x02,

CBCharacteristicPropertyWriteWithoutResponse = 0x04,CBCharacteristicPropertyWrite = 0x08,

CBCharacteristicPropertyNotify = 0x10,

CBCharacteristicPropertyIndicate = 0x20,

CBCharacteristicPropertyAuthenticatedSignedWrites = 0x40,

CBCharacteristicPropertyExtendedProperties = 0x80,

CBCharacteristicPropertyNotifyEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0) = 0x100,

CBCharacteristicPropertyIndicateEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0) = 0x200};

通過上面的步驟我們發現CBCentralManagerDelegate提供了藍牙狀態監測、掃描、連接的代理方法,但是CBPeripheralDelegate的代理方法卻還沒使用。別急,馬上就要用到了,通過名稱判斷這個代理的作用,肯定是跟Peripheral有關,我們進入系統API,看它的代理方法都有什麼,因為這裡的代理方法較多,我就挑選幾個常用的拿出來說明一下。

//發現服務的回調

- (void)peripheral:(CBPeripheral *)peripheral 

    didDiscoverServices:(nullable NSError *)error;

//發現特徵的回調

- (void)peripheral:(CBPeripheral *)peripheral 

    didDiscoverCharacteristicsForService:(CBService *)service 

    error:(nullable NSError *)error;

//讀數據的回調

- (void)peripheral:(CBPeripheral *)peripheral 

    didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic 

    error:(nullable NSError *)error;

//是否寫入成功的回調

 - (void)peripheral:(CBPeripheral *)peripheral 

    didWriteValueForCharacteristic:(CBCharacteristic *)characteristic 

    error:(nullable NSError *)error;


通過這幾個方法我們構建一個流程:連接成功->獲取指定的服務->獲取指定的特徵->訂閱指定特徵值->通過具有寫權限的特徵值寫數據->在didUpdateValueForCharacteristic回調中讀取藍牙反饋值

解釋一下訂閱特徵值:特徵值具有Notify權限才可以進行訂閱,訂閱之後該特徵值的value發生變化才會回調didUpdateValueForCharacteristic

//連接成功

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{    

    //連接成功之後尋找服務,傳nil會尋找所有服務

    [peripheral discoverServices:nil];

}

//發現服務的回調

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{   

   if (!error) {        

     for (CBService *service in peripheral.services) {                

     NSLog(@"serviceUUID:%@", service.UUID.UUIDString);   

       if ([service.UUID.UUIDString isEqualToString:ST_SERVICE_UUID]) {                

    //發現特定服務的特徵值               

     [service.peripheral discoverCharacteristics:nil forService:service];            

      }        

    }    

  }

}

//發現characteristics,由發現服務調用(上一步),獲取讀和寫的characteristics

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {    

for (CBCharacteristic *characteristic in service.characteristics) {        

//有時讀寫的操作是由一個characteristic完成        

if ([characteristic.UUID.UUIDString isEqualToString:ST_CHARACTERISTIC_UUID_READ]) {   

     self.read = characteristic;           

     [self.peripheral setNotifyValue:YES forCharacteristic:self.read];        

    } else if ([characteristic.UUID.UUIDString isEqualToString:ST_CHARACTERISTIC_UUID_WRITE]) {  

      self.write = characteristic;        }    

  }

}

//是否寫入成功的代理

- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{   

 if (error) {        

    NSLog(@"===寫入錯誤:%@",error);    

    }else{        

    NSLog(@"===寫入成功");    

    }

}

//數據接收

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {    

    if([characteristic.UUID.UUIDString isEqualToString:ST_CHARACTERISTIC_UUID_READ]){    

    //獲取訂閱特徵回復的數據

    NSData *value = characteristic.value;        

    NSLog(@"藍牙回覆:%@",value);

    }

}


比如我們要獲取藍牙電量,由硬體文檔查詢得知該指令是**0x1B9901**,那麼獲取電量的方法就可以寫成

- (void)getBattery{

    Byte value[3]={0};    

    value[0]=x1B;    

    value[1]=x99;    

    value[2]=x01;

    NSData * data = [NSData dataWithBytes:&value length:sizeof(value)];

    //發送數據

    [self.peripheral writeValue:data forCharacteristic:self.write type:CBCharacteristicWriteWithoutResponse];

}

如果寫入成功,我們將會在didUpdateValueForCharacteristic方法中獲取藍牙回復的信息。


如果你順利完成了上一步的操作,並且看到了藍牙返回的數據,那麼恭喜你,藍牙的常用操作你已經了解大半了。因為藍牙的任務大部分就是圍繞發送指令,獲取指令,將藍牙數據呈現給用戶。上一步我們已經獲取了藍牙指令,但是獲取的卻是0x567b0629這樣的數據,這是什麼意思呢。這時我們參考硬體文檔,看到這樣一段:


device-document


那麼我們就可以得出設備電量是 60%。

對數據解析的流程就是:判斷校驗和是否正確,是不是一條正確的數據->該條數據是不是我們需要的電量數據,即首字節為0x567b->根據定義規則解析電量,傳給view顯示。其中第一步校驗數據,視情況而定,也有不需要的情況。


    http://www.jianshu.com/p/a5e25206df39

    http://www.jianshu.com/p/0d956862ffa1

    http://www.jianshu.com/p/eb5b1e26adf7

有意思啊

相關焦點

  • 小雞模擬器ios版官方下載
    最具創意、歡迎和期待小雞模擬器ios版官方下載,值得下載試試! 小雞模擬器ios版官方下載小編測評:小雞模擬器ios版即下即玩,方便快捷,讓大家重溫以前的經典遊戲!小雞模擬器ios版官方下載軟體特點:·隨時隨地逛論壇,灌水交友了解小雞動態·支持機種豐富,家用機街機掌機經典薈·快速搜索,令你在最短時間找到喜歡的遊戲·全面支持中英文,全球玩家輕鬆遊戲無障礙·一鍵下載,爸爸媽媽再也不用擔心我的手指·遊戲專題推薦
  • 樂玩遊戲盒子ios版下載
    樂玩遊戲盒子ios版去哪裡下載呢!小編今天就給您帶來了超好玩的樂玩遊戲盒子ios版!樂玩遊戲盒子ios版遊戲種類豐富,匯集最新最火熱的單機、網遊,每日推薦最新最火破解遊戲,更有海量的免費、漢化遊戲,提供各種時下流行遊戲極速下載,為用戶提供更新、更安全、更全面的遊戲體驗。
  • 3000到8000 輕薄辦公本推薦,全平臺詳盡收錄
    3000到8000 輕薄辦公本推薦,全平臺詳盡收錄優點:缺點:小結:買這臺筆記本的朋友應該目標明確:要買的是一款入門級商務本。這款的丐版配置私以為就挺合適,預算更高可以買其他機器。對內存、硬碟甚至屏幕有需求的話直接換就好,4500u在E14上性能釋放不錯,對CPU性能有更高需求的話也許應該選購其他筆記本。
  • [Swift基礎] 麥子學院iOS開發視頻教程從入門到精通
    第一階段:語言基礎和iOS入門1、秒學Swift開發語言,坐標系計算機語言學法2、初始Objective-C3、iOS8 App開發快速入門4、iOS開發語言 swift 2.2基礎第二階段:玩轉界面1、swift2.0-iOS玩轉UIKit2、IOS動畫編程3、IOS多點觸控與手勢識別
  • ios破解版遊戲下載
    你正在尋ios破解版遊戲嗎?朋友,別再盲目尋找了,快上咪嚕遊戲盒子!裡面ios破解手遊應有盡有,不好玩來打我! 咪嚕BT手遊app為您提供海量BT手遊,無限元寶鑽石,上線送滿VIP,裡面的遊戲畫面精緻到讓人感動; 為您提供高比例充值,官方BT服,充值高達1:500;高爆率快速通關,開啟BT手遊新玩法; 為您提供官服/H5手遊:充值滿立減+超多優惠劵可同時享有,福利多少優惠多多; 為您提供千餘款熱門手遊,規模全球領先!
  • ios免越獄破解版遊戲下載
    你正在尋ios免越獄破解版遊戲嗎?朋友,別再盲目尋找了,快上咪嚕遊戲盒子!裡面破解手遊應有盡有,不好玩來打我! 咪嚕BT手遊app為您提供海量BT手遊,無限元寶鑽石,上線送滿VIP,裡面的遊戲畫面精緻到讓人感動; 為您提供高比例充值,官方BT服,充值高達1:500;高爆率快速通關,開啟BT手遊新玩法; 為您提供官服/H5手遊:充值滿立減+超多優惠劵可同時享有,福利多少優惠多多; 為您提供千餘款熱門手遊,規模全球領先!
  • 大朋看看vr青春版藍牙遙控器怎麼使用 大朋vr青春版手柄教程
    大朋看看vr青春版眼鏡藍牙遙控器怎麼用、大朋看看vr青春版遙控器如何使用,大朋看看vr青春版手機藍牙手柄遙控器無法連接配對怎麼辦。購買了大朋看看vr青春版眼鏡會有一個配套的藍牙遙控器,袖扣VR小編將在本文中為各位詳細的介紹:大朋看看vr青春版藍牙手柄遙控器連接使用詳細圖文步驟說明、大朋看看vr青春版藍牙遙控器使用注意事項,連接和使用過程中常見問題解決方法,希望小編的本篇文章能解決你在使用VR藍牙遙控器中遇到的各類問題。
  • NBA2K19ios版初步試玩!操控感降低,互動性增強!
    NBA2K19ios版已經在蘋果商店上線了,大嘴巴第一時間花了50塊錢巨資下載了遊戲,並且把初步試玩的感受發布在這裡供大家參考!NBA2K19ios版畫面風格有了很大的改變,四宮格模式,增加了故事模式,更有劇情性,有時間的朋友可以好好感受下劇情,而街球模式加入到快速比賽一欄中去;
  • 悟飯遊戲廳ios版破解版下載
    悟飯遊戲廳ios版破解版下載不管是從時間上來說,還是從趣味性來說,都是一款你可以試玩的遊戲悟飯遊戲廳ios版破解版下載軟體介紹:悟飯遊戲廳ios版破解版下載的玩法豐富,絕對適合喜歡遊戲的你。
  • 蘋果可立拍 iOS版 更新:支持滑鼠、觸控板或藍牙鍵盤
    IT之家 4月8日消息 蘋果現已發布可立拍 iOS 版 2.1.1 更新,在搭載 iPadOS 13.4 的 iPad 上,支持配合滑鼠、觸控板或藍牙鍵盤使用。
  • 小白入門寶典⑤ 無線藍牙音箱選購指南
    ,而同時從側面也反映出人們對於無線產品的青睞;從今年年初來看,藍牙音箱的勢頭依舊保持的不錯;而隨著藍牙4.2標準已經開始支持網際網路連接,勢必會加速藍牙音箱今後的普及,同時還可以讓其他藍牙設備與家庭間的互聯更加快速。
  • 悟飯遊戲廳ios版下載安裝
    對此類遊戲感興趣的玩家,快來挑戰悟飯遊戲廳ios版下載安裝吧悟飯遊戲廳ios版下載安裝軟體特色:學習工作太緊張,悟飯遊戲廳ios版下載安裝讓你心情愉悅1)海量經典免費遊戲隨便玩;
  • 小雞模擬器iOS版激活碼 iOS版安裝教程
    各位玩家一直在期盼的小雞模擬器iOS版終於要來咯!小夥伴們知道怎麼樣安裝嗎?知道激活碼在哪裡領取嗎?接下來九遊小編就來和大家詳細的說說小雞模擬器iOS版安裝教程,一起來看看吧! iOS小... 來了!來了!各位玩家一直在期盼的小雞模擬器iOS版終於要來咯!小夥伴們知道怎麼樣安裝嗎?
  • 無限內購遊戲ios版下載
    無限內購遊戲ios版哪款比較好呢?小編推進您使用咪嚕無限內購遊戲ios版!這是一款專業做變態無線內購破解版遊戲的app,幫助玩家找到高返利,高權限,無VIP的精品手遊,在這裡你可以快人一步,讓給遊戲更好玩。
  • 英雄聯盟手遊臺服ios版怎麼下載-臺服ios版下載方法介紹
    英雄聯盟手遊臺服ios版怎麼下載,相信不少的玩家都有這樣的疑問,今天小編就為大家帶來英雄聯盟手遊臺服ios版下載方法介紹,希望可以幫到玩家。英雄聯盟手遊臺服ios版下載方法介紹
  • 咪嚕ios版遊戲下載安裝_咪嚕ios版手遊下載安裝_18183手機遊戲下載
    咪嚕ios版下載安裝擁有豐富的玩法模式任你選擇,讓你的遊戲過程更加的精彩! 咪嚕ios客戶端是一款破解遊戲盒子,為用戶提供各類優質熱門破解遊戲,綠色安全,無需付費,各種裝備道具隨意用,怎麼爽怎麼來,哪個好玩就玩哪個,輕鬆自在。喜歡的朋友歡迎下載使用!
  • 變態手遊ios版下載_變態手遊ios版官網最新下載_18183手機遊戲下載
    變態手遊ios版下載!這是專為遊戲愛好者開發出來的手遊盒子,gm公益服手遊、折扣手遊、破解手遊...應有盡有,這類不僅有豐富的手遊資源還有最新鮮的遊戲資訊,充值比例更高福利更多更好玩,需要的小夥伴快來下載吧!
  • 入門藍牙新標準? DOSS阿薩特音響評測
    入門藍牙新標準? DOSS阿薩特音響評測    對於年輕時尚人群來說,時尚精緻的藍牙便攜音響無疑是外出分享最好的選擇。金屬的立方形包裝盒    在其包裝盒表面我們可以看見這款音響的大致信息,它的型號等標識都是採用刻痕設計的,並非簡單的印製,這在入門級的產品中似乎並不常見。
  • 英語語法怎麼能快速入門?
    借用李笑來「最少必要知識」(Minimal Actionable Knowledge and Experience)的概念,在學習英語語法的時候,要先想辦法在最短的時間裡弄清楚都有哪些最少必要知識,然後快速掌握它們,這樣就能實現對於這一領域的「
  • 蘋果可立拍 iOS 版 2.1.1 更新:支持滑鼠、觸控板或藍牙鍵盤
    IT之家4月8日消息 蘋果現已發布可立拍 iOS 版 2.1.1 更新,在搭載 iPadOS 13.4 的 iPad 上,支持配合滑鼠、觸控板或藍牙鍵盤使用。IT之家了解到,可立拍 iOS 版 2.1.1 還支持使用「複製」按鈕快速創建包含片段所有效果的片段副本,並可通過輕點「拆分」按鈕將任意片段一分為二,然後為每個新片段創建動畫效果。