一、藍(lán)牙
隨著藍(lán)牙低功耗技術(shù)BLE(Bluetooth Low Energy)的發(fā)展,藍(lán)牙技術(shù)正在一步步成熟,如今的大部分移動設(shè)備都配備有藍(lán)牙4.0,相比之前的藍(lán)牙技術(shù)耗電量大大降低。
在iOS中進(jìn)行藍(lán)牙傳輸常用的框架有如下幾種:
GameKit.framework:
iOS7之前的藍(lán)牙框架,只可用于同應(yīng)用之間的藍(lán)牙傳輸。
-
MultipeerConnectivity.framework:
iOS7開始引入的藍(lán)牙框架,用于取代GameKit,也有缺陷,僅支持iOS設(shè)備之間藍(lán)牙傳輸。 -
CoreBluetooth.framework:
功能強(qiáng)大的藍(lán)牙框架,但要求設(shè)備必須支持藍(lán)牙4.0,可以支持所有設(shè)備藍(lán)牙傳輸,只要該設(shè)備支持藍(lán)牙4.0。
應(yīng)用的比較多的是CoreBluetooth框架,這里就選擇CoreBluetooth框架來講。
二、CoreBluetooth
當(dāng)前BLE應(yīng)用相當(dāng)廣泛,不再僅僅是兩個設(shè)備之間的數(shù)據(jù)傳輸,它還有很多其他應(yīng)用市場,例如室內(nèi)定位、無線支付、智能家居等等,這也使得CoreBluetooth成為當(dāng)前最熱門的藍(lán)牙技術(shù)。
我的理解中,CoreBluetooth藍(lán)牙通信過程和網(wǎng)絡(luò)通信過程比較類似。
在CoreBluetooth中,藍(lán)牙傳輸都分為兩個部分:
- 外圍設(shè)備
CBPeripheral:
負(fù)責(zé)發(fā)布并廣播服務(wù),告訴周圍的中央設(shè)備它的可用服務(wù)和特征,類似于網(wǎng)絡(luò)通信中的服務(wù)端。
- 中央設(shè)備
CBCentral:
負(fù)責(zé)和外圍設(shè)備建立連接,一旦連接成功就可以使用外圍設(shè)備的服務(wù)和特征,類似于網(wǎng)絡(luò)通信中的客戶端

外圍設(shè)備和中央設(shè)備交互的橋梁是服務(wù)和特征,兩個都有一個唯一標(biāo)識CBUUID來確定一個服務(wù)或者特征:
- 服務(wù)
CBService:
中央設(shè)備只有通過服務(wù)才能與外圍設(shè)備進(jìn)行數(shù)據(jù)傳輸,類似于客戶端通過網(wǎng)址URL才能與服務(wù)器連接一樣
- 特征
CBCharacteristic:
每個服務(wù)可以擁有多個特征,中央設(shè)備必須訂閱外圍設(shè)備服務(wù)的特征值,才能獲取外圍設(shè)備的數(shù)據(jù),類似于GET請求可以請求獲取服務(wù)器數(shù)據(jù),POST請求可以向服務(wù)器傳輸數(shù)據(jù)一樣。

三、設(shè)備作為外圍設(shè)備
設(shè)備作為外圍設(shè)備的創(chuàng)建步驟:
- 創(chuàng)建外圍設(shè)備管理器
CBPeripheralManager,并設(shè)置代理
- 創(chuàng)建一個特征
CBCharacteristic,綁定一個CBUUID,設(shè)置特征屬性 - 創(chuàng)建一個服務(wù)
CBService,綁定一個CBUUID,設(shè)置服務(wù)的特征 - 調(diào)用外圍設(shè)備管理器的對象方法,添加服務(wù)到外圍設(shè)備上
-(void)addService:(CBService *)service;
- 外圍設(shè)備管理器開始廣播服務(wù)
-(void)startAdvertising:(NSDictionary *)dict;
- 在外圍設(shè)備管理器的代理方法,處理與中央設(shè)備的交互

