藍(lán)牙開發(fā)隨記

1.概述

之前一直沒有接觸過藍(lán)牙開發(fā)褂删,最近公司需要使用藍(lán)牙傳輸饲握,從硬件設(shè)備同步數(shù)據(jù)到賬號(hào)里痕惋,借此記錄一下。
目前iOS中使用最多的藍(lán)牙開發(fā)庫(kù)是CoreBluetooth皆怕,它要求藍(lán)牙外設(shè)必須支持藍(lán)牙4.0及以上毅舆。藍(lán)牙4.0的特點(diǎn)是功耗低,所以也成為BLE4.0(Bluetooth Low Energy)愈腾,從iPhone4s開始支持憋活。
使用時(shí)需要引入頭文件import < CoreBluetooth/CoreBluetooth.h >。

2.CoreBluetooth介紹

使用 CoreBluetooth進(jìn)行藍(lán)牙開發(fā)主要用到的類虱黄,大約包含CBCentralManager(設(shè)備管理者)余掖、CBPeripheral(外設(shè)設(shè)備)、CBService(設(shè)備含有的服務(wù))礁鲁、CBCharacteristic(服務(wù)的特征值)幾大類盐欺。

藍(lán)牙的開發(fā)一般分為兩種模式:CBCentralMannager中心模式和CBPeripheralManager外設(shè)模式。

我們使用的是中心模式仅醇,外設(shè)模式也差不多類似冗美。這里主要說一下中心模式的開發(fā)流程:

  1. 創(chuàng)建中心設(shè)備管理實(shí)例

  2. 掃描外設(shè)

  3. 發(fā)現(xiàn)外設(shè)

  4. 根據(jù)相應(yīng)外設(shè)

  5. 掃描外設(shè)的服務(wù)

  6. 掃描外設(shè)服務(wù)中的特征值

  7. 訂閱特征的通知、讀取特征值數(shù)據(jù)

大致代碼流程:

1. 創(chuàng)建管理類
#import <CoreBluetooth/CoreBluetooth.h>

self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
2. 監(jiān)聽藍(lán)牙狀態(tài)析二、掃描外設(shè)
#pragma mark - CBCentralManagerDelegate

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

    switch (central.state) {
        case CBManagerStateUnknown:

            NSLog(@"CBManagerStateUnknown");
            break;

        case CBManagerStateResetting:

            NSLog(@"CBManagerStateResetting");
            break;

        case CBManagerStateUnsupported:

            NSLog(@"CBManagerStateUnsupported");
            break;

        case CBManagerStateUnauthorized:

            NSLog(@"CBManagerStateUnauthorized");
            break;

        case CBManagerStatePoweredOff:

            NSLog(@"CBManagerStatePoweredOff");
            break;

        case CBManagerStatePoweredOn: {

            NSLog(@"CBManagerStatePoweredOn");
            [self.centralManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey : @(YES)}];
            break;
        }

        default:

            break;

    }
} 
3. 發(fā)現(xiàn)外設(shè)粉洼、連接外設(shè)
#pragma mark - 掃描外設(shè)回調(diào)
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI {

    if ((!self.peripheral || self.peripheral.state == CBPeripheralStateDisconnected)
        &&([peripheral.name isEqualToString:@""])) { //想要連接的外設(shè)名稱

        self.peripheral = peripheral;
        // 鏈接外設(shè)
        [self.centralManager connectPeripheral:peripheral options:nil];

    }
}
4. 連接外設(shè)成功节预,發(fā)現(xiàn)外設(shè)服務(wù)
#pragma mark - 連接外設(shè)成功

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

    [central stopScan];
    [self.peripheral setDelegate:self];
    [peripheral discoverServices:nil];
}
#pragma mark - 連接外設(shè)失敗
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{

    NSLog(@"didFailToConnectPeripheral:%@", error);
}
5. 連接外設(shè)成功,發(fā)現(xiàn)外設(shè)服務(wù)
#pragma mark - 發(fā)現(xiàn)服務(wù)回調(diào)

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

    if (error || peripheral != self.peripheral) return;

    for (CBService *service in peripheral.services) {
        if (service.UUID isEqual:[CBUUID UUIDWithString:@""]) { // 需要使用的服務(wù)id
            [peripheral discoverCharacteristics:nil forService:service];
            return;
        }
    }
}

