一、框架
基於 <CoreBluetooth/CoreBluetooth.h> 框架
不要試圖繼承CoreBluetooth中的任何類,因為重載會導致未知的結果
有兩種開發方案,一種是以本地作為中心設備,一種是已遠端設備作為中心設備
包含類
外圍設備:通常用於發布服務、生成數據、保存數據。外圍設備發布並廣播服務,告訴周圍的中央設備它的可用服務特征
中心設備:中心設備掃描到外圍設備后會視圖建立連接,連接成功后可用使用外圍設備的服務和特征
外圍設備和中心設備直接交換的橋梁是服務(CBService)和特征(CBCharacteristic),二者都擁有一個唯一的標識(CBUUID)來確定唯一的服務和特征。每個服務可以有多個特征。
-
CBPeripheral 外圍設備
-
CBPeripheralManager 外圍設備管理類
-
CBMutableService 外圍設備的服務
-
CBMutableCharacteristic 外圍設備的特征
-
CBUUID 外圍設備服務特征的唯一標志
-
CBCentral 中心設備
-
CBCentralManager 中心設備管理類
-
CBService 外圍設備的服務
-
CBCharacteristic 外圍設備的特征
-
CBATTRequest 中心設備讀寫數據的請求
申請權限
iOS 10以后,所有的藍牙開發都要申請藍牙權限,在項目的info.plist中設置NSBluetoothPeripheralUsageDescription,對應的key為Privacy - Bluetooth Always Usage Description和Privacy - Bluetooth Peripheral Usage Description
二、中心開發模式
以中心設備CBCentral作為本地,外網設備CBPeripheral作為遠端
初始化
// 初始化選項,設置YES時,如果用戶藍牙關閉,會彈出一個提示框
NSDictionary *options = @{CBCentralManagerOptionShowPowerAlertKey: @YES};
CBCentralManager* tM = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue() options:options];
self.cbcManager = tM;
掃描外圍設備
//判斷當前藍牙工作狀態是否開啟
if (self.cbcManager.state == CBManagerStatePoweredOn) {
//記錄當前過濾條件
self.fliterName = fliterName;
//優先查找系統已經連接上的PV藍牙設備
self.sysConnectArrs = [self.cbcManager retrieveConnectedPeripheralsWithServices:@[[CBUUID UUIDWithString:PVMG10BluetoothServiceUUID]]];
for (CBPeripheral * cbp in self.sysConnectArrs) {
[self centralManager:self.cbcManager didDiscoverPeripheral:cbp advertisementData:@{} RSSI:cbp.RSSI];
}
//開始搜索設備
NSDictionary * option = @{
// CBCentralManagerScanOptionAllowDuplicatesKey 指示是否過濾重復情況
CBCentralManagerScanOptionAllowDuplicatesKey:[NSNumber numberWithBool:NO],
// 藍牙未開啟情況下是否顯示提示框
CBCentralManagerOptionShowPowerAlertKey:@0
};
// services和option都可以傳nil
// services傳對應的UUIDstring則掃描指定id的設備
[self.cbcManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:BluetoothServiceUUID]] options:option];
}
else{
// TODO:返回藍牙未打開狀態
}
掃描結果回調
藍牙狀態監聽
- (void)centralManagerDidUpdateState:(nonnull CBCentralManager *)central {
switch (central.state) {
case CBManagerStateUnknown:
NSLog(@">>>CBCentralManagerStateUnknown");
break;
case CBManagerStateResetting:
NSLog(@">>>CBCentralManagerStateResetting");
break;
case CBManagerStateUnsupported:
NSLog(@">>>CBCentralManagerStateUnsupported");
break;
case CBManagerStateUnauthorized:
NSLog(@">>>CBCentralManagerStateUnauthorized");
break;
case CBManagerStatePoweredOff:
NSLog(@">>>CBCentralManagerStatePoweredOff");
{
//手動斷開設備連接
for (NSString * pcDeviceName in self.connectedDeviceMap) {
PVBluetoothDevice * device = self.connectedDeviceMap[pcDeviceName];
[self centralManager:self.cbcManager didDisconnectPeripheral:device.peripheral error:nil];
}
}
break;
case CBManagerStatePoweredOn:
{
NSLog(@">>>CBCentralManagerStatePoweredOn");
}
break;
default:
break;
}
if (self.delegate && [self.delegate respondsToSelector:@selector(pvBluetoothToolsUpdateManagerStaus:)]) {
[self.delegate pvBluetoothToolsUpdateManagerStaus:central.state];
}
}
發現設備回調
//搜索到設備
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{
//通過名稱過濾設備是否為過濾設備
for (NSString * fliter in self.fliterName) {
if ([peripheral.name hasPrefix:fliter]) {
[self.discoverDevices addObject:peripheral];
//把系統掃描出來的一起回調
[self.discoverDevices addObjectsFromArray:self.sysConnectArrs];
if (self.delegate && [self.delegate respondsToSelector:@selector(pvBluetoothToolsUpdateSerchDevice:sysConnected:)]){
//查看下新搜索出來的設備系統是不是已經連接了
NSArray * sysconnectedDeviceArr = [self.cbcManager retrieveConnectedPeripheralsWithServices:@[[CBUUID UUIDWithString:PVMG10BluetoothServiceUUID]]];
BOOL sysConnected = [sysconnectedDeviceArr containsObject:peripheral];
[self.delegate pvBluetoothToolsUpdateSerchDevice:peripheral sysConnected:sysConnected];
}
}
}
}
連接設備
//CBConnectPeripheralOptionNotifyOnConnectionKey 表示應用被掛起時,系統應該為給定的外設顯示警報
[self.cbcManager connectPeripheral:peripheral options:@{CBConnectPeripheralOptionNotifyOnConnectionKey:[NSNumber numberWithBool:YES]}];
連接結果回調
設備連接成功
//
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
[self.connectedDeviceMap setObject:peripheral forKey:peripheral.name];
//開始搜索服務
[peripheral discoverServices:@[[CBUUID UUIDWithString:BluetoothUartServiceUUID]]];
}
連接失敗
//連接失敗
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
NSLog(@"%@",error.localizedDescription);
}
連接斷開
-(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
NSLog(@"設備斷開");
[self.connectedDeviceMap removeObjectForKey:peripheral.name];
}
掃描外圍設備的服務
// uuid需要約定好
[peripheral discoverServices:@[[CBUUID UUIDWithString:BluetoothUartServiceUUID]]];
掃描結果回調
//發現服務服務
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
for (CBService * service in peripheral.services) {
if ([service.UUID.UUIDString isEqualToString:BluetoothUartServiceUUID]) {//確定串口服務
這里查找特征
}
}
查詢服務的特征
//開始查找特征
[peripheral discoverCharacteristics:NULL forService:service];
發現服務特征回調
//發現特征
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
for (CBCharacteristic *characteristic in service.characteristics) {
// 遍歷獲取對應的特征值
// 獲取約定的發送特征
if ([characteristic.UUID.UUIDString isEqualToString:BluetoothSendcharacteristicUUID]) {
BluetoothDevice * device = self.connectedDeviceMap[peripheral.name];
device.sendCharacteristic = characteristic;
}
// 獲取約定的接收特征
else if ([characteristic.UUID.UUIDString isEqualToString:BluetoothReceivedcharacteristicUUID]){
BluetoothDevice * device = self.connectedDeviceMap[peripheral.name];
device.receivedCharacteristic = characteristic;
[device.peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
/**a
-- 當發現characteristic有descriptor,回調didDiscoverDescriptorsForCharacteristic
*/
[peripheral discoverDescriptorsForCharacteristic:characteristic];
}
}
注冊特征
// 注冊了特征值后,就可以通過特征值來讀取數據了。
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
特征注冊結果回調
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error;
通過特征讀取數據
//收到數據
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
NSLog(@"%@",characteristic.value);
if (self.delegate && [self.delegate respondsToSelector:@selector(pvBluetoothToolsReceiveData:)]) {
[self.delegate pvBluetoothToolsReceiveData:characteristic.value];
}
}
通過特征發送數據
type有兩個值:
- CBCharacteristicWriteWithResponse 需要返回發送數據的結果
- CBCharacteristicWriteWithoutResponse 不需要返回發送數據的結果
[device.peripheral writeValue:data forCharacteristic:device.sendCharacteristic type:CBCharacteristicWriteWithoutResponse];
發送數據結果回調
如果需要返回發送結果,會調用當前回調
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
NSLog(@"數據發送成功");
}
關閉藍牙設備
- (void)closeBlueTooth {
//停止掃描
[self.centralManager stopScan];
if (self.peripheral) {
//斷開當前的連接
[self.centralManager cancelPeripheralConnection:self.peripheral];
}
self.centralManager = nil;
self.peripheral = nil;
self.characteristic = nil;
}
