背景:
最近公司項(xiàng)目需要接運(yùn)動(dòng)手環(huán)殴玛,獲取運(yùn)動(dòng)步數(shù),設(shè)備時(shí)間翘地,重置設(shè)備時(shí)間等功能申尤,需要進(jìn)行藍(lán)牙傳輸。
前言:
1.當(dāng)前iOS中開發(fā)藍(lán)牙所運(yùn)用的系統(tǒng)庫是<CoreBluetooth/CoreBluetooth.h>衙耕。
2.藍(lán)牙外設(shè)必須為4.0及以上昧穿,否則無法開發(fā),藍(lán)牙4.0設(shè)備因?yàn)榈秃碾姵艚埽砸步凶鯞LE粤咪。
3.CoreBluetooth框架的核心其實(shí)是兩個(gè)東西,peripheral和central, 可以理解成外設(shè)和中心渴杆,就是你的蘋果手機(jī)就是中心,外部藍(lán)牙稱為外設(shè)宪塔。
4.服務(wù)和特征(service and characteristic):簡而言之磁奖,外部藍(lán)牙中它有若干個(gè)服務(wù)service(服務(wù)你可以理解為藍(lán)牙所擁有的能力),而每個(gè)服務(wù)service下?lián)碛腥舾蓚€(gè)特征characteristic(特征你可以理解為解釋這個(gè)服務(wù)的屬性)某筐。
5.Descriptor(描述)用來描述characteristic變量的屬性比搭。例如,一個(gè)descriptor可以規(guī)定一個(gè)可讀的描述南誊,或者一個(gè)characteristic變量可接受的范圍身诺,或者一個(gè)characteristic變量特定的單位蜜托。
圖示
名詞解釋:
BLE:(Bluetooth low energy)藍(lán)牙4.0設(shè)備因?yàn)榈秃碾姡?/p>
Central:中心設(shè)備,相對(duì)比較強(qiáng)大霉赡,用來連接其他外圍設(shè)備(手機(jī))橄务;
Peripheral:外圍設(shè)備,這一般就是非常小或者簡單的低功耗設(shè)備穴亏,用來提供數(shù)據(jù)蜂挪,并連接到一個(gè)更加相對(duì)強(qiáng)大的中心設(shè)備(小米手環(huán)等等等);
Services:服務(wù)嗓化,藍(lán)牙外設(shè)對(duì)外廣播的必定會(huì)有一個(gè)服務(wù)棠涮,可能也有多個(gè),服務(wù)下面包含著一些特征刺覆,服務(wù)可以理解成一個(gè)模塊的窗口严肪;
Characteristic:特征,存在于服務(wù)下面的谦屑,一個(gè)服務(wù)下面也可以存在多個(gè)特征驳糯,特征可以理解成具體實(shí)現(xiàn)功能的窗口,一般特征都會(huì)有value伦仍,也就是特征值结窘,特征是與外界交互的最小單位;
Description:描述充蓝,每個(gè)Characteristic可以對(duì)應(yīng)一個(gè)或多個(gè)Description用于描述Characteristic的信息或?qū)傩裕〞簳r(shí)不太了解)
UUID:可以理解成藍(lán)牙上的唯一標(biāo)識(shí)符(硬件上是Mac值隧枫,iOS應(yīng)該是被系統(tǒng)攔截了,所以獲取不到Mac值谓苟,相對(duì)于轉(zhuǎn)化而來是的UUID)官脓,為了區(qū)分不同的服務(wù)和特征,或者給服務(wù)和特征取名字涝焙,我們就用UUID來代表服務(wù)和特征卑笨。
流程:
1、建立一個(gè)Central Manager實(shí)例進(jìn)行藍(lán)牙管理CBCentralManagerDelegate
2仑撞、搜索外圍設(shè)備(一直目標(biāo)設(shè)備名稱可指定搜索)
3赤兴、連接外圍設(shè)備(目標(biāo)設(shè)備)CBPeripheralDelegate
4、獲得外圍設(shè)備的服務(wù)
5隧哮、獲得服務(wù)的特征(該步驟進(jìn)行特征的讀桶良、寫、通知等屬性)
6沮翔、從外圍設(shè)備讀數(shù)據(jù)
7陨帆、給外圍設(shè)備發(fā)送數(shù)據(jù)
1.屬性
// 外圍設(shè)備(一般是手機(jī))設(shè)備
@property (nonatomic, strong) CBCentralManager *mCentral;
// 外設(shè)設(shè)備
@property (nonatomic, strong) CBPeripheral *mPeripheral;
// 特征值
@property (nonatomic, strong) CBCharacteristic *mCharacteristic;
// 服務(wù)
@property (nonatomic, strong) CBService *mService;
2.協(xié)議<CBCentralManagerDelegate, CBPeripheralDelegate>
2.1. CBCentralManagerDelegate----設(shè)備鏈接需要的協(xié)議
/**
* 首先設(shè)備管理的類初始化,一旦初始化完成之后,就會(huì)遵循CBCentralManagerDelegate協(xié)議
*/
_mCentral = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];
@required
/**
* 藍(lán)牙的所有狀態(tài)疲牵,根據(jù)狀態(tài)進(jìn)行相關(guān)操作
* 開啟--掃描
* 未開啟/不支持藍(lán)牙等--友好提示
typedef NS_ENUM(NSInteger, CBCentralManagerState) {
CBCentralManagerStateUnknown = CBManagerStateUnknown,
CBCentralManagerStateResetting = CBManagerStateResetting,
CBCentralManagerStateUnsupported = CBManagerStateUnsupported,
CBCentralManagerStateUnauthorized = CBManagerStateUnauthorized,
CBCentralManagerStatePoweredOff = CBManagerStatePoweredOff,
CBCentralManagerStatePoweredOn = CBManagerStatePoweredOn,
} NS_DEPRECATED(10_7, 10_13, 5_0, 10_0, "Use CBManagerState instead");
*/
- (void)centralManagerDidUpdateState:(CBCentralManager *)central;
@optional
/**
* 發(fā)現(xiàn)外設(shè)藍(lán)牙設(shè)備的方法
* <這里進(jìn)行會(huì)搜索到周邊具有藍(lán)牙功能的設(shè)備承二,可以通過對(duì)具體藍(lán)牙名稱或者已知藍(lán)牙名稱前綴進(jìn)行篩選你要的藍(lán)牙設(shè)備,并且目標(biāo)設(shè)備在這里遵循CBPeripheralDelegate 協(xié)議纲爸,進(jìn)行搜索設(shè)備的services>
* [self.mCentral stopScan]; // 停止掃描
self.mPeripheral = peripheral;
// CBPeripheralDelegate
self.mPeripheral.delegate = self; // 遵循協(xié)議
[self.mCentral connectPeripheral:peripheral options:nil]; // 連接外設(shè)-->掃描services
*/
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI;
/**
* 中心管理者(連接外設(shè))連接成功
*/
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;
/**
* 中心管理者(連接外設(shè))連接失敗
*/
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral;
/**
* 中心管理者(外設(shè)丟失)連接丟失
*/
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;
2.2 CBPeripheralDelegate
/**
* 掃描目標(biāo)外設(shè)services回調(diào)
* [peripheral discoverCharacteristics:nil forService:service]; // 掃描service下面的特征值characteristics
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error;
/**
* 獲取特征值characteristics和描述
* 這里可以查詢到具體characteristic屬性properties(枚舉類型)的讀亥鸠,寫,通知缩焦,根據(jù)UUID(需要跟硬件工程師協(xié)商統(tǒng)一的)
* 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(10_9, 6_0) = 0x100,
CBCharacteristicPropertyIndicateEncryptionRequired NS_ENUM_AVAILABLE(10_9, 6_0) = 0x200
};
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error;
/**
* 讀取特征中的值和描述:更新特征值的時(shí)候調(diào)用读虏,可以理解為獲取藍(lán)牙返回的數(shù)據(jù)(需要的所有數(shù)據(jù)均在這里進(jìn)行處理)
*/
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;
/**
* 狀態(tài)改變和發(fā)現(xiàn)描述
*/
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;
/**
* 發(fā)現(xiàn)外設(shè)的特征的描述數(shù)組
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error;
/**
* 寫入數(shù)據(jù)成功與否的回調(diào)
*/
-(void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;
描述
我們是從手環(huán)中獲取到運(yùn)動(dòng)步數(shù),怎么獲取袁滥,如何接收數(shù)據(jù)盖桥,怎么處理數(shù)據(jù)?這是開發(fā)前就需要了解的题翻。通常硬件工程師會(huì)制定一個(gè)藍(lán)牙數(shù)據(jù)處理協(xié)議揩徊,就稱之為藍(lán)牙協(xié)議吧,因?yàn)樗P(guān)系著你能否獲取到你想要的數(shù)據(jù)嵌赠,導(dǎo)致能否按時(shí)完成項(xiàng)目塑荒。
-
我們的藍(lán)牙協(xié)議是這樣的
WechatIMG535.jpeg 讀懂藍(lán)牙協(xié)議,進(jìn)行指令發(fā)送(按照工程師給的藍(lán)牙協(xié)議拼接指令數(shù)組)
// 獲取總步數(shù)指令
Byte b[] = {0xC6};
// 獲取每個(gè)小時(shí)步數(shù)指令
Byte b2[] = {0xC4, 0x03, 0x01, 0x8, 0x03};
NSData *data = [NSData dataWithBytes:&b length:sizeof(b)];
NSData *data2 = [NSData dataWithBytes:&b2 length:sizeof(b2)];
// NSLog(@"%@", data);
// [self.mPeripheral writeValue:data forCharacteristic:self.mCharacteristic type:CBCharacteristicWriteWithResponse];
[self.mPeripheral writeValue:data2 forCharacteristic:self.mCharacteristic type:CBCharacteristicWriteWithResponse];
- 數(shù)據(jù)的處理姜挺,這里根據(jù)不同的硬件工程師規(guī)定的藍(lán)牙協(xié)議進(jìn)行自行處理數(shù)據(jù)哈(根據(jù)工程師給的藍(lán)牙協(xié)議按照對(duì)應(yīng)字節(jié)進(jìn)行解析16進(jìn)制數(shù)據(jù))
首先看看硬件工程師返回給我們的數(shù)據(jù):
A*小于20字節(jié)的返回一次就夠了
如:<29071306 1c090303 05130000 00000000 00000000>
B*大于20字節(jié)的分段接受齿税,每次20字節(jié)
如:<24281306 18080034 00000000 02fb0000 0000006d>
<00000000 00000000 00000000 00000000 00000000>
<0000a5>
上面數(shù)據(jù)的解析思路(以我們的協(xié)議為參考,具體情況按照你們的來):
24281306 1808 解析:命令頭24炊豪,數(shù)據(jù)長度0x28凌箕,然后是19年6月24日8點(diǎn)。词渤。
數(shù)據(jù)是每6個(gè)byte為一組牵舱,前兩個(gè)是步數(shù),比如 0034 00000000表示 0x0034步缺虐,高兩bit是用來表示步數(shù)或是睡眠芜壁,00表示步數(shù),01表示睡眠高氮,步數(shù)用14bit表示
圖形化解析
開發(fā)這種東西首先要理解流程慧妄,其次才是代碼,代碼千千萬剪芍,萬變不離其宗腰涧,因?yàn)閷戇@篇文章的時(shí)候還在開發(fā)公司的項(xiàng)目,而且離交付項(xiàng)目沒多少時(shí)間了紊浩,所以代碼寫的只是為了調(diào)試,都有備注的,各位看官還請(qǐng)手下留情7凰7驯恕!
如果發(fā)現(xiàn)問題還請(qǐng)及時(shí)指出口芍,與君共勉9坎!鬓椭!
如果有需求颠猴,可以直接與本人聯(lián)系,QQ:1749281699
最后再次發(fā)下Demo
附加:
可以使用以下測試軟件進(jìn)行測試:
LightBlue
nrf connect