iOS藍牙通信CoreBluetooth框架學習

最近學習藍牙熄捍,所以找了一些資料學習研究了一下藍牙通訊的一個流程。寫了一個小demo,demo效果見下圖:


設備a作為發(fā)送數據端荚孵,發(fā)送不同的數字
設備b作為接收數據端,接收到不同的數字

需要demo的朋友自行下載纬朝,如果有用处窥,請給star,謝謝

接下來我們講學習:

  • 基礎知識了解
  • app作為主設備,發(fā)送數據
  • app作為從設備玄组,接收數據

1.基礎知識了解

藍牙5.0是由藍牙技術聯(lián)盟在2016年提出的藍牙技術標準滔驾,藍牙5.0針對低功耗設備速度有相應提升和優(yōu)化,藍牙5.0結合wifi對室內位置進行輔助定位俄讹,提高傳輸速度哆致,增加有效工作距離。百度百科

我們在開發(fā)中要使用CoreBluetooth框架

我們先學習幾個概念:

service and characteristic 服務和特征

  • 每個設備都會提供服務和特征患膛,類似于服務端的api摊阀,但是由于結構不
    同,每個外設會有很多的服務,每個服務中又包含很多字段踪蹬,這些字段的權限一般分為 讀read胞此,寫write,通知notiy幾種跃捣,就是我們連接設備后具體需要操作的內容漱牵。
  • service是characteristic的集合
  • 一個characteristic包括一個單一變量和0-n個用來描述characteristic變量的descriptor奉芦,characteristic可以被認為是一個類型缩麸,類 似于類。

Description

每個characteristic可以對應一個或多個Description用戶描述characteristic的信息或屬性

CoreBluetooth框架

CoreBluetooth框架的核心其實是兩個東西全度,central和peripheral, 可以理解成中心和外設。對應他們分別有一組相關的API和類

兩種模式圖,左邊叫做中心模式,右邊稱為外設模式

外設-服務-特征

每個設備(CBPeripheral)都會有一些服務(CBService)闻镶,每個服務里面都會有一些特征(CBCharacteristic)甚脉,特征就是具體鍵值對,提供數據的地方铆农。每個特征屬性分為這么幾種:讀牺氨,寫,通知這么幾種方式

屬性列表

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
};

藍牙設備的幾種狀態(tài):

藍牙設備狀態(tài)圖.jpg

設備作為中心模式(central)流程:

中心模式流程圖.jpg

設備作為外設模式(peripheral)流程:

外設模式流程圖.jpg

2.app作為主設備墩剖,發(fā)送數據

注意:藍牙需要真機調試,所以必須要有真機

1) 導入 CoreBluetooth 框架,和頭文件

import <CoreBluetooth/CoreBluetooth.h>

兩個屬性:

 @property(nonatomic,strong)CBCentralManager *manager;//主設備
 @property(nonatomic,strong)NSMutableArray *peripherals;//被發(fā)現(xiàn)設備數組

初始化波闹,設置代理 CBCentralManagerDelegate

self.manager = [[CBCentralManager alloc]initWithDelegate:self queue:dispatch_get_main_queue()];
self.peripherals = @[].mutableCopy;

2) 實現(xiàn)CBCentralManagerDelegate相關的協(xié)議方法

a. 當設備開關藍牙 都會走這個回調
-(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");
                    //開始掃描周圍的外設
                    [manager scanForPeripheralsWithServices:nil options:nil];
 //參數可以添加一些option,來增加精確的查找范圍, 如 :
     //   NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                            //     [NSNumber numberWithBool:YES],       //CBCentralManagerScanOptionAllowDuplicatesKey,
                                // nil];
     //   [manager scanForPeripheralsWithServices:nil options:options];
 */
                    break;
                default:
                    break;
            }

        }
b. 掃描到設備會進入這個方法,并連接外設(connect)
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{
        NSLog(@"當掃描到設備:%@",peripheral.name);
        //接下來可以連接設備
  //這里自己去設置下連接規(guī)則,我設置的是nicolas開頭的設備
    if ([peripheral.name hasPrefix:@"nicolas"]){
    //找到的設備必須持有它涛碑,否則CBCentralManager中也不會保存peripheral精堕,那么CBPeripheralDelegate中的方法也不會被調用!蒲障!
        [self.peripherals addObject:peripheral];
                        //連接設備
        [self.manager connectPeripheral:peripheral options:nil];       
    }
  }
