
首先先介紹一下藍(lán)牙開發(fā)的模式:
- 藍(lán)牙中心模式
- 藍(lán)牙外設(shè)模式
一.藍(lán)牙中心模式
1.創(chuàng)建 CBCentralManager 中心對(duì)象
2.central掃描外設(shè) discover
3.central連接外設(shè) connect
- 掃描外設(shè)中的服務(wù)和特征discover
4.1、獲取外設(shè)的 services:
執(zhí)行:discoverServices
成功后執(zhí)行:peripheral:didDiscoverServices
委托方法
4.2、獲取外設(shè)的 Characteristics,獲取 Characteristics 的值:
執(zhí)行:discoverCharacteristics:forService
成功后執(zhí)行:peripheral:didDiscoverCharacteristicsForService:error
委托方法
4.3、獲取外設(shè)的Characteristics 的 Descriptor 和 Descriptor 的值:
讀特征值:readValueForCharacteristic
讀到后進(jìn)入:didUpdateValueForCharacteristic:error委托方法
搜索 Characteristic:discoverDescriptorsForCharacteristic
搜到后進(jìn)入:didDiscoverDescriptorsForCharacteristic:error委托方法
獲取到 Descriptors 的值:peripheral:didUpdateValueForDescriptor:error
Descriptors 是對(duì) characteristic 的描述,一般是字符串
4.4、把數(shù)據(jù)寫到 Characteristic:writeCharacteristic:charactericstic:value
4.5、讀 RSSI,用通知的方式訂閱數(shù)據(jù)等。
5、與外設(shè)做數(shù)據(jù)交互 explored interact
6、訂閱 Characteristic 的通知:notifyCharacteristic:characteristic
取消通知:cancelNotifyCharacteristic:characteristic
7、斷開連接 disconnect:disconnnectPeripheral:peripheral

