藍(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ā)跟硬件方面保持溝通很重要!?。?/li>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容