1. 程式人生 > 程式設計 >iOS藍芽開發 藍芽連線和資料讀寫

iOS藍芽開發 藍芽連線和資料讀寫

在做藍芽開發之前,最好先了解一些概念:
服務(services):藍芽外設對外廣播的必定會有一個服務,可能也有多個,服務下面包含著一些特徵,服務可以理解成一個模組的視窗;
特徵(characteristic):存在於服務下面的,一個服務下面也可以存在多個特徵,特徵可以理解成具體實現功能的視窗,一般特徵都會有value,也就是特徵值,特徵是與外界互動的最小單位;
UUID:可以理解成藍芽上的唯一識別符號(硬體上肯定不是這個意思,但是這樣理解便於我們開發),為了區分不同的服務和特徵,或者給服務和特徵取名字,我們就用UUID來代表服務和特徵。

藍芽連線可以大致分為以下幾個步驟

1.建立一個Central Manager例項進行藍芽管理

2.搜尋外圍裝置
3.連線外圍裝置
4.獲得外圍裝置的服務
5.獲得服務的特徵
6.從外圍裝置讀資料
7.給外圍裝置傳送資料
其他:提醒

首先我們先匯入系統的BLE的框架
#import <CoreBluetooth/CoreBluetooth.h>

必須遵守2個協議
<CBCentralManagerDelegate,CBPeripheralDelegate>

/** 中心管理者 */
@property (nonatomic,strong) CBCentralManager *cMgr;

/** 連線到的外設 */
@property (nonatomic,strong) CBPeripheral *peripheral;

1.建立一個Central Manager例項進行藍芽管理

-(CBCentralManager *)cmgr
{
  if (!_cmgr) {
    _cMgr = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
  }
  return _cMgr;
}
 
//只要中心管理者初始化 就會觸發此代理方法 判斷手機藍芽狀態
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
  switch (central.state) {
    case 0:
      NSLog(@"CBCentralManagerStateUnknown");
      break;
    case 1:
      NSLog(@"CBCentralManagerStateResetting");
      break;
    case 2:
      NSLog(@"CBCentralManagerStateUnsupported");//不支援藍芽
      break;
    case 3:
      NSLog(@"CBCentralManagerStateUnauthorized");
      break;
    case 4:
    {
      NSLog(@"CBCentralManagerStatePoweredOff");//藍芽未開啟
    }
      break;
    case 5:
    {
      NSLog(@"CBCentralManagerStatePoweredOn");//藍芽已開啟
       // 在中心管理者成功開啟後再進行一些操作
      // 搜尋外設
      [self.cMgr scanForPeripheralsWithServices:nil // 通過某些服務篩選外設
                       options:nil]; // dict,條件
      // 搜尋成功之後,會呼叫我們找到外設的代理方法
      // - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI; //找到外設
    }
      break;
    default:
      break;
  }
}

2.搜尋外圍裝置 (我這裡為了舉例,採用了自己身邊的一個手環)

