概述
詳細
一、藍牙常見名稱和縮寫
-
BLE:(Bluetooth low energy)藍牙4.0設備因為低耗電
-
BLE:(Bluetooth low energy)藍牙4.0設備因為低耗電
-
Central:中心設備,發起藍牙連接的設備(一般是指手機)
-
Peripheral:外設,被藍牙連接的設備(一般是運動手環)
-
Service and Characteristic:服務和特征,每個設備會提供服務和特征,類似於服務端的API,但是結構不同,每個設備會有很多服務,每個服務中包含很多特征,這些特征的權限一般分為讀(read),寫(write),通知(notify)幾種,就是我們連接設備后具體需要操作的內容
-
Description:描述,每個Characteristic可以對應一個或者多個Description用於描述Characteristic的信息或屬性
二、藍牙基礎知識
1、CoreBluetooth框架的核心其實是倆東西
-
Peripheral
-
Central

2、這兩組api分別對應不同的業務常見
-
左側叫中心模式,就是以你的app作為中心,連接其他的外設的場景
-
右側稱為外設模式,使用外設連接其他中心設備操作的場景
3、服務和特征(service and characteristic)
-
每個設備都會有1個or多個服務
-
每個服務里都會有1個or多個特征
-
特征就是具體鍵值對,提供數據的地方
-
每個特征屬性分為:讀,寫,通知等等
外設,服務,特征的關系

三、BLE中心模式流程
1、建立中心角色
2、掃描外設(Discover Peripheral)
3、連接外設(Connect Peripheral)
4、掃描外設中的服務和特征(Discover Services And Characteristics)
4.1 獲取外設的services
4.2 獲取外設的Characteristics,獲取characteristics的值
4.3 獲取Characteristics的Descriptor和Descriptor的值
5、利用特征與外設做數據交互
6、訂閱Characteristic的通知
7、斷開連接(Disconnect)
四、准備工作
1、一台蘋果設備,進行真機測試
2、一個藍牙模塊或者外設
五、程序實現
項目代碼截圖:

