1、概念介紹
本文所說的藍(lán)牙開發(fā)是基于蘋果<CoreBluetooth/CoreBluetooth.h>框架的藍(lán)牙功能開發(fā)。
基本概念:
中心設(shè)備:用于掃描周邊藍(lán)牙外設(shè)的設(shè)備,在iOS開發(fā)中,手機(jī)就是我們的中心設(shè)備。
外部設(shè)備:被掃描的藍(lán)牙設(shè)備,比如電子手表、藍(lán)牙耳機(jī)或其他藍(lán)牙設(shè)備。
廣播:外部設(shè)備不斷發(fā)送藍(lán)牙藍(lán)牙信號(hào),供中心設(shè)備掃描到。
服務(wù)(CBService):設(shè)備之間進(jìn)行數(shù)據(jù)交換的基礎(chǔ)單位,設(shè)備連接后可以進(jìn)行,讀取服務(wù)和寫入服務(wù)、更新服務(wù)。
特征(CBCharacteristic):服務(wù)下的子單位,數(shù)據(jù)在服務(wù)上的具體載體。一個(gè)服務(wù)會(huì)有多個(gè)特征,每個(gè)特征會(huì)有value來承載數(shù)據(jù)。
UUID:區(qū)分不同服務(wù)和特征的唯一標(biāo)識(shí)符。
當(dāng)我們進(jìn)行藍(lán)牙開發(fā)時(shí),一般是在iPhone上,以中心設(shè)備的模式進(jìn)行開發(fā)。步驟為:
1、檢測藍(lán)牙狀態(tài)
2、掃描周邊設(shè)備藍(lán)牙
3、連接藍(lán)牙
4、讀取服務(wù)及特征數(shù)據(jù),進(jìn)行數(shù)據(jù)交互
外設(shè)設(shè)備開發(fā):
1、檢測藍(lán)牙狀態(tài)
2、創(chuàng)建藍(lán)牙對(duì)象設(shè)置代理,等待被連接
3、寫入特征和讀取特征,與中心設(shè)備進(jìn)行數(shù)據(jù)交互
我們可以使用蘋果電腦作為外設(shè),蘋果手機(jī)作為中心設(shè)備,模擬兩個(gè)設(shè)備的藍(lán)牙交互流程。
為了更好的理解藍(lán)牙功能開發(fā),我們確定一個(gè)練習(xí)的目標(biāo):在蘋果電腦上使用藍(lán)牙傳輸一張圖片數(shù)據(jù)到手機(jī)上,然后在手機(jī)上進(jìn)行顯示。
由于圖片比較大,在傳輸過程中我們需要對(duì)數(shù)據(jù)進(jìn)行分割傳輸。
2、模擬外部設(shè)備開發(fā)
1、首先創(chuàng)建工程,導(dǎo)入框架
#import <CoreBluetooth/CoreBluetooth.h>
2、創(chuàng)建外設(shè)CBPeripheralManager對(duì)象
@property(nonatomic,strong)CBPeripheralManager* peripheralManager;
self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:dispatch_get_global_queue(0, 0)];
設(shè)置ViewController為代理,設(shè)置回調(diào)隊(duì)列為主隊(duì)列。
3、實(shí)現(xiàn)代理方法
當(dāng)檢測到藍(lán)牙狀態(tài)發(fā)生改變時(shí),系統(tǒng)會(huì)調(diào)用狀態(tài)改變的代理方法,通知我們藍(lán)牙是否可用。
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{
switch (peripheral.state) {
case CBPeripheralManagerStatePoweredOff:
NSLog(@"藍(lán)牙關(guān)閉");
break;
case CBPeripheralManagerStatePoweredOn:
NSLog(@"藍(lán)牙打開");
//廣播數(shù)據(jù)
[self startAdvertising];
break;
default:
NSLog(@"藍(lán)牙狀態(tài)不明");
break;
}
}
我們?cè)谒{(lán)牙打開的回調(diào)里面添加廣播的數(shù)據(jù),告訴中心設(shè)備,我們的特征。
- (void)startAdvertising {
CBUUID* peripheralServiceUUID = [CBUUID UUIDWithString:@"AD01"];
NSDictionary *para = @{
CBAdvertisementDataLocalNameKey : @"macblue",
CBAdvertisementDataServiceUUIDsKey : @[peripheralServiceUUID],
};
// 開始廣播
[self.peripheralManager startAdvertising:para];
}
startAdvertising方法中的字典只能添加兩個(gè)key,分別為CBAdvertisementDataLocalNameKey,CBAdvertisementDataServiceUUIDsKey。我們最多可用傳遞28個(gè)字節(jié)數(shù)據(jù)。
當(dāng)中心設(shè)備掃描時(shí),會(huì)掃描到我們?cè)O(shè)置的廣播數(shù)據(jù)。
如下:
{
kCBAdvDataIsConnectable = 1;
kCBAdvDataLocalName = macblue;
kCBAdvDataRxPrimaryPHY = 0;
kCBAdvDataRxSecondaryPHY = 0;
kCBAdvDataServiceUUIDs = (
AD01
);
kCBAdvDataTimestamp = "727518148.203617";
kCBAdvDataTxPowerLevel = 12;
}
中心設(shè)備以kCBAdvDataLocalName = macblue和kCBAdvDataServiceUUIDs = (AD01)來判斷設(shè)備是否為我們需要連接的測試設(shè)備。
此時(shí),我們的外部設(shè)備以及準(zhǔn)備好,等待中心設(shè)備掃描連接。
3、中心設(shè)備開發(fā)
導(dǎo)入藍(lán)牙框架
#import <CoreBluetooth/CoreBluetooth.h>
創(chuàng)建藍(lán)牙對(duì)象
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_global_queue(0, 0)];
實(shí)現(xiàn)代理方法
//藍(lán)牙狀態(tài)發(fā)生改變調(diào)用的代理方法
- (void)centralManagerDidUpdateState:(CBCentralManager *)central;
各種狀態(tài)如下,當(dāng)藍(lán)牙狀態(tài)為CBManagerStatePoweredOn時(shí)可對(duì)藍(lán)牙進(jìn)行操作。
typedef NS_ENUM(NSInteger, CBManagerState) {
CBManagerStateUnknown = 0,
CBManagerStateResetting,
CBManagerStateUnsupported,
CBManagerStateUnauthorized,
CBManagerStatePoweredOff,
CBManagerStatePoweredOn,
} NS_ENUM_AVAILABLE(10_13, 10_0);
開始掃描周圍藍(lán)牙設(shè)備
- (void)scanDeviceWithServicerUUID:(NSString *)servicerUUID {
NSLog(@"開始掃描服務(wù):%@",servicerUUID);
if (servicerUUID) {
CBUUID* servicesUUID = [CBUUID UUIDWithString:servicerUUID];
[self.centralManager scanForPeripheralsWithServices:@[servicesUUID] options:nil];
}else {
[self.centralManager scanForPeripheralsWithServices:nil options:nil];
}
}
掃描到目標(biāo)藍(lán)牙設(shè)備時(shí),停止藍(lán)牙設(shè)備的掃描
[self.centralManager stopScan];
連接目標(biāo)藍(lán)牙設(shè)備
[self.centralManager connectPeripheral:peripheral options:@{CBConnectPeripheralOptionNotifyOnConnectionKey:@1}];
藍(lán)牙連接成功和失敗都有代理方法回調(diào)
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error;
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error;
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral timestamp:(CFAbsoluteTime)timestamp isReconnecting:(BOOL)isReconnecting error:(nullable NSError *)error;
- (void)centralManager:(CBCentralManager *)central connectionEventDidOccur:(CBConnectionEvent)event forPeripheral:(CBPeripheral *)peripheral CB_CM_API_AVAILABLE;
- (void)centralManager:(CBCentralManager *)central didUpdateANCSAuthorizationForPeripheral:(CBPeripheral *)peripheral NS_AVAILABLE_IOS(13_0);
連接上目標(biāo)藍(lán)牙設(shè)備后,讀取藍(lán)牙服務(wù)數(shù)據(jù)和特征數(shù)據(jù)
- (void)discoverServices:(nullable NSArray<CBUUID *> *)serviceUUIDs;
讀取到服務(wù)后會(huì)調(diào)用對(duì)應(yīng)的代理方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(nullable NSError *)error;
從服務(wù)中讀取特征值
- (void)discoverCharacteristics:(nullable NSArray<CBUUID *> *)characteristicUUIDs forService:(CBService *)service;
找到特征后會(huì)出發(fā)找到特征的代理方法
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error;
可以根據(jù)CBCharacteristic對(duì)象的characteristics數(shù)組,處理不同的特征服務(wù)。
類型如下:
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
};
主要有CBCharacteristicPropertyRead、CBCharacteristicPropertyWrite、CBCharacteristicPropertyNotify。方便為讀、寫、通知。讀主要是讀取設(shè)備藍(lán)牙數(shù)據(jù),寫是向設(shè)備藍(lán)牙寫入數(shù)據(jù),通知是接收設(shè)備藍(lán)牙的通知。
讀取到特征值后會(huì)調(diào)用代理方法
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error;
寫入特征值后也會(huì)調(diào)用代理方法告訴用戶是否寫入正確
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error;
訂閱狀態(tài)發(fā)生改變也會(huì)調(diào)用代理方法
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error;