iOS藍(lán)牙框架CoreBluetooth應(yīng)用

前一段時(shí)間做一個(gè)iPhone端通過(guò)藍(lán)牙與血壓計(jì)交互的軟件,類(lèi)似于天天血壓這款軟件的功能。在此帶來(lái)了關(guān)于藍(lán)牙的一些分享!

1、外設(shè)

外設(shè)就是一臺(tái)向外發(fā)送信息的設(shè)備,它以廣播的形勢(shì)進(jìn)行消息的發(fā)送,在手機(jī)和血壓計(jì)中,血壓計(jì)所扮演的角色就是外設(shè)。其它的一些例子,又比如智能手環(huán)、打印機(jī)、跑步用的計(jì)步器等等,這些設(shè)備都是屬于外設(shè)。在CoreBluetooth 中是通過(guò)CBPeripheralManager來(lái)進(jìn)行管理的。

2、中心

中心是我們所說(shuō)的手機(jī)端,用來(lái)接收外設(shè)所發(fā)送的信息,比如血壓計(jì)測(cè)量時(shí)所測(cè)量的值,測(cè)量的最終結(jié)果等信息,另外也可以通過(guò)中心端向外設(shè)寫(xiě)入一些值來(lái)使外設(shè)展示一些功能,比如通過(guò)手機(jī)端發(fā)送的一些指令使得血壓計(jì)啟動(dòng)測(cè)量、關(guān)閉測(cè)量和關(guān)機(jī)功能。

二、實(shí)現(xiàn)手機(jī)端(中心)的代碼邏輯

1、建立中心角色
2、掃描外設(shè)
3、連接外設(shè)
4、掃描外設(shè)中的服務(wù)和特征
    4.1 獲取外設(shè)的services
    4.2 獲取外設(shè)的Characteristics,獲取Characteristics的值,獲取Characteristics的Descriptor和Descriptor的值
5、與外設(shè)做數(shù)據(jù)交互
6、 訂閱Characteristic的通知
7、斷開(kāi)連接

在此解釋一下什么是服務(wù)(services),在硬件工程師開(kāi)發(fā)一款藍(lán)牙設(shè)備時(shí),會(huì)在設(shè)備中定義好服務(wù)。在每一個(gè)服務(wù)中都有一個(gè)或多個(gè)特征,每個(gè)特征的屬性有只讀、只寫(xiě)、通知等等。


創(chuàng)建中心管理者

//導(dǎo)入框架
#import <CoreBluetooth/CoreBluetooth.h>
@interface XYViewController ()<CBCentralManagerDelegate, CBPeripheralDelegate >
//用于保存被發(fā)現(xiàn)設(shè)備
@property (strong, nonatomic) NSMutableArray* myPeripherals;
@end
- (void)viewDidLoad {
    [super viewDidLoad];
    self.myCentralManager = [[CBCentralManager alloc]initWithDelegate:self queue:nil options:nil];
}

設(shè)置主設(shè)備的委托,CBCentralManagerDelegate
必須實(shí)現(xiàn)的代理方法:
- (void)centralManagerDidUpdateState:(CBCentralManager *)central;//主設(shè)備狀態(tài)改變的委托,在初始化CBCentralManager的適合會(huì)打開(kāi)設(shè)備,只有當(dāng)設(shè)備正確打開(kāi)后才能使用

其他選擇實(shí)現(xiàn)的委托中比較重要的:
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI; //找到外設(shè)的委托
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;//連接外設(shè)成功的委托
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;//外設(shè)連接失敗的委托
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;//斷開(kāi)外設(shè)的委托

掃描到設(shè)備進(jìn)行連接

//掃描到設(shè)備會(huì)進(jìn)入方法
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{

 //接下連接測(cè)試設(shè)備,如果沒(méi)有設(shè)備,可以下載一個(gè)叫l(wèi)ightbule的app去模擬一個(gè)設(shè)備 
//找到的設(shè)備必須持有它,否則CBCentralManager中也不會(huì)保存peripheral,那么CBPeripheralDelegate中的方法也不會(huì)被調(diào)用??!
 [myPeripherals addObject:peripheral];
 //連接設(shè)備
  [manager connectPeripheral:peripheral options:nil];
     
}

一個(gè)主設(shè)備最多能連7個(gè)外設(shè),每個(gè)外設(shè)最多只能給一個(gè)主設(shè)備連接,連接成功、失敗、斷開(kāi)都會(huì)進(jìn)入到相應(yīng)的代理