c. 連接外設(connect)后是否成功會進入下面的方法
 - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;//外設(Peripherals)連接成功的委托
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;//外設(Peripherals)連接失敗的委托
 - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;//斷開外設(Peripherals)的委托

3) 獲取外設的服務和特征

在設備連接成功后歹篓,我們需要設置外設Peripherals的委托(CBPeripheralDelegate),并開始獲取外設(Peripherals)的服務service和特征characteristic

CBPeripheralDelegate 的委托里包含了主設備與外設交互的許多 回調方法揉阎,包括獲取services庄撮,獲取characteristics,獲取characteristics的值毙籽,獲取characteristics的Descriptor洞斯,和Descriptor的值,寫數據坑赡,讀rssi烙如,用通知的方式訂閱數據等等。

 //連接到Peripherals-成功回調
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
        {   [peripheral setDelegate:self];
            [peripheral discoverServices:nil];
             // 獲取service時候也可以設置option   添加指定條件可以 提高效率如: 
            //    NSMutableArray *serviceUUIDs = [NSMutableArray array ];
//指定設備
          //    CBUUID *cbuuid = [CBUUID UUIDWithString:[NSString                  stringWithFormat:@"%x",Ble_Device_Service]];
           //    [serviceUUIDs addObject:cbuuid];
           //   [peripheral discoverServices:serviceUUIDs]; 

        }

掃描到服務services

  -(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
            if (error)
            {
               return;
            }
            for (CBService *service in peripheral.services) {
                  NSLog(@"%@",service.UUID);
             //掃描每個service的Characteristics
                  [peripheral discoverCharacteristics:nil forService:service];
              }
  }

掃描到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){
             {
         //獲取Characteristic的值
                 [peripheral readValueForCharacteristic:characteristic];
//讀到數據會進入方法:-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
             }
         }
         for (CBCharacteristic *characteristic in service.characteristics){
   //搜索Characteristic的Descriptors
             [peripheral discoverDescriptorsForCharacteristic:characteristic];
         }
     }

獲取的charateristic的值 (也就是從設備給主設備的通訊)

-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
        //打印出characteristic的UUID和值
        //!注意毅否,value的類型是NSData亚铁,具體開發(fā)時,會根據外設協(xié)議制定的方式去解析數據
        NSLog(@"characteristic uuid:%@  value:%@",characteristic.UUID,characteristic.value);
//主設備存從設備的設備與特征   
     if(characteristic.properties & CBCharacteristicPropertyWrite){
        if ([characteristic.UUID.UUIDString isEqual:@"FFF2"]) {
            self.cunPeripheral = peripheral;
            self.cunCBCharacteristic = characteristic;
        }
    }
    }

把數據寫到 Characteristic 中螟加,也就是發(fā)送數據
Byte b =0X01;
NSData *data = [NSData dataWithBytes:&b length:sizeof(b)];
[self writeCharacteristic:self.cunPeripheral characteristic:self.cunCBCharacteristic value:data];

-(void)writeCharacteristic:(CBPeripheral *)peripheral
                characteristic:(CBCharacteristic *)characteristic
                         value:(NSData *)value{
       //只有 characteristic.properties 有write的權限才可以寫
        if(characteristic.properties & CBCharacteristicPropertyWrite){
            [peripheral writeValue:value forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
        }else{
            NSLog(@"該字段不能寫徘溢!");
        }
    }

4) 訂閱Characteristic的通知

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

    }

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

         [peripheral setNotifyValue:NO forCharacteristic:characteristic];
    }

5) 斷開連接

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

3.app作為從設備捆探,接收數據

1) 初始化peripheralManager,設置peripheralManager的委托

self.peripheralManager = [[CBPeripheralManager alloc]initWithDelegate:self queue:nil];

2) 實現(xiàn)代理方法

創(chuàng)建characteristics 創(chuàng)建service然爆,把characteristics添加到service 然后把service添加到peripheralManager

 - (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{
  // 在這里判斷藍牙的狀態(tài), 因為藍牙打開成功后才能配置service和characteristics
  //具體配置代碼見demo
}

開啟廣播

//perihpheral添加了service
- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error{
    if (error == nil) {
        serviceNum++;
    }
    //因為我們添加了2個服務,所以想兩次都添加完成后才去發(fā)送廣播
    if (serviceNum==2) {
        [peripheralManager startAdvertising:@{
                                              CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:ServiceUUID1],[CBUUID UUIDWithString:ServiceUUID2]],
                                              CBAdvertisementDataLocalNameKey : LocalNameKey
                                     }
         ];
    }
}