// 發現外設後呼叫的方法
- (void)centralManager:(CBCentralManager *)central // 中心管理者
 didDiscoverPeripheral:(CBPeripheral *)peripheral // 外設
   advertisementData:(NSDictionary *)advertisementData // 外設攜帶的資料
         RSSI:(NSNumber *)RSSI // 外設發出的藍芽訊號強度
{
  //NSLog(@"%s,line = %d,cetral = %@,peripheral = %@,advertisementData = %@,RSSI = %@",__FUNCTION__,__LINE__,central,peripheral,advertisementData,RSSI);
  
  /*
   peripheral = <CBPeripheral: 0x166668f0 identifier = C69010E7-EB75-E078-FFB4-421B4B951341,Name = "OBand-75",state = disconnected>,advertisementData = {
   kCBAdvDataChannel = 38;
   kCBAdvDataIsConnectable = 1;
   kCBAdvDataLocalName = OBand;
   kCBAdvDataManufacturerData = <4c69616e 0e060678 a5043853 75>;
   kCBAdvDataServiceUUIDs =   (
   FEE7
   );
   kCBAdvDataTxPowerLevel = 0;
   },RSSI = -55
   根據列印結果,我們可以得到運動手環它的名字叫 OBand-75
   
   */
  
  // 需要對連線到的外設進行過濾
  // 1.訊號強度(40以上才連線,80以上連線)
  // 2.通過裝置名(裝置字串字首是 OBand)
  // 在此時我們的過濾規則是:有OBand字首並且訊號強度大於35
  // 通過列印,我們知道RSSI一般是帶-的
  
  if ([peripheral.name hasPrefix:@"OBand"]) {
    // 在此處對我們的 advertisementData(外設攜帶的廣播資料) 進行一些處理
    
    // 通常通過過濾,我們會得到一些外設,然後將外設儲存到我們的可變陣列中,// 這裡由於附近只有1個運動手環,所以我們先按1個外設進行處理
    
    // 標記我們的外設,讓他的生命週期 = vc
    self.peripheral = peripheral;
    // 發現完之後就是進行連線
    [self.cMgr connectPeripheral:self.peripheral options:nil];
    NSLog(@"%s,line = %d",__LINE__);
  }
}

3.連線外圍裝置

// 中心管理者連線外設成功
- (void)centralManager:(CBCentralManager *)central // 中心管理者
 didConnectPeripheral:(CBPeripheral *)peripheral // 外設
{
  NSLog(@"%s,%@=連線成功",peripheral.name);
  // 連線成功之後,可以進行服務和特徵的發現
  
  // 設定外設的代理
  self.peripheral.delegate = self;
  
  // 外設發現服務,傳nil代表不過濾
  // 這裡會觸發外設的代理方法 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
  [self.peripheral discoverServices:nil];
}
// 外設連線失敗
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
  NSLog(@"%s,%@=連線失敗",peripheral.name);
}
 
// 丟失連線
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
  NSLog(@"%s,%@=斷開連線",peripheral.name);
}

4.獲得外圍裝置的服務 & 5.獲得服務的特徵

// 發現外設服務裡的特徵的時候呼叫的代理方法(這個是比較重要的方法,你在這裡可以通過事先知道UUID找到你需要的特徵,訂閱特徵,或者這裡寫入資料給特徵也可以)
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
  NSLog(@"%s,__LINE__);
  
  for (CBCharacteristic *cha in service.characteristics) {
    //NSLog(@"%s,char = %@",cha);
    
  }
}

5.從外圍裝置讀資料

// 更新特徵的value的時候會呼叫 (凡是從藍芽傳過來的資料都要經過這個回撥,簡單的說這個方法就是你拿資料的唯一方法) 你可以判斷是否
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
  NSLog(@"%s,__LINE__);
  if (characteristic == @"你要的特徵的UUID或者是你已經找到的特徵") {
  //characteristic.value就是你要的資料
  }
}

6.給外圍裝置傳送資料(也就是寫入資料到藍芽)

這個方法你可以放在button的響應裡面,也可以在找到特徵的時候就寫入,具體看你業務需求怎麼用啦

[self.peripherale writeValue:_batteryData forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];
//第一個引數是已連線的藍芽裝置 ;第二個引數是要寫入到哪個特徵; 第三個引數是通過此響應記錄是否成功寫入
// 需要注意的是特徵的屬性是否支援寫資料
- (void)yf_peripheral:(CBPeripheral *)peripheral didWriteData:(NSData *)data forCharacteristic:(nonnull CBCharacteristic *)characteristic
{
  /*
   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
   };
   
   打印出特徵的許可權(characteristic.properties),可以看到有很多種,這是一個NS_OPTIONS的列舉,可以是多個值
   常見的又read,write,noitfy,indicate.知道這幾個基本夠用了,前倆是讀寫許可權,後倆都是通知,倆不同的通知方式
   */
//  NSLog(@"%s,char.pro = %d",characteristic.properties);
  // 此時由於列舉屬性是NS_OPTIONS,所以一個列舉可能對應多個型別,所以判斷不能用 =,而應該用包含&
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。