1.概述
之前一直沒有接觸過藍(lán)牙開發(fā)褂删,最近公司需要使用藍(lán)牙傳輸饲握,從硬件設(shè)備同步數(shù)據(jù)到賬號(hào)里痕惋,借此記錄一下。
目前iOS中使用最多的藍(lán)牙開發(fā)庫(kù)是CoreBluetooth皆怕,它要求藍(lán)牙外設(shè)必須支持藍(lán)牙4.0及以上毅舆。藍(lán)牙4.0的特點(diǎn)是功耗低,所以也成為BLE4.0(Bluetooth Low Energy)愈腾,從iPhone4s開始支持憋活。
使用時(shí)需要引入頭文件import < CoreBluetooth/CoreBluetooth.h >。
2.CoreBluetooth介紹
使用 CoreBluetooth進(jìn)行藍(lán)牙開發(fā)主要用到的類虱黄,大約包含CBCentralManager(設(shè)備管理者)余掖、CBPeripheral(外設(shè)設(shè)備)、CBService(設(shè)備含有的服務(wù))礁鲁、CBCharacteristic(服務(wù)的特征值)幾大類盐欺。
藍(lán)牙的開發(fā)一般分為兩種模式:CBCentralMannager中心模式和CBPeripheralManager外設(shè)模式。
我們使用的是中心模式仅醇,外設(shè)模式也差不多類似冗美。這里主要說一下中心模式的開發(fā)流程:
創(chuàng)建中心設(shè)備管理實(shí)例
掃描外設(shè)
發(fā)現(xiàn)外設(shè)
根據(jù)相應(yīng)外設(shè)
掃描外設(shè)的服務(wù)
掃描外設(shè)服務(wù)中的特征值
訂閱特征的通知、讀取特征值數(shù)據(jù)
大致代碼流程:
1. 創(chuàng)建管理類
#import <CoreBluetooth/CoreBluetooth.h>
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
2. 監(jiān)聽藍(lán)牙狀態(tài)析二、掃描外設(shè)
#pragma mark - CBCentralManagerDelegate
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
switch (central.state) {
case CBManagerStateUnknown:
NSLog(@"CBManagerStateUnknown");
break;
case CBManagerStateResetting:
NSLog(@"CBManagerStateResetting");
break;
case CBManagerStateUnsupported:
NSLog(@"CBManagerStateUnsupported");
break;
case CBManagerStateUnauthorized:
NSLog(@"CBManagerStateUnauthorized");
break;
case CBManagerStatePoweredOff:
NSLog(@"CBManagerStatePoweredOff");
break;
case CBManagerStatePoweredOn: {
NSLog(@"CBManagerStatePoweredOn");
[self.centralManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey : @(YES)}];
break;
}
default:
break;
}
}
3. 發(fā)現(xiàn)外設(shè)粉洼、連接外設(shè)
#pragma mark - 掃描外設(shè)回調(diào)
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI {
if ((!self.peripheral || self.peripheral.state == CBPeripheralStateDisconnected)
&&([peripheral.name isEqualToString:@""])) { //想要連接的外設(shè)名稱
self.peripheral = peripheral;
// 鏈接外設(shè)
[self.centralManager connectPeripheral:peripheral options:nil];
}
}
4. 連接外設(shè)成功节预,發(fā)現(xiàn)外設(shè)服務(wù)
#pragma mark - 連接外設(shè)成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
[central stopScan];
[self.peripheral setDelegate:self];
[peripheral discoverServices:nil];
}
#pragma mark - 連接外設(shè)失敗
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
NSLog(@"didFailToConnectPeripheral:%@", error);
}
5. 連接外設(shè)成功,發(fā)現(xiàn)外設(shè)服務(wù)
#pragma mark - 發(fā)現(xiàn)服務(wù)回調(diào)
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
if (error || peripheral != self.peripheral) return;
for (CBService *service in peripheral.services) {
if (service.UUID isEqual:[CBUUID UUIDWithString:@""]) { // 需要使用的服務(wù)id
[peripheral discoverCharacteristics:nil forService:service];
return;
}
}
}
#pragma mark - 發(fā)現(xiàn)特征回調(diào)
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
if (error || peripheral != self.peripheral) return;
for (CBCharacteristic *characteristic in service.characteristics) {
CBCharacteristicProperties p = characteristic.properties;
if (p & CBCharacteristicPropertyIndicate &&
[characteristic.UUID isEqual:[CBUUID UUIDWithString:@""]]) {//需要的通知特征id
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
}
#pragma mark - 特征值更新回調(diào)
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
if (error) {
NSLog(@"didUpdateValueForCharacteristic error : %@", [error localizedDescription]);
} else {
NSLog(@"didUpdateValueForCharacteristic value : %@",characteristic.value);
}
}
#pragma mark - 訂閱狀態(tài)更新回調(diào)
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
if (error || peripheral != self.peripheral) return;
if (characteristic.isNotifying) {
NSLog(@"%@", characteristic);
}
}
6. 寫入數(shù)據(jù)
- (void)writeValue {
Byte byte = 0X01;
NSData *data = [NSData dataWithBytes:&byte length:sizeof(byte)];
[self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse]
}
7. 其他可能操作
#pragma mark - 斷開連接
- (void)disConnectPeripheral {
[self.centralManager cancelPeripheralConnection:self.peripheral];
}
#pragma mark - 停止掃描外設(shè)
- (void)stopScanPeripheral{
[self.centralManager stopScan];
}
3.坑點(diǎn)
-
iOS不能直接寫入數(shù)據(jù)到client configuration descriptor, 使用setNotifyValue: forCharacteristic:方法替代即属韧。
-
外設(shè)的唯一標(biāo)志符:
-
mac地址
官方API里面并沒有暴露外設(shè)的mac地址安拟,如果需要獲取mac地址,兩種方法:- 硬件設(shè)備的廣播里面添加mac地址信息宵喂,通過advertisementData獲取糠赦。
- 把所有掃描到的外設(shè)設(shè)備,依次連接獲取mac地址锅棕,然后判斷是不是想要連接的設(shè)備(著實(shí)有些麻煩拙泽,所以最好讓硬件設(shè)備把數(shù)據(jù)放到廣播數(shù)據(jù)里)。
參考 BluetoothMacAddressDemo
設(shè)備名字唯一
我們連接的硬件設(shè)備每臺(tái)設(shè)備的名稱都不會(huì)重復(fù)裸燎,可以直接使用這個(gè)來判斷顾瞻。
-
- 數(shù)據(jù)傳輸
我們開發(fā)過程中,連接外設(shè)定閱成功之后德绿,但是并無數(shù)據(jù)返回荷荤,跟硬件方面溝通后,才知道設(shè)備只有在某些設(shè)備下才會(huì)傳輸數(shù)據(jù)移稳。藍(lán)牙開發(fā)跟硬件方面保持溝通很重要T棠伞!秒裕!