//連接到Peripherals-成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
 NSLog(@">>>連接到名稱(chēng)為(%@)的設(shè)備-成功",peripheral.name);
 [peripheral setDelegate:self];
        //掃描外設(shè)Services,成功后會(huì)進(jìn)入方法:-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
        [peripheral discoverServices:nil];
}

//連接到Peripherals-失敗
-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
 NSLog(@">>>連接到名稱(chēng)為(%@)的設(shè)備-失敗,原因:%@",[peripheral name],[error localizedDescription]);
}

//Peripherals斷開(kāi)連接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
  NSLog(@">>>外設(shè)連接斷開(kāi)連接 %@: %@\n", [peripheral name], [error localizedDescription]);

}

掃描到Services

-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
//  NSLog(@">>>掃描到服務(wù):%@",peripheral.services);
  if (error){
      NSLog(@">>>Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]);
       return;
  }

   for (CBService *service in peripheral.services) {
          NSLog(@"%@",service.UUID);
        //掃描每個(gè)service的Characteristics,掃描到后會(huì)進(jìn)入方法: -(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
     [peripheral discoverCharacteristics:nil forService:service];
    }

    }

獲取外設(shè)的Characteristics,獲取Characteristics的值,獲取Characteristics的Descriptor和Descriptor的值

//掃描到Characteristics
 -(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
     if (error)
     {
         NSLog(@"error Discovered characteristics for %@ with error: %@", service.UUID, [error localizedDescription]);
         return;
     }

     for (CBCharacteristic *characteristic in service.characteristics)
     {
         NSLog(@"service:%@ 的 Characteristic: %@",service.UUID,characteristic.UUID);
     }

     //獲取Characteristic的值,讀到數(shù)據(jù)會(huì)進(jìn)入方法:-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
     for (CBCharacteristic *characteristic in service.characteristics){
         {
             [peripheral readValueForCharacteristic:characteristic];
         }
     }

     //搜索Characteristic的Descriptors,讀到數(shù)據(jù)會(huì)進(jìn)入方法:-(void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
     for (CBCharacteristic *characteristic in service.characteristics){
         [peripheral discoverDescriptorsForCharacteristic:characteristic];
     }


 }

//獲取的charateristic的值
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    //打印出characteristic的UUID和值
    //!注意,value的類(lèi)型是NSData,具體開(kāi)發(fā)時(shí),會(huì)根據(jù)外設(shè)協(xié)議制定的方式去解析數(shù)據(jù)
    NSLog(@"characteristic uuid:%@  value:%@",characteristic.UUID,characteristic.value);

}

//搜索到Characteristic的Descriptors
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{

    //打印出Characteristic和他的Descriptors
     NSLog(@"characteristic uuid:%@",characteristic.UUID);
    for (CBDescriptor *d in characteristic.descriptors) {
        NSLog(@"Descriptor uuid:%@",d.UUID);
    }

}
//獲取到Descriptors的值
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error{
    //打印出DescriptorsUUID 和value
    //這個(gè)descriptor都是對(duì)于characteristic的描述,一般都是字符串,所以這里我們轉(zhuǎn)換成字符串去解析
    NSLog(@"characteristic uuid:%@  value:%@",[NSString stringWithFormat:@"%@",descriptor.UUID],descriptor.value);
}

把數(shù)據(jù)寫(xiě)到Characteristic中,??在寫(xiě)入的時(shí)候,必須要先寫(xiě)入與外設(shè)建立連接的值,只有建立了連接之后寫(xiě)入其他的值才能有反應(yīng)(ps:我被坑過(guò))

//寫(xiě)數(shù)據(jù)
-(void)writeCharacteristic:(CBPeripheral *)peripheral
            characteristic:(CBCharacteristic *)characteristic
                     value:(NSData *)value{

    //打印出 characteristic 的權(quán)限,可以看到有很多種,這是一個(gè)NS_OPTIONS,就是可以同時(shí)用于好幾個(gè)值,
    //常見(jiàn)的有read,write,notify,indicate,知知道這幾個(gè)基本就夠用了,前連個(gè)是讀寫(xiě)權(quán)限,后兩個(gè)都是通知,兩種不同的通知方式。
  /*
     CBCharacteristicPropertyBroadcast                                              
     CBCharacteristicPropertyRead                                                   
     CBCharacteristicPropertyWriteWithoutResponse                                   
     CBCharacteristicPropertyWrite                                                  
     CBCharacteristicPropertyNotify                                                 
     CBCharacteristicPropertyIndicate                                               
    CBCharacteristicPropertyAuthenticatedSignedWrites                               
     CBCharacteristicPropertyExtendedProperties                                     
     CBCharacteristicPropertyNotifyEncryptionRequired 
   CBCharacteristicPropertyIndicateEncryptionRequired 
  */
    NSLog(@"%lu", (unsigned long)characteristic.properties);

    //只有 characteristic.properties 有write的權(quán)限才可以寫(xiě)
    if(characteristic.properties & CBCharacteristicPropertyWrite){
        /*
            最好一個(gè)type參數(shù)可以為CBCharacteristicWriteWithResponse或type:CBCharacteristicWriteWithResponse,區(qū)別是是否會(huì)有反饋
        */
   [peripheral writeValue:value forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
    }else{
        NSLog(@"該字段不可寫(xiě)!");
    }

}

訂閱Characteristic的通知

//設(shè)置通知
-(void)notifyCharacteristic:(CBPeripheral *)peripheral
            characteristic:(CBCharacteristic *)characteristic{
    //設(shè)置通知,數(shù)據(jù)通知會(huì)進(jìn)入:didUpdateValueForCharacteristic方法
    [peripheral setNotifyValue:YES forCharacteristic:characteristic];

}

//取消通知
-(void)cancelNotifyCharacteristic:(CBPeripheral *)peripheral
             characteristic:(CBCharacteristic *)characteristic{

     [peripheral setNotifyValue:NO forCharacteristic:characteristic];
}

斷開(kāi)連接

//停止掃描并斷開(kāi)連接
-(void)disconnectPeripheral:(CBCentralManager *)centralManager
                 peripheral:(CBPeripheral *)peripheral{
    //停止掃描
    [centralManager stopScan];
    //斷開(kāi)連接
    [centralManager cancelPeripheralConnection:peripheral];
}

如何計(jì)算寫(xiě)入的值?

一下為模擬數(shù)據(jù),僅供參考,主要講的是計(jì)算思路
藍(lán)牙文檔如圖所示

屏幕快照 2016-07-30 下午11.25.32.png
屏幕快照 2016-07-30 下午11.32.45.png

按照文檔流程所示可以算出每一項(xiàng)功能所對(duì)應(yīng)的值以及手機(jī)端所接收到值對(duì)應(yīng)的功能
在這些值中其中校驗(yàn)碼的計(jì)算是需要自己計(jì)算一下的,計(jì)算的方法如下圖所示,現(xiàn)將16進(jìn)制轉(zhuǎn)化為2進(jìn)制,然后進(jìn)行異或運(yùn)算獲得

mmexport1469892606458.jpg

demo,在此

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,556評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事?!?“怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,463評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,009評(píng)論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,778評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,218評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,436評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,969評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,795評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,993評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,229評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,659評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,917評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,687評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,990評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容

  • Guide to BluetoothSecurity原文 本出版物可免費(fèi)從以下網(wǎng)址獲得:https://doi.o...
    公子小水閱讀 8,122評(píng)論 0 6
  • (一) iOS藍(lán)牙開(kāi)發(fā)藍(lán)牙相關(guān)基礎(chǔ)知識(shí) 藍(lán)牙常見(jiàn)名稱(chēng)和縮寫(xiě) MFI ======= make for ipad ...
    雷鳴1010閱讀 5,020評(píng)論 2 12
  • 藍(lán)牙 藍(lán)牙的波段為2400-2483.5MHz(包括防護(hù)頻帶)。這是全球范圍內(nèi)無(wú)需取得執(zhí)照(但定不是無(wú)管制的)的工...
    蘇永茂閱讀 6,257評(píng)論 0 11
  • 背景知識(shí) 藍(lán)牙技術(shù)最初由愛(ài)立信(也就是多年前手機(jī)做得最丑最奇葩的公司,最終被用戶(hù)以腳投票踢出市場(chǎng))創(chuàng)制。技術(shù)始于愛(ài)...
    梁睿坤閱讀 2,103評(píng)論 0 5
  • 那一刻 你的心里有一場(chǎng)海嘯 可你靜靜站著 沒(méi)有任何人知道
    鹿七_(dá)閱讀 272評(píng)論 0 0