二.藍(lán)牙外設(shè)模式流程
1.創(chuàng)建一個(gè) Peripheral 管理對(duì)象
peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
藍(lán)牙設(shè)備打開成功后會(huì)進(jìn)入委托方法:peripheralManagerDidUpdateState:
- 本地 Peripheral 設(shè)置服務(wù)、特性、描述、權(quán)限等。
創(chuàng)建 Characteristics 及其 description,創(chuàng)建 service,把 characteristics 添加到 service 中,再把 service 添加到 peripheralManager 中。
- Peripheral 發(fā)送廣播 advertising:peripheralManagerDidStartAdvertising:error
Peripheral 添加service:peripheralManager:didAddService:error
- 對(duì) central 的操作進(jìn)行響應(yīng)
讀 characteristics 請(qǐng)求:peripheralManager:didReceiveReadQuest:
寫characteristics 請(qǐng)求:peripheralManager:didReceiveWriteRequests:
訂閱特征:peripheralManager:central:didSubscribeToCharacteristic:
取消訂閱peripheralManager:central:didUnsubscribeFromCharacteristic:
一些基本屬性:
RSSI:信號(hào)強(qiáng)弱值,防丟器會(huì)用到。
UUID:唯一標(biāo)識(shí)符,用于區(qū)分設(shè)備
service UUID:服務(wù),一個(gè) Server 會(huì)包含多個(gè)characteristic,用 UUID 來區(qū)分。
characteristic:特征,用 UUID 來區(qū)分
了解了以上流程:由于蘋果的封閉生態(tài),之前對(duì)藍(lán)牙的限制比較嚴(yán)格,如果要和 iOS 設(shè)備通信,必須是經(jīng)過了 MFI 認(rèn)證的芯片才可以;藍(lán)牙4.0低功耗模式的到來,蘋果也對(duì)藍(lán)牙放開了一些限制。所以目前針對(duì) iOS 的藍(lán)牙編程主要就是針對(duì)藍(lán)牙4.0以上的低功耗藍(lán)牙,也就是 BLE 模式。
BLE 模式的特點(diǎn):
功耗低。
連接速度很快,連接距離遠(yuǎn)(100米)。
相應(yīng)的傳輸數(shù)據(jù)量小,比傳統(tǒng)藍(lán)牙傳輸?shù)男『芏啵瑩?jù)說單次發(fā)送也就20字節(jié)。
BLE 模式并不適合用來做較大數(shù)據(jù)量的傳輸使用
Bluetooth.h
@property(nonatomic,strong) CBCentralManager *centralManager;
@property(nonatomic,strong) CBPeripheral *peripheral;
@property(nonatomic,strong) CBCharacteristic *characteristic;
@property(nonatomic,strong) NSMutableArray *peripheralArray;
- (void)initBluetooth; //初始化藍(lán)牙
- (void)scanBluetooth; //掃描藍(lán)牙
- (void)stopScanBluetooth; //停止掃描
- (void)connectPeripheral:(CBPeripheral *)peripheral; //連接藍(lán)牙
- (void)disConnectPeripheral:(CBPeripheral *)peripheral; //取消連接藍(lán)牙
- (void)sendData:(NSData *)data; //向掃描到的藍(lán)牙Characteristic 發(fā)送數(shù)據(jù)
Bluetooth.m
// 初始化藍(lán)牙
- (void)initBluetooth
{
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];//創(chuàng)建CBCentralManager對(duì)象
_peripheralArray = [[NSMutableArray alloc] init];
}
//掃描藍(lán)牙
(void)scanBluetooth
{
NSLog(@"BluetoothBase scanBluetooth");
//CBCentralManagerScanOptionAllowDuplicatesKey值為 No,表示不重復(fù)掃描已發(fā)現(xiàn)的設(shè)備
NSDictionary *optionDic = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:CBCentralManagerScanOptionAllowDuplicatesKey];
[_centralManager scanForPeripheralsWithServices:nil options:optionDic];//如果你將第一個(gè)參數(shù)設(shè)置為nil,Central Manager就會(huì)開始尋找所有的服務(wù)。
}
//停止掃描藍(lán)牙(void)stopScanBluetooth
{
[self.centralManager stopScan];
NSLog(@"BluetoothBase stopScanBluetooth,已經(jīng)連接外設(shè)停止掃描或者手動(dòng)停止掃描");
}
//連接藍(lán)牙(void)connectPeripheral:(CBPeripheral *)peripheral
{
[self.centralManager connectPeripheral:peripheral options:nil];
self.peripheral = peripheral;
peripheral.delegate = self; //連接時(shí)設(shè)置代理
}
//取消連接藍(lán)牙(void)disConnectPeripheral:(CBPeripheral *)peripheral
{
[_centralManager cancelPeripheralConnection:peripheral];
}
//如果發(fā)送的數(shù)據(jù)過大,就需要做分包處理了。至于傳輸?shù)淖畲笞止?jié)數(shù)是多大,就需要和硬件工程師討論了。pl @PlatoJobs
//向藍(lán)牙寫入數(shù)據(jù)-
(void)sendData:(NSData *)data
{
[self initBluetoothDispatch];if (_characteristic.properties & CBCharacteristicPropertyWrite){
[_peripheral writeValue:data forCharacteristic:_characteristic type:CBCharacteristicWriteWithResponse];
NSLog(@"BluetoothBase writeDataToCharacteristic:%@",[_characteristic.UUID UUIDString]);
}else{
NSLog(@"沒有發(fā)現(xiàn)可以寫入的characteristic");
}
}
藍(lán)牙的一些代理方法(CBCentralManagerDelegate):
//centralManager已經(jīng)更新狀態(tài)
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
NSLog(@"centralManagerDidUpdateState:%ld",(long)central.state);
switch (central.state) {
case CBCentralManagerStateUnknown:
NSLog(@"CBCentralManagerStateUnknown");
break;
case CBCentralManagerStateResetting:
NSLog(@"CBCentralManagerStateResetting");
break;
case CBCentralManagerStateUnsupported:
NSLog(@"CBCentralManagerStateUnsupported");
break;
case CBCentralManagerStateUnauthorized:
NSLog(@"CBCentralManagerStateUnauthorized");
break;
case CBCentralManagerStatePoweredOff:
NSLog(@"CBCentralManagerStatePoweredOff");
break;
case CBCentralManagerStatePoweredOn:
[self scanBluetooth]; //很重要,當(dāng)藍(lán)牙處于打開狀態(tài),開始掃描。
break;
default:
NSLog(@"藍(lán)牙未工作在正確狀態(tài)");
break;
}
}
//centralManager已經(jīng)發(fā)現(xiàn)外設(shè)
//掃描到外設(shè),停止掃描,連接設(shè)備(每掃描到一個(gè)外設(shè)都會(huì)調(diào)用一次這個(gè)函數(shù),若要展示搜索到的藍(lán)牙,可以逐一保存 peripheral 并展示)
-
(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI
{
[_peripheralArray addObject:peripheral]; //保存用于連接的 peripheral
[PRTBluetoothModel share].peripheralArray = _peripheralArray;[[NSNotificationCenter defaultCenter] postNotificationName:@"PRTBluetoothScanUpdatePeripheralList" object:nil];
}
//已經(jīng)連接外設(shè)
//連接外設(shè)成功,掃描外設(shè)中的服務(wù)和特征 -
(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
[PRTDispatchModel share].currentDispatchMode = PRTPrinterModeBle; //將藍(lán)牙模式保存到當(dāng)前傳輸模式。NSLog(@"didConnectPeripheral:%@",peripheral.name);
[[NSNotificationCenter defaultCenter] postNotificationName:@"PRTBluetoothScanDidConnectPeripheral" object:nil];[self stopScanBluetooth]; //連接成功后停止掃描
[self.peripheral setDelegate:self];
//數(shù)組中存放兩個(gè)服務(wù)的 UUID
NSMutableArray *uuidArray = [[NSMutableArray alloc] initWithObjects:[CBUUID UUIDWithString:UUID_String_DeviceInfo_Service], [CBUUID UUIDWithString:UUIDSTR_ISSC_PROPRIETARY_SERVICE], nil];[peripheral discoverServices:uuidArray];//發(fā)現(xiàn)服務(wù),成功后執(zhí)行:peripheral:didDiscoverServices委托方法
}
//連接外設(shè)失敗 (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@"didFailToConnectPeripheral:%@",error);
}
//已經(jīng)發(fā)現(xiàn)服務(wù)-
(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
NSLog(@"didDiscoverServices:%@",peripheral.name);
if (error) {
NSLog(@"didDiscoverServices error:%@",[error localizedDescription]);
return;
}for (CBService *service in peripheral.services) {
//發(fā)現(xiàn)特征,成功后執(zhí)行:peripheral:didDiscoverCharacteristicsForService:error委托方法
[peripheral discoverCharacteristics:nil forService:service];
}
}
//已經(jīng)為服務(wù)發(fā)現(xiàn)特征
/*
藍(lán)牙都會(huì)有幾個(gè)服務(wù),每個(gè)服務(wù)都會(huì)有幾個(gè)特征,服務(wù)和特征都是用不同的 UUID 來標(biāo)識(shí)的。
每個(gè)特征的 properties 是不同的,就是說有不同的功能屬性,有的對(duì)應(yīng)寫入,有的對(duì)應(yīng)讀取。
藍(lán)牙聯(lián)盟有一個(gè)規(guī)范,但是這個(gè)也是可以自定義的,所以不清楚的話,聯(lián)系硬件工程師問清楚
*/
-
(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
NSLog(@"didDiscoverCharacteristicsForServic:%@",service.UUID);CBCharacteristic *characteristic = nil;
if ([service.UUID isEqual:[CBUUID UUIDWithString:@"這里填你的藍(lán)牙服務(wù)的 UUID"]]) {
for (characteristic in service.characteristics)
{
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"這里填你的藍(lán)牙特征的 UUID"]]) {
self.characteristic = characteristic;//重要,將滿足條件的特征保存為全局特征,以便對(duì)齊進(jìn)行寫入操作。
[PRTBluetoothModel share].characteristicWrite = characteristic;
[self.peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
}if (error) {
NSLog(@"didDiscoverCharacteristicsForService error:%@",[error localizedDescription]);
}
}
// 已經(jīng)更新特征的值
//獲取外設(shè)發(fā)來的數(shù)據(jù),不論是read和notify,獲取數(shù)據(jù)都是從這個(gè)方法中讀取。 -
(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
NSLog(@"didUpdateValueForCharacteristic:%@",[characteristic.UUID UUIDString]);
if (error) {
NSLog(@"didUpdateValueForCharacteristic error:%@",[error localizedDescription]);
}for (CBDescriptor *descriptor in characteristic.descriptors) //12.23新增
{
[peripheral readValueForDescriptor:descriptor];
}
}
//已經(jīng)寫入特征的值
//委托方法:已經(jīng)為特征【寫入值】
-(void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
NSLog(@"didWriteValueForCharacteristic:%@",[characteristic.UUID UUIDString]);if (error) {
NSLog(@"didWriteValueForCharacteristic error:%@",[error localizedDescription]);
}[peripheral readValueForCharacteristic:characteristic]; //12.23新增
}
//已經(jīng)發(fā)現(xiàn)特征的描述 (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
NSLog(@"didDiscoverDescriptorsForCharacteristic:%@",characteristic);
for (CBDescriptor *d in characteristic.descriptors) {
NSLog(@"Descriptor UUID:%@",d.UUID);
}
}
// 已經(jīng)更新描述的值(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error
{
NSLog(@"didUpdateValueForDescriptor:%@",descriptor);
[peripheral readValueForDescriptor:descriptor]; //12.23新增
}
//已經(jīng)更新特征的通知狀態(tài)-
(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
NSLog(@"didUpdateNotificationStateForCharacteristic:%@",characteristic);[peripheral readValueForCharacteristic:characteristic]; //12.23新增
[peripheral discoverDescriptorsForCharacteristic:characteristic];
}