iOS 藍牙4.0開發使用
嗨大家好,我是iOS開發一枚大帥比,過去的幾年項目涉及到藍牙比較多,抽空之余,把使用的小知識點歸納起來,一是方便自己對知識做很好的總結和復習,二是希望能幫助到瑯琊開發的朋友們。
一、簡介(什么是BLE4.0?哪里使用它?)
現在的互聯網時代,智能硬件設備越來越多樣化,這些設備中,有多是通過手機來控制硬件設備,來達到控制的效果,這中間少不了要使用到藍牙功能,通過藍牙來通信來控制設備。也就是我們說的“設備中心和外設的故事”。
藍牙版本介紹:
每個人對于藍牙都不陌生,近距離數據傳輸,方便;可是當你的業務需求需要你第一次接觸藍牙開發的時候,卻會發現你對它并不了解;首先,藍牙發展至今經歷了8個版本的更新。1.1、1.2、2.0、2.1、3.0、4.0、4.1、4.2。那么在1.x~3.0之間的我們稱之為傳統藍牙,4.x開始的藍牙我們稱之為低功耗藍牙也就是藍牙ble,當然4.x版本的藍牙也是向下兼容的。android手機必須系統版本4.3及以上才支持BLE API。低功耗藍牙較傳統藍牙,傳輸速度更快,覆蓋范圍更廣,安全性更高,延遲更短,耗電極低等等優點。(現在的穿戴設備都是使用BLE藍牙技術的)
傳統藍牙與低功耗藍牙通信方式也有所不同,傳統的一般通過socket方式,而低功耗藍牙是通過Gatt協議來實現。
本文章目的便是介紹BLE 4.0的使用以及相關問題的解決,本文采用簡要模式介紹BLE4.0的核心類的使用以及藍牙開發的簡介,如需了解藍牙知識的詳細知識點,百度可搜索其他大神的文章進行學習,下文通用BLE代為藍牙4.0。
二、BLE的核心模式
BLE的兩種模式分為CBCentralMannager 中心模式 和CBPeripheralManager 外設模式,在這里主要和大家分享CBCentralMannager 中心模式的開發和使用。
CBCentralMannager 中心模式
以手機(app)作為設備中心,連接其他外設(硬件)的場景。詳細流程如下:
1、建立中心角色
2、掃描外設
3、發現外設
4、連接外設:
? ? 1.連接失敗
? ? 2. 連接斷開
? ? 3.連接成功
5、掃描外設中的服務
? ? 1.發現并獲取外設中的服務Service
6、掃描外設對應服務的特征
? ? 1.發現并獲取外設對應服務的特征Characteristic
? ? 2.給對應特征寫數據
? ? 3.訂閱特征的通知 7.1 根據特征讀取數據
說明:Service,Characteristic是每個硬件設備出廠設定的設備服務和特征值,用UUID作為唯一標識符。UUID為這種格式:0000ffe1-0000-1000-8000-00805f9b34fb。比如有3個Service,那么就有三個不同的UUID與Service對應。這些UUID都寫在硬件里,我們通過BLE提供的API可以讀取到,一個BLE終端可以包含多個Service, 一個Service可以包含多個Characteristic,一個Characteristic包含一個value和多個Descriptor,一個Descriptor包含一個Value。Characteristic是比較重要的,是手機與BLE終端交換數據的關鍵,讀取設置數據等操作都是操作Characteristic的相關屬性。說白了,我們可以把每個服務特征值看成是我們網絡請求的api接口,我們和藍牙的交互,是要連接到對應的service和對應的Characteristic才可以正確讀取到和硬件文檔以及出廠定制好的服務和數據。
三、CBPeriphera
暫且把這個小可愛理解為你所能發現搜索到的外設(硬件)對象,藍牙硬件的信息都包含在它里面
下面我們看下這個類所包含的內容:
CB_EXTERN_CLASS @interface CBPeripheral : CBPeer
//代理
@property(weak, nonatomic, nullable) id<CBPeripheralDelegate> delegate;
//我們所能搜索到的外設名稱
@property(retain, readonly, nullable) NSString *name;
//信號強度
@property(retain, readonly, nullable) NSNumber *RSSI;
//設備狀態,包含以下4種狀態
@property(readonly) CBPeripheralState state;
typedef NS_ENUM(NSInteger, CBPeripheralState) {
CBPeripheralStateDisconnected = 0,
CBPeripheralStateConnecting,
CBPeripheralStateConnected,
CBPeripheralStateDisconnecting
}
//服務群組
@property(retain, readonly, nullable) NSArray<CBService *> *services;
由于函數和屬性太多,我只列舉主要的幾個,其他的可在代碼中點擊查看即可
四、使用步驟概要
1、導入:#import <CoreBluetooth/CoreBluetooth.h>
2、遵守CBCentralManagerDelegate,CBPeripheralDelegate協議
3、初始化中心Manager,創建中心角色
為了方便引用,一般把manager聲明為一個屬性對象:
@property (nonatomic, strong) CBCentralManager * centralManager;
?self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
注:queue為你想把藍牙初始化放到哪個隊列,一般默認主隊列
? ? ? ? options傳nil即可,具體使用可查看策略含義
4、檢查當前設備中心的藍牙狀態
// 狀態更新時調用
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
? ? switch (central.state) {
? ? ? ? case CBManagerStateUnknown:{
? ? ? ? ? ? NSLog(@"為知狀態");
? ? ? ? ? ? self.peripheralState = central.state;
? ? ? ? }
? ? ? ? ? ? break;
? ? ? ? case CBManagerStateResetting:
? ? ? ? {
? ? ? ? ? ? NSLog(@"重置狀態");
? ? ? ? ? ? self.peripheralState = central.state;
? ? ? ? }
? ? ? ? ? ? break;
? ? ? ? case CBManagerStateUnsupported:
? ? ? ? {
? ? ? ? ? ? NSLog(@"不支持的狀態");
? ? ? ? ? ? self.peripheralState = central.state;
? ? ? ? }
? ? ? ? ? ? break;
? ? ? ? case CBManagerStateUnauthorized:
? ? ? ? {
? ? ? ? ? ? NSLog(@"未授權的狀態");
? ? ? ? ? ? self.peripheralState = central.state;
? ? ? ? }
? ? ? ? ? ? break;
? ? ? ? case CBManagerStatePoweredOff:
? ? ? ? {
? ? ? ? ? ? NSLog(@"關閉狀態");
? ? ? ? ? ? self.peripheralState = central.state;
? ? ? ? }
? ? ? ? ? ? break;
? ? ? ? case CBManagerStatePoweredOn:
? ? ? ? {
? ? ? ? ? ? NSLog(@"開啟狀態-可用狀態");
? ? ? ? ? ? self.peripheralState = central.state;
? ? ? ? ? ? NSLog(@"%ld",(long)self.peripheralState);
? ? ? ? }
? ? ? ? ? ? break;
? ? ? ? default:
? ? ? ? ? ? break;
? ? }
}
5、開始掃描
if (self.peripheralState == CBManagerStatePoweredOn){
[self.centralManager scanForPeripheralsWithServices:nil options:nil];
}
6、發現外設
/**
掃描到設備
@param central 中心管理者
@param peripheral 掃描到的設備
@param advertisementData 廣告信息
@param RSSI 信號強度
*/
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI
{
? ? NSLog(@"%@",[NSString stringWithFormat:@"發現設備,設備名:%@",peripheral.name]);
}
7、連接外設
[self.centralManager connectPeripheral:peripheral options:nil];
? ? ? 連接狀態
/**
@param central 中心管理者
@param peripheral 連接失敗的設備
@param error 錯誤信息
*/
**?連接失敗 **
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
? ? NSLog(@"%@",@"連接失敗");
}
** 連接斷開 **
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {?
NSLog(@"%@",@"斷開連接");
?}
** 連接成功 **?
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {?
NSLog(@"連接設備:%@成功",peripheral.name);
?[self.centralManager stopScan];?
}
8、掃描外設服務Service
// 設置設備的代理
peripheral.delegate = self;
// services:傳入nil? 代表掃描所有服務
[peripheral discoverServices:nil];
/**
掃描到服務
@param peripheral 服務對應的設備
@param error 掃描錯誤信息
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
? ? // 遍歷所有的服務
? ? for (CBService *service in peripheral.services)
? ? {
? ? ? ? NSLog(@"服務:%@",service.UUID.UUIDString);
? ? }
}
9、掃描service特征值
kWriteServerUUID 為和廠家協定好的,
例:讀取電量的UUID:08B07DCB-13DD-435C-8BDA-04DA65BDC6AA
// 獲取對應的服務
? ? ? ? if (![service.UUID.UUIDString isEqualToString:kWriteServerUUID])
? ? ? ? {
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? // 根據服務去掃描特征
? ? ? ? [peripheral discoverCharacteristics:nil forService:service];
10、給特征值寫數據(就是發送指令)
[peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
11、訂閱特征值通知(訂閱后可收到回應的數據)
if ([characteristic.UUID.UUIDString isEqualToString:kNotifyCharacteristicUUID]){
? [peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
12、根據特征值讀取數據(注:應把之前發送數據和訂閱通知的peripheral和characteristic定義為全局屬性)
*該處即為接收到外設發送的數據的方法
/**
根據特征讀到數據
@param peripheral 讀取到數據對應的設備
@param characteristic 特征
@param error 錯誤信息
*/
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error
{
? ? if ([characteristic.UUID.UUIDString isEqualToString:kNotifyCharacteristicUUID])
? ? {
? ? ? ? NSData *data = characteristic.value;
? ? ? ? NSLog(@"%@",data);
? ? }
}
到這里,整個藍牙使用的核心流程就基本介紹完了,鑒于寫博客文章太累,太耗時,我決定先睡覺去,回頭把文章慢慢細化一下,查漏補缺,格式可能也不是很完美,請讀者們見諒,多提寶貴意見,喜歡的老鐵們,可以點下喜歡或者收藏!
打個廣告
本人github地址:shLuckySeven
歡迎去點star