iOS藍牙開發


一、框架

基於 <CoreBluetooth/CoreBluetooth.h> 框架

不要試圖繼承CoreBluetooth中的任何類,因為重載會導致未知的結果

有兩種開發方案,一種是以本地作為中心設備,一種是已遠端設備作為中心設備

包含類

外圍設備:通常用於發布服務、生成數據、保存數據。外圍設備發布並廣播服務,告訴周圍的中央設備它的可用服務特征

中心設備:中心設備掃描到外圍設備后會視圖建立連接,連接成功后可用使用外圍設備的服務和特征

外圍設備中心設備直接交換的橋梁是服務(CBService)和特征(CBCharacteristic),二者都擁有一個唯一的標識(CBUUID)來確定唯一的服務和特征。每個服務可以有多個特征。

  • CBPeripheral 外圍設備

  • CBPeripheralManager 外圍設備管理類

  • CBMutableService 外圍設備的服務

  • CBMutableCharacteristic 外圍設備的特征

  • CBUUID 外圍設備服務特征的唯一標志

  • CBCentral 中心設備

  • CBCentralManager 中心設備管理類

  • CBService 外圍設備的服務

  • CBCharacteristic 外圍設備的特征

  • CBATTRequest 中心設備讀寫數據的請求

申請權限

iOS 10以后,所有的藍牙開發都要申請藍牙權限,在項目的info.plist中設置NSBluetoothPeripheralUsageDescription,對應的key為Privacy - Bluetooth Always Usage DescriptionPrivacy - Bluetooth Peripheral Usage Description

二、中心開發模式

以中心設備CBCentral作為本地,外網設備CBPeripheral作為遠端

初始化

// 初始化選項,設置YES時,如果用戶藍牙關閉,會彈出一個提示框
NSDictionary *options = @{CBCentralManagerOptionShowPowerAlertKey: @YES};

CBCentralManager* tM = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue() options:options];

self.cbcManager = tM;

掃描外圍設備

//判斷當前藍牙工作狀態是否開啟
if (self.cbcManager.state == CBManagerStatePoweredOn) {
    //記錄當前過濾條件
    self.fliterName = fliterName;
    //優先查找系統已經連接上的PV藍牙設備
    self.sysConnectArrs = [self.cbcManager retrieveConnectedPeripheralsWithServices:@[[CBUUID UUIDWithString:PVMG10BluetoothServiceUUID]]];
    for (CBPeripheral * cbp in self.sysConnectArrs) {
        [self centralManager:self.cbcManager didDiscoverPeripheral:cbp advertisementData:@{} RSSI:cbp.RSSI];
    }
    
    //開始搜索設備
    NSDictionary * option = @{
        // CBCentralManagerScanOptionAllowDuplicatesKey 指示是否過濾重復情況
        CBCentralManagerScanOptionAllowDuplicatesKey:[NSNumber numberWithBool:NO],
        // 藍牙未開啟情況下是否顯示提示框
        CBCentralManagerOptionShowPowerAlertKey:@0
    };
    
    // services和option都可以傳nil
    // services傳對應的UUIDstring則掃描指定id的設備
    [self.cbcManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:BluetoothServiceUUID]] options:option];
}
else{
    // TODO:返回藍牙未打開狀態
    
}

掃描結果回調

藍牙狀態監聽

- (void)centralManagerDidUpdateState:(nonnull CBCentralManager *)central {
    switch (central.state) {
        case CBManagerStateUnknown:
            NSLog(@">>>CBCentralManagerStateUnknown");
            break;
        case CBManagerStateResetting:
            NSLog(@">>>CBCentralManagerStateResetting");
            break;
        case CBManagerStateUnsupported:
            NSLog(@">>>CBCentralManagerStateUnsupported");
            break;
        case CBManagerStateUnauthorized:
            NSLog(@">>>CBCentralManagerStateUnauthorized");
            break;
        case CBManagerStatePoweredOff:
            NSLog(@">>>CBCentralManagerStatePoweredOff");
        {
            //手動斷開設備連接
            for (NSString * pcDeviceName in self.connectedDeviceMap) {
                PVBluetoothDevice * device = self.connectedDeviceMap[pcDeviceName];
                [self centralManager:self.cbcManager didDisconnectPeripheral:device.peripheral error:nil];
            }
        }
            break;
        case CBManagerStatePoweredOn:
        {
            NSLog(@">>>CBCentralManagerStatePoweredOn");
            
        }
            break;
        default:
            break;
    }
    if (self.delegate && [self.delegate respondsToSelector:@selector(pvBluetoothToolsUpdateManagerStaus:)]) {
        [self.delegate pvBluetoothToolsUpdateManagerStaus:central.state];
    }
}