#pragma mark - 發(fā)現(xiàn)特征回調(diào)
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
        
    if (error || peripheral != self.peripheral) return;

    for (CBCharacteristic *characteristic in service.characteristics) {
        CBCharacteristicProperties p = characteristic.properties;
        if (p & CBCharacteristicPropertyIndicate && 
        [characteristic.UUID isEqual:[CBUUID UUIDWithString:@""]]) {//需要的通知特征id
            [peripheral setNotifyValue:YES forCharacteristic:characteristic];
        }
    }
}

#pragma mark - 特征值更新回調(diào)
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{

    if (error) {
        NSLog(@"didUpdateValueForCharacteristic error : %@", [error localizedDescription]);

    } else {
        NSLog(@"didUpdateValueForCharacteristic value : %@",characteristic.value);

    }
}

#pragma mark - 訂閱狀態(tài)更新回調(diào)

- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    
    if (error || peripheral != self.peripheral) return;

    if (characteristic.isNotifying) {
        NSLog(@"%@", characteristic);
    }
}
6. 寫入數(shù)據(jù)
- (void)writeValue {
    Byte byte = 0X01;
    NSData *data = [NSData dataWithBytes:&byte length:sizeof(byte)];
    [self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse]
}
7. 其他可能操作
#pragma mark - 斷開連接
- (void)disConnectPeripheral {
    [self.centralManager cancelPeripheralConnection:self.peripheral];
}

#pragma mark - 停止掃描外設(shè)
- (void)stopScanPeripheral{
    [self.centralManager stopScan];
}

3.坑點(diǎn)

  1. iOS不能直接寫入數(shù)據(jù)到client configuration descriptor, 使用setNotifyValue: forCharacteristic:方法替代即属韧。

    官方說明

  2. 外設(shè)的唯一標(biāo)志符:

    • mac地址
      官方API里面并沒有暴露外設(shè)的mac地址安拟,如果需要獲取mac地址,兩種方法:

      • 硬件設(shè)備的廣播里面添加mac地址信息宵喂,通過advertisementData獲取糠赦。
      • 把所有掃描到的外設(shè)設(shè)備,依次連接獲取mac地址锅棕,然后判斷是不是想要連接的設(shè)備(著實(shí)有些麻煩拙泽,所以最好讓硬件設(shè)備把數(shù)據(jù)放到廣播數(shù)據(jù)里)。
        參考 BluetoothMacAddressDemo
    • 設(shè)備名字唯一
      我們連接的硬件設(shè)備每臺(tái)設(shè)備的名稱都不會(huì)重復(fù)裸燎,可以直接使用這個(gè)來判斷顾瞻。

  1. 數(shù)據(jù)傳輸
    我們開發(fā)過程中,連接外設(shè)定閱成功之后德绿,但是并無數(shù)據(jù)返回荷荤,跟硬件方面溝通后,才知道設(shè)備只有在某些設(shè)備下才會(huì)傳輸數(shù)據(jù)移稳。藍(lán)牙開發(fā)跟硬件方面保持溝通很重要T棠伞!秒裕!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市钞啸,隨后出現(xiàn)的幾起案子几蜻,更是在濱河造成了極大的恐慌,老刑警劉巖体斩,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梭稚,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡絮吵,警方通過查閱死者的電腦和手機(jī)弧烤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蹬敲,“玉大人暇昂,你說我怎么就攤上這事“槲耍” “怎么了急波?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)瘪校。 經(jīng)常有香客問我澄暮,道長(zhǎng)名段,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任泣懊,我火速辦了婚禮伸辟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘馍刮。我一直安慰自己信夫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布渠退。 她就那樣靜靜地躺著忙迁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪碎乃。 梳的紋絲不亂的頭發(fā)上姊扔,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音梅誓,去河邊找鬼恰梢。 笑死,一個(gè)胖子當(dāng)著我的面吹牛梗掰,可吹牛的內(nèi)容都是我干的嵌言。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼及穗,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼摧茴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起埂陆,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤苛白,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后焚虱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體购裙,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年鹃栽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了躏率。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡民鼓,死狀恐怖薇芝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情丰嘉,我是刑警寧澤恩掷,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站供嚎,受9級(jí)特大地震影響黄娘,放射性物質(zhì)發(fā)生泄漏峭状。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一逼争、第九天 我趴在偏房一處隱蔽的房頂上張望优床。 院中可真熱鬧,春花似錦誓焦、人聲如沸胆敞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽移层。三九已至,卻和暖如春赫粥,著一層夾襖步出監(jiān)牢的瞬間观话,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工越平, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留频蛔,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓秦叛,卻偏偏與公主長(zhǎng)得像晦溪,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子挣跋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353