以下是實現的過程:
1、導入依賴庫、聲明委托、定義變量
#import "ViewController.h" #import <CoreBluetooth/CoreBluetooth.h> #define mBLEName @"ZJ2" @interface ViewController () <CBCentralManagerDelegate, CBPeripheralDelegate> //手機設備 @property (nonatomic, strong) CBCentralManager *mCentral; //外設設備 @property (nonatomic, strong) CBPeripheral *mPeripheral; //特征值 @property (nonatomic, strong) CBCharacteristic *mCharacteristic; //服務 @property (nonatomic, strong) CBService *mService; //描述 @property (nonatomic, strong) CBDescriptor *mDescriptor; @end
2、程序開始時初始化設備
- (CBCentralManager *)mCentral
{
if (!_mCentral) {
_mCentral = [[CBCentralManager alloc] initWithDelegate:self
queue:dispatch_get_main_queue()
options:nil];
}
return _mCentral;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//中心管理者初始化
[self mCentral];
}
3、當程序退出時,記得斷開連接
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
// 停止掃描
if([self.mCentral isScanning]){
NSLog(@"stopScan");
[self.mCentral stopScan];
}
//停止連接
if(nil != self.mPeripheral && self.mPeripheral.state == CBPeripheralStateConnecting){
NSLog(@"cancelPeripheralConnection");
[self.mCentral cancelPeripheralConnection:self.mPeripheral];
}
}
4、掃描外設
//只要中心管理者初始化,就會觸發此代理方法
- (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.mCentral scanForPeripheralsWithServices:nil // 通過某些服務篩選外設
options:nil]; // dict,條件
}
break;
default:
break;
}
}
5、連接外設
//發現外設后調用的方法
- (void)centralManager:(CBCentralManager *)central // 中心管理者
didDiscoverPeripheral:(CBPeripheral *)peripheral // 外設
advertisementData:(NSDictionary *)advertisementData // 外設攜帶的數據
RSSI:(NSNumber *)RSSI // 外設發出的藍牙信號強度
{
NSLog(@"搜索到設備名:%@,設備ID:%@",peripheral.name,peripheral.identifier);
//(ABS(RSSI.integerValue) > 35)
//發現完之后就是進行連接
if([peripheral.name isEqualToString:mBLEName]){
self.mPeripheral = peripheral;
self.mPeripheral.delegate = self;
[self.mCentral connectPeripheral:peripheral options:nil];
}
}
6、獲取服務
//中心管理者連接外設成功
- (void)centralManager:(CBCentralManager *)central // 中心管理者
didConnectPeripheral:(CBPeripheral *)peripheral // 外設
{
NSLog(@"設備連接成功,設備名:%@", peripheral.name);
//7、外設發現服務,傳nil代表不過濾
[self.mPeripheral discoverServices:nil];
}
// 外設連接失敗
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@"設備連接失敗,設備名:%@", peripheral.name);
}
// 丟失連接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@"設備丟失連接,設備名:%@", peripheral.name);
}
7、獲取服務中的特征
//發現外設的服務后調用的方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
// 是否獲取失敗
if (error) {
NSLog(@"設備獲取服務失敗,設備名:%@", peripheral.name);
return;
}
for (CBService *service in peripheral.services) {
self.mService = service;
NSLog(@"設備獲取服務成功,服務名:%@,服務UUID:%@,服務數量:%lu",service,service.UUID,peripheral.services.count);
//外設發現特征
[peripheral discoverCharacteristics:nil forService:service];
}
}
8、獲取特征中的值和描述
//從服務中發現外設特征的時候調用的代理方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
if(error){
NSLog(@"設備獲取特征失敗,設備名:%@", peripheral.name);
return;
}
/**
CBCharacteristicPropertyRead = 0x02,
CBCharacteristicPropertyWriteWithoutResponse = 0x04,
CBCharacteristicPropertyWrite = 0x08,
CBCharacteristicPropertyNotify = 0x10,
*/
for (CBCharacteristic *cha in service.characteristics) {
if(cha.properties & CBCharacteristicPropertyWrite){
NSLog(@"CBCharacteristicPropertyWrite");
NSLog(@"%lu",cha.properties & CBCharacteristicPropertyWrite);
self.mCharacteristic = cha;
}else if(cha.properties & CBCharacteristicPropertyWriteWithoutResponse){
NSLog(@"CBCharacteristicPropertyWriteWithoutResponse");
}else if(cha.properties & CBCharacteristicPropertyRead){
NSLog(@"CBCharacteristicPropertyRead");
}else if(cha.properties & CBCharacteristicPropertyNotify){
NSLog(@"CBCharacteristicPropertyNotify");
}else if(cha.properties & CBCharacteristicPropertyIndicate){
NSLog(@"CBCharacteristicPropertyIndicate");
}
NSLog(@"設備獲取特征成功,服務名:%@,特征值名:%@,特征UUID:%@,特征數量:%lu",service,cha,cha.UUID,service.characteristics.count);
//獲取特征對應的描述 會回調didDiscoverDescriptorsForCharacteristic
[peripheral discoverDescriptorsForCharacteristic:cha];
//獲取特征的值 會回調didUpdateValueForCharacteristic
[peripheral readValueForCharacteristic:cha];
}
if(nil != self.mCharacteristic){
//打開外設的通知,否則無法接受數據
[peripheral setNotifyValue:YES forCharacteristic:self.mCharacteristic];
}
}
9、讀取特征中的值和描述
//更新特征值的時候調用,可以理解為獲取藍牙發回的數據
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
NSString *value = [[NSString alloc] initWithData:characteristic.value encoding:NSASCIIStringEncoding];
NSLog(@"特征名:%@,特征值:%@",characteristic,value);
if([value isEqualToString:@"open"]){
}else if([value isEqualToString:@"close"]){
}
}
10、狀態改變和發現描述
//通知狀態改變時調用
-(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
if(error){
NSLog(@"特征名:%@,改變通知狀態失敗",characteristic);
}
NSLog(@"特征名:%@,改變了通知狀態",characteristic);
}
//發現外設的特征的描述數組
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error
{
if(error){
NSLog(@"設備獲取描述失敗,設備名:%@", peripheral.name);
return;
}
for (CBDescriptor *descriptor in characteristic.descriptors) {
self.mDescriptor = descriptor;
[peripheral readValueForDescriptor:descriptor];
NSLog(@"設備獲取描述成功,描述名:%@",descriptor);
}
}
11、發送數據
//發送數據
-(void)sendDataToBLE:(NSString *)data{
NSData* myData = [data dataUsingEncoding:NSUTF8StringEncoding];
[self.mPeripheral writeValue:myData // 寫入的數據
forCharacteristic:self.mCharacteristic // 寫給哪個特征
type:CBCharacteristicWriteWithResponse];// 通過此響應記錄是否成功寫入
}
-(void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
NSLog(@"數據發送成功");
}
六、運行效果
從電腦串口助手可以看到,發送了兩次的D3數據,手機也收到了兩次11的數據

這里使用的是藍牙模塊Risym cc2541和蘋果手機實現兩者的通信功能,根據BLE中心模式流程走就可以了
下面是手機設備NSLog打印輸出的結果,從連接到發送數據和接收數據的過程。

(查看大圖)
可以發現連接成功后,設備有兩個服務,第一個服務對應有九個特征值,第二個服務對應有一個特征值,驗證了上面的原理是正確的

(查看大圖)
七、其他補充
CSDN博客地址:http://blog.csdn.net/qq_30379689/article/details/61413950
CSDN課程地址:http://edu.csdn.net/course/detail/4534
注:本文著作權歸作者,由demo大師發表,拒絕轉載,轉載需要作者授權