外圍設(shè)備管理器啟動服務(wù)的相關(guān)代理方法:
/* 外圍設(shè)備管理器狀態(tài)發(fā)生改變后調(diào)用,比如外圍設(shè)備打開藍(lán)牙的時候 */
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral;
/* 外圍設(shè)備管理器添加了服務(wù)后調(diào)用,一般在這里進(jìn)行廣播服務(wù) */
- (void)peripheralManager:(CBPeripheralManager *)peripheral
didAddService:(CBService *)service /* 添加的服務(wù) */
error:(NSError *)error;/* 添加服務(wù)錯誤信息 */
/* 啟動廣播服務(wù)后調(diào)用 */
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral
error:(NSError *)error;/* 啟動服務(wù)錯誤信息 */
/* 外圍設(shè)備恢復(fù)狀態(tài)時調(diào)用 */
- (void)peripheralManager:(CBPeripheralManager *)peripheral
willRestoreState:(NSDictionary *)dict;
外圍設(shè)備管理器和中央設(shè)備進(jìn)行交互的代理方法:
/* 中央設(shè)備訂閱外圍設(shè)備的特征時調(diào)用 */
- (void)peripheralManager:(CBPeripheralManager *)peripheral /* 外圍設(shè)備管理器 */
central:(CBCentral *)central /* 中央設(shè)備 */
didSubscribeToCharacteristic:(CBCharacteristic *)characteristic;/* 訂閱的特征 */
/* 中央設(shè)備取消訂閱外圍設(shè)備的特征時調(diào)用 */
- (void)peripheralManager:(CBPeripheralManager *)peripheral /* 外圍設(shè)備管理器 */
central:(CBCentral *)central /* 中央設(shè)備 */
didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic;/* 特征 */
/* 外圍設(shè)備收到中央設(shè)備的寫請求時調(diào)用 */
- (void)peripheralManager:(CBPeripheralManager *)peripheral
didReceiveWriteRequests:(CBATTRequest *)request;/* 寫請求 */
外圍設(shè)備管理器CBPeripheralManager的常用對象方法:
/* 添加服務(wù) */
- (void)addService:(CBService *)service;
/* 開啟廣播服務(wù),dict設(shè)置設(shè)備信息 */
- (void)startAdvertising:(NSDictionary *)dict;
/* 更新特征值,centrals為空,表示對所有連接的中央設(shè)備通知 */
- (void)updateValue:(NSData *)value /* 特征的特征值 */
forCharacteristic:(CBCharacteristic *)characteristic /* 特征 */
onSubscribedCentrals:(NSArray *)centrals;/* 需要通知更新特征值的中央設(shè)備 */
下面是設(shè)備作為外圍設(shè)備的實例:
#import "PeripheralViewController.h"
#import <CoreBluetooth/CoreBluetooth.h>
#define kPeripheralName @"Liuting's Device" //外圍設(shè)備名稱,自定義
#define kServiceUUID @"FFA0-FFB0" //服務(wù)的UUID,自定義
#define kCharacteristicUUID @"FFCC-FFDD" //特征的UUID,自定義
@interface PeripheralViewController ()<CBPeripheralManagerDelegate>
@property (strong, nonatomic) CBPeripheralManager *peripheralManager;/* 外圍設(shè)備管理器 */
@property (strong, nonatomic) NSMutableArray *centralM;/* 訂閱的中央設(shè)備 */
@property (strong, nonatomic) CBMutableCharacteristic *characteristicM;/* 特征 */
@end
@implementation PeripheralViewController
- (void)viewDidLoad{
[super viewDidLoad];
self.centralM = [NSMutableArray array];
//創(chuàng)建外圍設(shè)備管理器
self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self
queue:nil];
}
#pragma mark - UI事件
/* 點擊更新特征值 */
- (IBAction)changeCharacteristicValue:(id)sender {
//特征值,這里是更新特征值為當(dāng)前時間
NSString *valueStr = [NSString stringWithFormat:@"%@",[NSDate date]];
NSData *value = [valueStr dataUsingEncoding:NSUTF8StringEncoding];
//更新特征值
[self.peripheralManager updateValue:value
forCharacteristic:self.characteristicM
onSubscribedCentrals:nil];
}
#pragma mark - 私有方法
/* 創(chuàng)建特征、服務(wù)并添加服務(wù)到外圍設(shè)備 */
- (void)addMyService{
/*1.創(chuàng)建特征*/
//創(chuàng)建特征的UUID對象
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID];
/* 創(chuàng)建特征
* 參數(shù)
* uuid:特征標(biāo)識
* properties:特征的屬性,例如:可通知、可寫、可讀等
* value:特征值
* permissions:特征的權(quán)限
*/
CBMutableCharacteristic *characteristicM =
[[CBMutableCharacteristic alloc] initWithType:characteristicUUID
properties:CBCharacteristicPropertyNotify
value:nil
permissions:CBAttributePermissionsReadable];
self.characteristicM = characteristicM;
//創(chuàng)建服務(wù)UUID對象
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID];
//創(chuàng)建服務(wù)
CBMutableService *serviceM = [[CBMutableService alloc] initWithType:serviceUUID
primary:YES];
//設(shè)置服務(wù)的特征
[serviceM setCharacteristics:@[characteristicM]];
//將服務(wù)添加到外圍設(shè)備
[self.peripheralManager addService:serviceM];
}
#pragma mark - CBPeripheralManager代理方法
/* 外圍設(shè)備狀態(tài)發(fā)生變化后調(diào)用 */
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{
//判斷外圍設(shè)備管理器狀態(tài)
switch (peripheral.state) {
case CBPeripheralManagerStatePoweredOn:
{
NSLog(@"BLE已打開.");
//添加服務(wù)
[self addMyService];
break;
}
default:
{
NSLog(@"此設(shè)備不支持BLE或未打開藍(lán)牙功能,無法作為外圍設(shè)備.");
break;
}
}
}
/* 外圍設(shè)備恢復(fù)狀態(tài)時調(diào)用 */
- (void)peripheralManager:(CBPeripheralManager *)peripheral
willRestoreState:(NSDictionary *)dict
{
NSLog(@"狀態(tài)恢復(fù)");
}
/* 外圍設(shè)備管理器添加服務(wù)后調(diào)用 */
- (void)peripheralManager:(CBPeripheralManager *)peripheral
didAddService:(CBService *)service
error:(NSError *)error
{
//設(shè)置設(shè)備信息dict,CBAdvertisementDataLocalNameKey是設(shè)置設(shè)備名
NSDictionary *dict = @{CBAdvertisementDataLocalNameKey:kPeripheralName};
//開始廣播
[self.peripheralManager startAdvertising:dict];
NSLog(@"向外圍設(shè)備添加了服務(wù)并開始廣播...");
}
/* 外圍設(shè)備管理器啟動廣播后調(diào)用 */
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral
error:(NSError *)error
{
if (error) {
NSLog(@"啟動廣播過程中發(fā)生錯誤,錯誤信息:%@",error.localizedDescription);
return;
}
NSLog(@"啟動廣播...");
}
/* 中央設(shè)備訂閱特征時調(diào)用 */
- (void)peripheralManager:(CBPeripheralManager *)peripheral
central:(CBCentral *)central
didSubscribeToCharacteristic:(CBCharacteristic *)characteristic
{
NSLog(@"中心設(shè)備:%@ 已訂閱特征:%@.",central,characteristic);
//把訂閱的中央設(shè)備存儲下來
if (![self.centralM containsObject:central]) {
[self.centralM addObject:central];
}
}
/* 中央設(shè)備取消訂閱特征時調(diào)用 */
- (void)peripheralManager:(CBPeripheralManager *)peripheral
central:(CBCentral *)central
didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic
{
NSLog(@"中心設(shè)備:%@ 取消訂閱特征:%@",central,characteristic);
}
/* 外圍設(shè)備管理器收到中央設(shè)備寫請求時調(diào)用 */
- (void)peripheralManager:(CBPeripheralManager *)peripheral
didReceiveWriteRequests:(CBATTRequest *)request
{
NSLog(@"收到寫請求");
}
@end
四、設(shè)備作為中央設(shè)備
更多的時候,我們需要的是一個中央設(shè)備,外圍設(shè)備不一定是iOS設(shè)備,所以上面外圍設(shè)備的創(chuàng)建不一定會用到,比如外圍設(shè)備是GPS導(dǎo)航儀、心率儀等,這些只要遵循BLE4.0的規(guī)范,中央設(shè)備就可以與之連接并尋找服務(wù)和訂閱特征。