發現設備回調

//搜索到設備
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{
    
    //通過名稱過濾設備是否為過濾設備
    for (NSString * fliter in self.fliterName) {
        if ([peripheral.name hasPrefix:fliter]) {
            [self.discoverDevices addObject:peripheral];
            
            //把系統掃描出來的一起回調
            [self.discoverDevices addObjectsFromArray:self.sysConnectArrs];
            if (self.delegate && [self.delegate respondsToSelector:@selector(pvBluetoothToolsUpdateSerchDevice:sysConnected:)]){
                //查看下新搜索出來的設備系統是不是已經連接了
                NSArray * sysconnectedDeviceArr = [self.cbcManager retrieveConnectedPeripheralsWithServices:@[[CBUUID UUIDWithString:PVMG10BluetoothServiceUUID]]];
                BOOL sysConnected = [sysconnectedDeviceArr containsObject:peripheral];
                [self.delegate pvBluetoothToolsUpdateSerchDevice:peripheral sysConnected:sysConnected];
            }
        }
    }
}

連接設備

//CBConnectPeripheralOptionNotifyOnConnectionKey 表示應用被掛起時,系統應該為給定的外設顯示警報
[self.cbcManager connectPeripheral:peripheral options:@{CBConnectPeripheralOptionNotifyOnConnectionKey:[NSNumber numberWithBool:YES]}];

連接結果回調

設備連接成功

//
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
    [self.connectedDeviceMap setObject:peripheral forKey:peripheral.name];
    
    //開始搜索服務
    [peripheral discoverServices:@[[CBUUID UUIDWithString:BluetoothUartServiceUUID]]];
}

連接失敗

//連接失敗
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
    
    NSLog(@"%@",error.localizedDescription);
}

連接斷開

-(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
    NSLog(@"設備斷開");
    [self.connectedDeviceMap removeObjectForKey:peripheral.name];
}

掃描外圍設備的服務

//  uuid需要約定好
[peripheral discoverServices:@[[CBUUID UUIDWithString:BluetoothUartServiceUUID]]];

掃描結果回調

//發現服務服務
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
    for (CBService * service in peripheral.services) {
        if ([service.UUID.UUIDString isEqualToString:BluetoothUartServiceUUID]) {//確定串口服務
            這里查找特征
        }
    }

查詢服務的特征

//開始查找特征
[peripheral discoverCharacteristics:NULL forService:service];

發現服務特征回調

//發現特征
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
    for (CBCharacteristic *characteristic in service.characteristics) {
        // 遍歷獲取對應的特征值
        // 獲取約定的發送特征
        if ([characteristic.UUID.UUIDString isEqualToString:BluetoothSendcharacteristicUUID]) {
            BluetoothDevice * device = self.connectedDeviceMap[peripheral.name];
            device.sendCharacteristic = characteristic;
        }
        // 獲取約定的接收特征
        else if ([characteristic.UUID.UUIDString isEqualToString:BluetoothReceivedcharacteristicUUID]){
            BluetoothDevice * device = self.connectedDeviceMap[peripheral.name];
            device.receivedCharacteristic = characteristic;
            [device.peripheral setNotifyValue:YES forCharacteristic:characteristic];
        }
        
        /**a
         -- 當發現characteristic有descriptor,回調didDiscoverDescriptorsForCharacteristic
         */
        [peripheral discoverDescriptorsForCharacteristic:characteristic];
    }
}

注冊特征

// 注冊了特征值后,就可以通過特征值來讀取數據了。
[peripheral setNotifyValue:YES forCharacteristic:characteristic];

特征注冊結果回調

- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error;

通過特征讀取數據

//收到數據
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    NSLog(@"%@",characteristic.value);
    if (self.delegate && [self.delegate respondsToSelector:@selector(pvBluetoothToolsReceiveData:)]) {
        [self.delegate pvBluetoothToolsReceiveData:characteristic.value];
    }
}

通過特征發送數據

type有兩個值:

  • CBCharacteristicWriteWithResponse 需要返回發送數據的結果
  • CBCharacteristicWriteWithoutResponse 不需要返回發送數據的結果
[device.peripheral writeValue:data forCharacteristic:device.sendCharacteristic type:CBCharacteristicWriteWithoutResponse];

發送數據結果回調

如果需要返回發送結果,會調用當前回調

- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    NSLog(@"數據發送成功");
}

關閉藍牙設備

- (void)closeBlueTooth {
    //停止掃描
    [self.centralManager stopScan];
    if (self.peripheral) {
        //斷開當前的連接
        [self.centralManager cancelPeripheralConnection:self.peripheral];
    }
    self.centralManager = nil;
    self.peripheral = nil;
    self.characteristic = nil;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM