iOS 藍牙開發(fā)

前言:此篇文章只針對第一次接觸藍牙的小白,文章中僅僅描述了如何連接藍牙、如何發(fā)送數(shù)據(jù) 、可能遇到的問題 等。對于其他專業(yè)性的名詞沒有做相應(yīng)的描述。

一、準(zhǔn)備工作
1、iOS使用藍牙 必須先允許定位,所以需要開啟定位。使用藍牙需要用戶同意才可使用 所以 工程info.plist 文件中需要添加 定位請求和藍牙請求的權(quán)限

定位權(quán)限
Privacy - Location When In Use Usage Description 

藍牙權(quán)限
Privacy - Bluetooth Peripheral Usage Description

2、使用藍牙首先要準(zhǔn)備幾個UUID

服務(wù)UUID
#define BLE_SERVICE_UUID   @"0000XXXX-0000-1000-8000-00805f9b34fb"

讀UUID
#define BLE_INDICATE_CHARACTERISTIC_UUID   @"0000XXXX-0000-1000-8000-00805f9b34fb"

寫UUID
#define BLE_WRITE_CHARACTERISTIC_UUID   @"0000XXXX-0000-1000-8000-00805f9b34fb"

這幾個UUID開發(fā)硬件的工程師會直接給你。作用后面會有所體驗

二、設(shè)置相關(guān)代碼

1、首先引入藍牙和定位所需框架

#import <SystemConfiguration/CaptiveNetwork.h>
#import <CoreLocation/CoreLocation.h>
#import <CoreBluetooth/CoreBluetooth.h>

2、其次引入代理

CBCentralManagerDelegate
CBPeripheralDelegate

3、然后聲明屬性

@property (nonatomic, strong) CBCentralManager  * bluetoothManager;
@property (nonatomic, strong) CLLocationManager * locationManager;
@property (nonatomic, strong) CBPeripheral      * currentPer;

4、設(shè)置定位

- (void)location {
    NSString* phoneVersion = [[UIDevice currentDevice] systemVersion];
    CGFloat version = [phoneVersion floatValue];
    // 如果是iOS13 未開啟地理位置權(quán)限 需要提示一下
    if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined && version >= 13) {
      self.locationManager = [[CLLocationManager alloc] init];
      [self.locationManager requestWhenInUseAuthorization];
    }
}

重點來了,以下代碼是藍牙相關(guān)的代碼

1、初始化 CBCentralManager

#pragma mark--  CBCentralManager的實例對象
- (void)initCBCentralManager{
    NSDictionary *options = @{CBCentralManagerOptionShowPowerAlertKey: @YES};
    CBCentralManager* cBCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:options];
    self.bluetoothManager = cBCentralManager;
}

2、 CBCentralManagerDelegate回調(diào):返回藍牙的狀態(tài) 在此函數(shù)中可以提醒用戶打開藍牙等操作

#pragma mark--  CBCentralManagerDelegate回調(diào):(開啟/關(guān)閉藍牙,也就是藍牙的狀態(tài))
- (void)centralManagerDidUpdateState:(CBCentralManager*)central{
    if (central.state == CBCentralManagerStatePoweredOn) {
        NSLog(@"藍牙已經(jīng)打開");
    } else if (central.state == CBManagerStatePoweredOff) {
        NSLog(@"藍牙已經(jīng)關(guān)閉");
    }
}

3、開始掃描藍牙設(shè)備

#pragma  mark-- 開始掃描設(shè)備(也就是開始掃描藍牙)
- (void)scanDevice{
    [self.bluetoothManager scanForPeripheralsWithServices:nil options:nil];
}

4、藍牙設(shè)備掃描結(jié)果回調(diào):在此方法中找到你想要連接的藍牙設(shè)備然后去連接設(shè)備

#pragma mark--  CBCentralManagerDelegate回調(diào):藍牙搜索結(jié)果回調(diào)
- (void)centralManager:(CBCentralManager*)central didDiscoverPeripheral:(CBPeripheral*)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber*)RSSI{
    NSString *scanedName=advertisementData[@"kCBAdvDataLocalName"];
    if (scanedName.length>0) {
        NSLog(@"掃描到設(shè)備scanedName=:%@",scanedName);
    }
    if ([scanedName hasPrefix:@"aux-5802"]) {
        self.currentPer = peripheral;
        // 發(fā)現(xiàn)設(shè)備后,請求連接設(shè)備
        [self connectedDevices];
    }
}


#pragma mark-- 開始連接設(shè)備:
- (void)connectedDevices{
    [self.bluetoothManager connectPeripheral:self.currentPer options:nil];
}

5、連接狀態(tài)回調(diào)

#pragma mark-- 鏈接狀態(tài)回調(diào)
///連接成功
- (void)centralManager:(CBCentralManager*)central didConnectPeripheral:(CBPeripheral*)peripheral{
    NSLog(@"連接成功");
    //連接成功停止搜索
    [self.bluetoothManager stopScan];

    self.currentPer = peripheral;

//連接成功后,掃描外圍設(shè)備的服務(wù)CBService:
  [self scanDeviceCBService];
    
}

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

///斷開連接結(jié)果
- (void)centralManager:(CBCentralManager*)central didDisconnectPeripheral:(CBPeripheral*)peripheral error:(NSError*)error{
    NSLog(@"斷開鏈接");
}


#pragma mark-- 連接成功后,掃描外圍設(shè)備的服務(wù)CBService:
- (void)scanDeviceCBService{
    self.currentPer.delegate = self;
    [ self.currentPer discoverServices:@[[CBUUID UUIDWithString:BLE_SERVICE_UUID]]];
}

6、 掃描服務(wù)結(jié)果會通過CBPeripheralDelegate回調(diào) 返回

#pragma mark-- 掃描服務(wù)結(jié)果會通過CBPeripheralDelegate回調(diào):
- (void)peripheral:(CBPeripheral*)peripheral didDiscoverServices:(NSError*)error{
    for (CBService *service in peripheral.services) {
        if ([service.UUID isEqual:[CBUUID UUIDWithString:BLE_SERVICE_UUID]]) {
            //查找特征
            [self.currentPer discoverCharacteristics:nil forService:service];
        }
    }
}

7、查詢特征結(jié)果會通過CBPeripheralDelegate回調(diào):返回

#pragma mark--查詢特征結(jié)果會通過CBPeripheralDelegate回調(diào):
-(void)peripheral:(CBPeripheral*)peripheral didDiscoverCharacteristicsForService:(CBService*)service error:(NSError*)error{
    for (CBCharacteristic *character in service.characteristics) {
        NSLog(@"%@",character);
      
        if ([character.UUID isEqual:[CBUUID UUIDWithString:BLE_WRITE_CHARACTERISTIC_UUID]]) { 
  // 寫

//注意:1、這里的 writeValue: 傳的是一個NSData類型的數(shù)據(jù) 這個數(shù)據(jù)硬件需要什么 你傳什么就可以了。

//注意:2、這里的 type :你需要查看硬件給你返回的什么類型然后你填什么類型就可以了,這個類型可以打印 character 查看他的 properties屬性  如果硬件返回的是 0x04(CBCharacteristicPropertyWriteWithoutResponse) 那你就需要填寫對應(yīng)的(CBCharacteristicWriteWithoutResponse)即可,切記這一點 否則會報 讀或?qū)憶]有權(quán)限的 問題
            [self.currentPer writeValue:   data forCharacteristic:character type:CBCharacteristicWriteWithoutResponse];
        }else if ([character.UUID isEqual:[CBUUID UUIDWithString:BLE_INDICATE_CHARACTERISTIC_UUID]]) {
  // 讀
            [self.currentPer setNotifyValue:YES forCharacteristic:character];
        }
    }   
}

8、特征的數(shù)據(jù)也是通過CBPeripheralDelegate回調(diào)

#pragma mark-- 特征的數(shù)據(jù)也是通過CBPeripheralDelegate回調(diào):
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    NSLog(@"peripheral:%@ \n\n characteristic:%@ \n\n error:%@",peripheral, characteristic, error);
    [peripheral readValueForCharacteristic:characteristic];
}

9、藍牙返回數(shù)據(jù) 代理方法 :這里可能會出現(xiàn) Reading is not permitted 或則 Writing is not permitted 出現(xiàn)這個 問題不要著急 首先檢查 硬件給你的 讀寫UUID是否正確 如果正確 再次檢查 第七步 ( [self.currentPer writeValue: data forCharacteristic:character type:CBCharacteristicWriteWithoutResponse]; )中的 type是否與硬件返回的一致 確保這兩點基本沒有什么問題了

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    if (error) {
        NSLog(@"%@",error);
    } else {
        NSData *responseData = characteristic.value;
        NSLog(@"%@",responseData);

//注意:藍牙返回的也是 NSData類型的數(shù)據(jù) 拿到數(shù)據(jù)解析數(shù)據(jù)就就可以了
        [self auxCmdParse:responseData];//這一步是解析數(shù)據(jù)
    }
}

補充:
向藍牙發(fā)送數(shù)據(jù)包(數(shù)據(jù)包的格式跟硬件協(xié)商好)

- (NSData*)getData{
    NSString *ssid = self.ssid;
    NSString *key= self.password;
    NSString *paas_address= self.paas_address;
    NSString *m2m_address= self.m2m_address;
    NSString *apCode= self.apCode;;
    NSMutableData *allMData = [[NSMutableData alloc] init];
    NSData *ssidData = [ssid dataUsingEncoding: NSUTF8StringEncoding];
    NSData *keyData = [key dataUsingEncoding: NSUTF8StringEncoding];
    NSData *paas_addressData = [paas_address dataUsingEncoding:NSUTF8StringEncoding];
    NSData *m2m_addressData = [m2m_address dataUsingEncoding:NSUTF8StringEncoding];
    NSData *apcodeData = [apCode dataUsingEncoding:NSUTF8StringEncoding];
    unsigned long length = 8+(ssidData.length)+(keyData.length)+(apcodeData.length)+(m2m_addressData.length)+(paas_addressData.length)+7;
    
    Byte bhead[]= {0xa5, 0xa5, length & 0xFF, 0x00, 0x01, 0x00, 0x00,0x00};
    
    [allMData appendBytes:bhead length:8];
    Byte blen[]= {ssidData.length & 0xFF};
    [allMData appendBytes:blen length:1];
    if (blen[0]>0){
        [allMData appendBytes:[ssidData bytes] length:blen[0]];
    }
    //    //
    blen[0]= keyData.length & 0xFF;
    [allMData appendBytes:blen length:1];
    if (blen[0]>0){
        [allMData appendBytes:[keyData bytes] length:blen[0]];
    }
    
    
    blen[0]= apcodeData.length & 0xFF;
    [allMData appendBytes:blen length:1];
    if (blen[0]>0){
        [allMData appendBytes:[apcodeData bytes] length:blen[0]];
    }
    
    //    //
    blen[0]= paas_addressData.length & 0xFF;
    [allMData appendBytes:blen length:1];
    if (blen[0]>0){
        [allMData appendBytes:[paas_addressData bytes] length:blen[0]];
    }
    //
    //
    blen[0]= m2m_addressData.length & 0xFF;
    [allMData appendBytes:blen length:1];
    if (blen[0]>0){
        [allMData appendBytes:[m2m_addressData bytes] length:blen[0]];
    }
    
    
    
    int crc= [CRC crc16CCIT:allMData andLen:(int)allMData.length];
    Byte bcrc[]= {(crc>>8)&0x0ff, crc&0x0ff};
    [allMData appendBytes:bcrc length:2];
    
    return allMData;
}

接收藍牙發(fā)來的數(shù)據(jù)包(按照規(guī)定的順序解包)

- (Boolean)cmdParse:(NSData *)data{
    Byte *b= (Byte *)[data bytes];
    if (b[0]== 0xa5 && b[1]== 0xa5
        && b[4]== 0x01 && b[5]== 0x10
        && b[6]== 0x00 && b[7]== 0x00
        && b[8]== 0x00 && b[9]== 0x00){
        int crcCal= [CRC crc16CCIT:data andLen:(int)data.length-2];
        int crcRcv= ((b[data.length-2] & 0x0ff) << 8) | (b[data.length-1] & 0x0ff);
        if (crcCal == crcRcv){
            _auxRplMac= [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X", b[11], b[12], b[13], b[14], b[15], b[16]];
            _auxRplPasscode= [self toHexString:b start:18 Len:b[17]];
            NSLog(@"%@",_auxRplMac);
            NSLog(@"%@",_auxRplPasscode);
            return true;
        }
    }
    return false;
}

- (NSString *)toHexString:(Byte *)b start:(int)start Len:(int)len{
    NSString *str= @"";
    for (int i=0; i<len; i++){
        str= [NSString stringWithFormat:@"%@%02X", str, b[start+i]];
    }
    return str;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 首先先明白幾個名詞:Central(中心設(shè)備)、Peripheral(外圍設(shè)備)、advertising(廣告)、...
    shuaikun閱讀 496評論 0 0
  • iOS的藍牙數(shù)據(jù)接收以及發(fā)送 名詞:Central(中心設(shè)備)、Peripheral(外圍設(shè)備)、advertis...
    TianBai閱讀 22,719評論 54 303
  • iOS 中使用 Core Bluetooth 框架實現(xiàn)藍牙通信。Core Bluetooth 是基于藍牙 4.0 ...
    歐大帥Allen閱讀 2,878評論 0 3
  • 相比于網(wǎng)絡(luò)請求,藍牙是一種低功耗(low-energy)的通信手段。目前iOS的開發(fā)都是針對CoreBluetoo...
    huxinwen閱讀 10,724評論 0 11
  • 夜鶯2517閱讀 128,087評論 1 9

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