設(shè)備作為中央設(shè)備的創(chuàng)建步驟:
- 創(chuàng)建中央設(shè)備管理器對象
CBCentralManager,設(shè)置代理
- 掃描外圍設(shè)備,發(fā)現(xiàn)外圍設(shè)備
CBPeripheral進(jìn)行連接,保持連接的外圍設(shè)備 - 在連接外圍設(shè)備成功的代理方法中,設(shè)置外圍設(shè)備的代理,調(diào)用外圍設(shè)備的對象方法尋找服務(wù)
- 查找外圍設(shè)備的服務(wù)和特征,查找到可用特征,則讀取特征數(shù)據(jù)。
- 記住這里是外圍設(shè)備對象
CBPeripheral,
不是上面的外圍設(shè)備管理器對象CBPeripheralManager
中央設(shè)備管理器的代理方法:
/* 中央設(shè)備管理器狀態(tài)改變后調(diào)用,比如藍(lán)牙的打開與關(guān)閉 */
- (void)centralManagerDidUpdateState:(CBCentralManager *)central;
/* 開啟掃描后,中央設(shè)備管理器發(fā)現(xiàn)外圍設(shè)備后調(diào)用 */
- (void)centralManager:(CBCentralManager *)central
didDiscoverPeripheral:(CBPeripheral *)peripheral /* 外圍設(shè)備 */
advertisementData:(NSDictionary *)advertisementData /* 設(shè)備信息 */
RSSI:(NSNumber *)RSSI; /* 信號強(qiáng)度 */
/* 中央設(shè)備管理器成功連接到外圍設(shè)備后調(diào)用 */
- (void)centralManager:(CBCentralManager *)central
didConnectPeripheral:(CBPeripheral *)peripheral;/* 外圍設(shè)備 */
/* 中央設(shè)備管理器連接外圍設(shè)備失敗后調(diào)用 */
- (void)centralManager:(CBCentralManager *)central
didFailToConnectPeripheral:(CBPeripheral *)peripheral /* 外圍設(shè)備 */
error:(NSError *)error;/* 連接失敗的錯誤信息 */
中央設(shè)備管理器的對象方法:
/* 掃描外圍設(shè)備,可以指定含有指定服務(wù)的外圍設(shè)備 */
- (void)scanForPeripheralsWithServices:(NSArray<CBUUID *> *)services
options:(NSDictionary *)options;
/* 停止掃描 */
- (void)stopScan;
/* 連接外圍設(shè)備 */
- (void)connectPeripheral:(CBPeripheral *)peripheral
options:(NSDictionary *)options;
/* 斷開外圍設(shè)備 */
- (void)cancelPeripheralConnection:(CBPeripheral *)peripheral;
外圍設(shè)備的代理方法【和上面的外圍設(shè)備管理器代理不一樣】
/**
* 1.成功訂閱外圍設(shè)備的服務(wù)后調(diào)用,在該代理方法中尋找服務(wù)的特征
* @param peripheral 連接到的設(shè)備
* @param error 錯誤信息
*/
- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverServices:(NSError *)error;
/**
* 2.成功找到外圍設(shè)備服務(wù)的特征后調(diào)用,在該代理方法中設(shè)置訂閱方式
* @param peripheral 連接的設(shè)備
* @param service 擁有的服務(wù)
* @param error 錯誤信息
*/
- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverCharacteristicsForService:(CBService *)service
error:(NSError *)error;
/**
* 3.外圍設(shè)備讀取到特征值就會調(diào)用
* @param peripheral 連接的設(shè)備
* @param characteristic 改變的特征
* @param error 錯誤信息
*/
- (void)peripheral:(CBPeripheral *)peripheral
didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error;
/**
* 4.向外圍設(shè)備的特征對象寫操作完成后調(diào)用
* 特別:當(dāng)寫操作為CBCharacteristicWriteWithoutResponse時不會調(diào)用
* @param peripheral 連接的設(shè)備
* @param characteristic 要寫入的特征
* @param error 錯誤信息
*/
- (void)peripheral:(CBPeripheral *)peripheral
didWriteValueForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error;
外圍設(shè)備CBPeripheral的常用對象方法:
/* 尋找服務(wù),傳入的是服務(wù)的唯一標(biāo)識CBUUID */
- (void)discoverServices:(NSArray<CBUUID *> *)services;
/* 尋找指定服務(wù)下的特征,特征數(shù)組也是傳入特征的唯一標(biāo)識CBUUID */
- (void)discoverCharacteristics:(NSArray<CBUUID *> *)characteristics
forService:(CBService *)service;/* 服務(wù) */
/* 設(shè)置是否向特征訂閱數(shù)據(jù)實時通知,YES表示會實時多次會調(diào)用代理方法讀取數(shù)據(jù) */
- (void)setNotifyValue:(BOOL)value
forCharacteristic:(CBCharacteristic *)characteristic;
/* 讀取特征的數(shù)據(jù),調(diào)用此方法后會調(diào)用一次代理方法讀取數(shù)據(jù) */
- (void)readValueForCharacteristic:(CBCharacteristic *)characteristic;
/* 向特征寫入數(shù)據(jù),看type類型,決定調(diào)不調(diào)用寫入數(shù)據(jù)后回調(diào)的代理方法 */
- (void)writeValue:(NSData *)value /* 寫入數(shù)據(jù) */
forCharacteristic:(CBCharacteristic *)characteristic /* 特征 */
type:(CBCharacteristicWriteType)type;/* 寫入類型 */
寫入類型目前只有2種方式:
/* 寫入類型,決定要不要調(diào)用代理方法 */
typedef NS_ENUM(NSInteger, CBCharacteristicWriteType) {
CBCharacteristicWriteWithResponse = 0, //有回調(diào)的寫入
CBCharacteristicWriteWithoutResponse //沒回調(diào)的寫入
};
下面是設(shè)備作為中央設(shè)備的實例:
#import "CentralViewController.h"
#import <CoreBluetooth/CoreBluetooth.h>
#define kPeripheralName @"Liuting's Device" //外圍設(shè)備名稱
#define kServiceUUID @"FFA0-FFB0" //服務(wù)的UUID
#define kCharacteristicUUID @"FFCC-FFDD" //特征的UUID
@interface CentralViewController ()<CBCentralManagerDelegate,CBPeripheralDelegate>
@property (strong, nonatomic) CBCentralManager *centralManager;/* 中央設(shè)備管理器 */
@property (strong, nonatomic) NSMutableArray *peripherals;/* 連接的外圍設(shè)備 */
@end
@implementation CentralViewController
#pragma mark - UI事件
- (void)viewDidLoad{
[super viewDidLoad];
self.peripherals = [NSMutableArray array];
//創(chuàng)建中心設(shè)備管理器并設(shè)置當(dāng)前控制器視圖為代理
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
#pragma mark - CBCentralManager代理方法
/* 中央設(shè)備管理器狀態(tài)更新后調(diào)用 */
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
switch (central.state) {
case CBPeripheralManagerStatePoweredOn:
NSLog(@"BLE已打開.");
//掃描外圍設(shè)備
[central scanForPeripheralsWithServices:nil options:nil];
break;
default:
NSLog(@"此設(shè)備不支持BLE或未打開藍(lán)牙功能,無法作為中央設(shè)備.");
break;
}
}
/*
* 發(fā)現(xiàn)外圍設(shè)備調(diào)用
* @param central 中央設(shè)備管理器
* @param peripheral 外圍設(shè)備
* @param advertisementData 設(shè)備信息
* @param RSSI 信號質(zhì)量(信號強(qiáng)度)
*/
- (void)centralManager:(CBCentralManager *)central
didDiscoverPeripheral:(CBPeripheral *)peripheral
advertisementData:(NSDictionary *)advertisementData
RSSI:(NSNumber *)RSSI
{
NSLog(@"發(fā)現(xiàn)外圍設(shè)備...");
//連接指定的外圍設(shè)備,匹配設(shè)備名
if ([peripheral.name isEqualToString:kPeripheralName]) {
//添加保存外圍設(shè)備,因為在此方法調(diào)用完外圍設(shè)備對象就會被銷毀
if(![self.peripherals containsObject:peripheral]){
[self.peripherals addObject:peripheral];
}
NSLog(@"開始連接外圍設(shè)備...");
[self.centralManager connectPeripheral:peripheral options:nil];
}
}
/* 中央設(shè)備管理器成功連接到外圍設(shè)備后調(diào)用 */
- (void)centralManager:(CBCentralManager *)central
didConnectPeripheral:(CBPeripheral *)peripheral
{
NSLog(@"連接外圍設(shè)備成功!");
//停止掃描
[self.centralManager stopScan];
//設(shè)置外圍設(shè)備的代理為當(dāng)前視圖控制器
peripheral.delegate = self;
//外圍設(shè)備開始尋找服務(wù)
[peripheral discoverServices:@[[CBUUID UUIDWithString:kServiceUUID]]];
}
/* 中央設(shè)備管理器連接外圍設(shè)備失敗后調(diào)用 */
- (void)centralManager:(CBCentralManager *)central
didFailToConnectPeripheral:(CBPeripheral *)peripheral
error:(NSError *)error
{
NSLog(@"連接外圍設(shè)備失敗!");
}
#pragma mark - CBPeripheral 代理方法
/* 外圍設(shè)備尋找到服務(wù)后調(diào)用 */
- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverServices:(NSError *)error
{
NSLog(@"已發(fā)現(xiàn)可用服務(wù)...");
//遍歷查找到的服務(wù)
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID];
for (CBService *service in peripheral.services) {
if([service.UUID isEqual:serviceUUID]){
//外圍設(shè)備查找指定服務(wù)中的特征,characteristics為nil,表示尋找所有特征
[peripheral discoverCharacteristics:nil forService:service];
}
}
}
/* 外圍設(shè)備尋找到特征后調(diào)用 */
- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverCharacteristicsForService:(CBService *)service
error:(NSError *)error
{
NSLog(@"已發(fā)現(xiàn)可用特征...");
//遍歷服務(wù)中的特征
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID];
if ([service.UUID isEqual:serviceUUID]) {
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID isEqual:characteristicUUID]) {
//情景一:通知
/* 找到特征后設(shè)置外圍設(shè)備為已通知狀態(tài)(訂閱特征):
* 調(diào)用此方法會觸發(fā)代理方法peripheral:didUpdateValueForCharacteristic:error:
* 調(diào)用此方法會觸發(fā)外圍設(shè)備管理器的訂閱代理方法
*/
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
//情景二:讀取
//調(diào)用此方法會觸發(fā)代理方法peripheral:didUpdateValueForCharacteristic:error:
//[peripheral readValueForCharacteristic:characteristic];
}
}
}
}
/* 外圍設(shè)備讀取到特征值后調(diào)用 */
- (void)peripheral:(CBPeripheral *)peripheral
didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error
{
if (characteristic.value) {
NSString *value = [[NSString alloc] initWithData:characteristic.value
encoding:NSUTF8StringEncoding];
NSLog(@"讀取到特征值:%@",value);
}else{
NSLog(@"未發(fā)現(xiàn)特征值.");
}
}
@end
五、藍(lán)牙后臺運行
除非去申請后臺權(quán)限,否則 app 都是只在前臺運行的,程序在進(jìn)入后臺不久便會切換到掛起狀態(tài)。掛起后,程序?qū)o法再接收任何藍(lán)牙事件。
中央設(shè)備管理器連接外圍設(shè)備的方法中的options屬性,可以設(shè)置如下字典值:
CBConnectPeripheralOptionNotifyOnConnectionKey:
在連接成功后,程序被掛起,?給出系統(tǒng)提示。
-
CBConnectPeripheralOptionNotifyOnDisconnectionKey:
在程序掛起,藍(lán)牙連接斷開時,給出系統(tǒng)提示。 -
CBConnectPeripheralOptionNotifyOnNotificationKey:
在程序掛起后,收到 peripheral 數(shù)據(jù)時,給出系統(tǒng)提示。
設(shè)置藍(lán)牙后臺模式:
- 添加
info.plist字段Required background nodes
- 在該字段下添加字符串值:
-
App communicates using CoreBluetooth:表示支持設(shè)備作為中央設(shè)備后臺運行 -
App shares data using CoreBluetooth:表示支持設(shè)備作為外圍設(shè)備后臺運行

設(shè)備作為中央設(shè)備的后臺運行和前臺運行區(qū)別:
- 會將發(fā)現(xiàn)的多個外圍設(shè)備的廣播數(shù)據(jù)包合并為一個事件,然后每找到一個外圍設(shè)備都會調(diào)用發(fā)現(xiàn)外圍設(shè)備的代理方法
- 如果全部的應(yīng)用都在后臺搜索外圍設(shè)備,那么每次搜索的時間間隔會更大。這會導(dǎo)致搜索到外圍設(shè)備的時間變長
設(shè)備作為外圍設(shè)備的后臺運行和前臺運行區(qū)別:
- 在廣播時,廣播數(shù)據(jù)將不再包含外圍設(shè)備的名字
- 外圍設(shè)備只能被明確標(biāo)識了搜索服務(wù)UUID的iOS設(shè)備找到
- 如果所有應(yīng)用都在后臺發(fā)起廣播,那么發(fā)起頻率會降低
關(guān)于后臺運行的細(xì)節(jié),可以參考:CoreBluetooth8 后臺運行藍(lán)牙服務(wù)
上面的代碼Demo點這里:LearnDemo里面的BluetoothDemo