處理收到的數據

//寫characteristics請求
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests{
    NSLog(@"didReceiveWriteRequests");
    CBATTRequest *request = requests[0];

    //判斷是否有寫數據的權限
    if (request.characteristic.properties & CBCharacteristicPropertyWrite) {
        //需要轉換成CBMutableCharacteristic對象才能進行寫值
        CBMutableCharacteristic *c =(CBMutableCharacteristic *)request.characteristic;
        c.value = request.value;
        [peripheralManager respondToRequest:request withResult:CBATTErrorSuccess];

         int i;
        [c.value getBytes:&i length:sizeof(i)];
        self.numberLabel.text = @(i).stringValue;
    }else{
        [peripheralManager respondToRequest:request withResult:CBATTErrorWriteNotPermitted];
    }
}

從設備還有一個需要每次接收到給主設備發(fā)送一個時間

藍牙學習就告一段落了黍图。
需要demo的朋友自行下載曾雕,如果有用,請給star,謝謝

直接用官方的框架寫還是比較麻煩的雌隅,這篇文章只做學習用翻默,現(xiàn)在其實有很多CoreBluetooth 的封裝,比如這個BabyBluetooth就很棒

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末恰起,一起剝皮案震驚了整個濱河市修械,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌检盼,老刑警劉巖肯污,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異吨枉,居然都是意外死亡蹦渣,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門貌亭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來柬唯,“玉大人,你說我怎么就攤上這事圃庭〕荩” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵剧腻,是天一觀的道長拘央。 經常有香客問我,道長书在,這世上最難降的妖魔是什么灰伟? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮儒旬,結果婚禮上栏账,老公的妹妹穿的比我還像新娘。我一直安慰自己栈源,他們只是感情好发笔,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著凉翻,像睡著了一般了讨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上制轰,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天前计,我揣著相機與錄音,去河邊找鬼垃杖。 笑死男杈,一個胖子當著我的面吹牛,可吹牛的內容都是我干的调俘。 我是一名探鬼主播伶棒,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼旺垒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了肤无?” 一聲冷哼從身側響起先蒋,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎宛渐,沒想到半個月后竞漾,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡窥翩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年业岁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寇蚊。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡笔时,死狀恐怖,靈堂內的尸體忽然破棺而出仗岸,到底是詐尸還是另有隱情糊闽,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布爹梁,位于F島的核電站右犹,受9級特大地震影響,放射性物質發(fā)生泄漏姚垃。R本人自食惡果不足惜念链,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望积糯。 院中可真熱鬧掂墓,春花似錦、人聲如沸看成。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽川慌。三九已至吃嘿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間梦重,已是汗流浹背兑燥。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留琴拧,地道東北人降瞳。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像蚓胸,于是被迫代替她去往敵國和親挣饥。 傳聞我的和親對象是個殘疾皇子除师,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內容

  • (一) iOS藍牙開發(fā)藍牙相關基礎知識 藍牙常見名稱和縮寫 MFI ======= make for ipad ...
    雷鳴1010閱讀 5,002評論 2 12
  • 本文主要以藍牙4.0做介紹,因為現(xiàn)在iOS能用的藍牙也就是只僅僅4.0的設備 用的庫就是core bluetoot...
    暮雨飛煙閱讀 840評論 0 2
  • 這里我們具體說明一下中心模式的應用場景。主設備(手機去掃描連接外設扔枫,發(fā)現(xiàn)外設服務和屬性汛聚,操作服務和屬性的應用。一般...
    丶逝水流年閱讀 2,263評論 3 4
  • 一般iOS開發(fā)者做APP開發(fā)大部分時候都是通過Http(s)請求跟后臺服務器打交道茧吊,做一些信息展示和用戶交互贞岭。很少...
    SunshineBrother閱讀 474評論 3 11
  • 目前在iOS中藍牙開發(fā)框架主要有以下幾種 GameKit.framework:iOS7之前的藍牙通訊框架八毯,從iOS...
    我系哆啦閱讀 5,960評論 27 24