IOS藍牙通訊詳解

前言

最近實驗室做了一個IOS設備之間使用藍牙進行數(shù)據(jù)交互的項目诽里。中間遇到了很多坑纫溃,現(xiàn)在大致講解一下藍牙通訊的流程父能。干貨請直接下翻到第四節(jié)臣镣。

iOS藍牙基礎知識

背景

  • iOS的藍牙不能用來傳輸文件。

  • iOS與iOS設備之間進行數(shù)據(jù)通信谈山,使用gameKit.framework

  • iOS與其他非iOS設備進行數(shù)據(jù)通信俄删,使用coreBluetooth.framework

iOS中藍牙的實現(xiàn)方案iOS中提供了4個框架用于實現(xiàn)藍牙連接:

  • GameKit.framework
用法簡單只能用于iOS設備之間的連接,多用于游戲(比如五子棋對戰(zhàn))奏路,從iOS7開始過期

  • MultipeerConnectivity.framework

只能用于iOS設備之間的連接抗蠢,從iOS7開始引入,主要用于文件共享(僅限于沙盒的文件)

  • ExternalAccessory.framework

可用于第三方藍牙設備交互思劳,但是藍牙設備必須經(jīng)過蘋果MFi認證(國內(nèi)較少)

  • CoreBluetooth.framework(時下熱門)

可用于第三方藍牙設備交互,必須要支持藍牙4.0硬件至少是4s妨猩,系統(tǒng)至少是iOS6藍牙4.0以低功耗著稱潜叛,一般也叫BLE(BluetoothLowEnergy)目前應用比較多的案例:運動手壞、嵌入式設備、智能家居

CoreBluetooth

什么是CoreBluetooth

The Core Bluetooth framework lets your iOS and Mac apps communicate with Bluetooth low energy devices. For example, your app can discover, explore, and interact with low energy peripheral devices, such as heart rate monitors, digital thermostats, and even other iOS devices.

The framework is an abstraction of the Bluetooth 4.0 specification for use with low energy devices. That said, it hides many of the low-level details of the specification from you, the developer, making it much easier for you to develop apps that interact with Bluetooth low energy devices. Because the framework is based on the specification, some concepts and terminology from the specification have been adopted. This chapter introduces you to the key terms and concepts that you need to know to begin developing great apps using the Core Bluetooth framework.

CoreBluetooth框架就是蘋果公司為我們提供的一個庫威兜,我們可以使用這個庫和其他支持藍牙4.0的設備進行數(shù)據(jù)交互销斟。值得注意的是在IOS10之后的APP中,我們需要在 info.plist文件中添加NSBluetoothPeripheralUsageDescription字段否則APP會崩潰

藍牙通訊中的外圍設備和中心設備

通常椒舵,設備之間進行通訊的時候都少不了中心設備和外圍設備蚂踊。一般來說,外圍設備具有一些需要傳遞給中心設備的數(shù)據(jù)笔宿,而中心設備獲取這些數(shù)據(jù)之后犁钟,可以進行相應的數(shù)據(jù)處理。同時泼橘,中心設備處理完數(shù)據(jù)之后涝动,也可以向外圍設備發(fā)送信息。例如炬灭,下圖1-1中外圍設備(心率感應器)將數(shù)據(jù)發(fā)送給IOS或者MAC上的APP中醋粟,即中心設備。

1-1 中心設備和外圍設備

中心設備可以發(fā)現(xiàn)并連接到發(fā)送了廣播的外圍設備

外圍設備向中心設備傳遞數(shù)據(jù)的主要方式是廣播重归。廣播中攜帶的數(shù)據(jù)有限(大致為31字節(jié))米愿,里面包含了外圍設備所想要向中心設備提供的數(shù)據(jù)。例如下圖1-2中鼻吮,一個溫度監(jiān)控儀可能會向外廣播現(xiàn)在房間的溫度育苟,中心設備就能拿到溫度數(shù)據(jù)進行相應的一些操作。所以在BLE技術中狈网,廣播是外圍設備讓其他設備能感知到它的主要方式

1-2 外圍設備廣播

外圍設備中的數(shù)據(jù)結構

外圍設備中包含一個或者多個服務或提供關于連接信號強度的一些信息宙搬。服務是一個數(shù)據(jù)集合,它包含完成一個(或多個)設備某些功能或特性的相關行為拓哺。例如勇垛,一個心率感應器的服務可能攜帶從心率傳感器發(fā)送而來的數(shù)據(jù)。服務本身是由特征或服務(即引用其它服務)組成士鸥。特征則為外圍設備的服務提供了更詳細的細節(jié)闲孤。例如,剛剛提到的心率服務中的特性就可能包含心率設備的位置和心率測量數(shù)據(jù)烤礁。圖1-3展示了這個心率感應設備中的結構讼积。

1-3 外圍設備中的服務和特征

中心設備和外圍設備進行數(shù)據(jù)交互

  • 當中心設備成功連接到一個外圍設備之后,它可以知道外圍設備提供的所以服務和特征(廣播的數(shù)據(jù)可能只包含一部分可用的服務)脚仔。

  • 中心設備可以對外圍設備的服務特征進行讀寫操作從而實現(xiàn)和外圍設備的數(shù)據(jù)交互勤众。例如,一個APP可能會通過溫度感應器獲取房間當前溫度鲤脏,并且通過給溫度感應器傳遞數(shù)據(jù)(像操作空調一樣)改變房間溫度们颜。

中心設備吕朵、外圍設備、外圍設備數(shù)據(jù)的表現(xiàn)形式

本地中心設備對象藍牙數(shù)據(jù)交互方式主要都通過Core Bluetooth框架進行窥突。

  • 當你使用中心端和 遠程外圍設備 進行交互的時候努溃,你的藍牙交互操作基本都在本地中心端執(zhí)行。除非你需要設置一個遠程外圍設備并且通過它對中心設備作出響應阻问,否則你的大部分藍牙交互操作都在中心端進行梧税。

  • 在本地中心端,一個名叫CBCentralManager的對象起著舉足輕重的作用称近。這個類被用來管理發(fā)現(xiàn)或者已經(jīng)連接的遠程外圍設備(通常這些外圍設備都以CBPeripheral對象為存在方式第队,某種程度上可以說CBPeripheral就是外圍設備,CBCentralManager就是中心設備)煌茬,包括掃描斥铺、發(fā)現(xiàn)并且連接到廣播的外圍設備。圖1-4展示了本地中心設備和遠程外圍設備在Core Bluetooth中的表現(xiàn)形式坛善。

1-4 本地中心設備在Core Bluetooth中的表現(xiàn)形式
  • 遠程外圍設備的數(shù)據(jù)由CBServiceCBCharacteristic對象表示> 當你在和遠程外圍設備進行數(shù)據(jù)交互的時候晾蜘,你實際上是在和其服務和特征進行交互。在Core Bluetooth框架中眠屎,服務由CBService對象代表剔交。同樣的,特征也由CBCharacteristic對象代表改衩。圖1-5闡述了外圍設備中的結構信息岖常。
1-5 外圍設備的樹狀結構

本地外圍設備對象

在IOS6和OS X v10.9之后,Mac和IOS設備都能夠作為 本地外圍設備 給包括Mac葫督、iPhone竭鞍、和iPad的設備分享數(shù)據(jù)。當你實現(xiàn)本地外圍設備角色功能橄镜,在藍牙交互角色中偎快,你就表現(xiàn)為外圍設備。

  • 在遠程外圍設備端洽胶,本地外圍設備由CBPeripheralManager對象作為代表晒夹。這些對象被用來管理發(fā)布外圍設備服務和特征數(shù)據(jù)并實現(xiàn)對中心設備的廣播。它也用來回應中心設備的讀寫操作姊氓。圖1-6展示了外圍設備在藍牙交互中的角色信息丐怯。
1-6 外圍設備在Core Bluetooth中的表現(xiàn)形式
  • 本地外圍設備由CBMutableServiceCBMutableCharacteristic對象代表> 當你和本地外圍設備進行數(shù)據(jù)處理的時候,你其實是在和服務和特征的可變版本打交道翔横。在Core Bluetooth框架中读跷,本地外圍設備的服務由CBMutableService代表。同樣禾唁,本地外圍設備特種由CBMutableCharacteristic代表舔亭。圖1-7傳輸了本地外圍設備服務和特征的樹狀結構些膨。
1-7 本地外圍設備服務和特征的樹狀結構

藍牙通訊應用實例

對藍牙基礎知識有了一個大致了解之后,我們現(xiàn)在利用CoreBluetooth框架進行實戰(zhàn)钦铺。我們需要外圍設備和中心設備模式,所以創(chuàng)建兩個分別名為BluetoothCentralTestBluetoothPeripheralTest的項目肢预。 在后期我們需要測試藍牙的時候矛洞,如果只有一個IOS設備,我們可以下載一個名為 LightBlue 的軟件用來模擬另一個藍牙設備

創(chuàng)建外圍設備

  • 外圍設備的工作流程為:

1烫映、開啟外圍設備管理

2沼本、設置服務、特征锭沟、描述等信息

3抽兆、開始廣播

  • 外圍設備和中心設備的數(shù)據(jù)交互可以用通知的形式來進行或者通過- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests這兩個方法來進行。 其中通知主要是中心設備訂閱外圍設備族淮,一般用作外圍設備單方面向中心設備發(fā)送數(shù)據(jù)

  • 我創(chuàng)建外圍設備是以單例的方式來創(chuàng)建辫红,代碼如下,注意:在.h文件中需要聲明協(xié)議CBPeripheralManagerDelegate


//

//LARPeripheralManager.m

//BlueToothPeripheralTest

//

//Created by柳鈺柯on 2016/12/4.

//Copyright ? 2016年柳鈺柯. All rights reserved.

//

#import"LARPeripheralManager.h"

staticNSString *constServiceUUID1 =@"FFF0";

staticNSString *constnotiyCharacteristicUUID =@"FFF1";

staticNSString *constreadwriteCharacteristicUUID =@"FFF2";

staticNSString *constServiceUUID2 =@"FFE0";

staticNSString *constreadCharacteristicUUID =@"FFE1";

staticNSString *constLocalNameKey =@"iPhone";

@implementationLARPeripheralManager{

//外圍設備管理器

CBPeripheralManager *peripheralManager;

//定時器

NSTimer *timer;

}

+ (instancetype)shareInstance

{

staticLARPeripheralManager *peripheral;

staticdispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

peripheral = [[selfalloc] init];

});

returnperipheral;

}

- (instancetype)init

{

if(self= [superinit]) {

NSLog(@"外圍設備單例創(chuàng)建");

peripheralManager = [[CBPeripheralManager alloc]initWithDelegate:selfqueue:nil];

}

returnself;

}

//初始化一些UUID和特征信息,此處設置的一些信息祝辣,在中心設備中可以根據(jù)需要進行過濾

- (void)setUp

{

// characteristic字段描述

CBUUID *CBUUIDCharacteristicUserDescriptionStringUUID = [CBUUID UUIDWithString:CBUUIDCharacteristicUserDescriptionString];

/*

可以通知的Characteristic

properties:CBCharacteristicPropertyNotify

permissions: CBAttributePermissionsReadable

*/

CBMutableCharacteristic *notiyCharacteristic = [[CBMutableCharacteristic alloc]initWithType:[CBUUID UUIDWithString:notiyCharacteristicUUID] properties:CBCharacteristicPropertyNotify value:nilpermissions:CBAttributePermissionsReadable];

/*

可讀寫的characteristics

properties:CBCharacteristicPropertyWrite | CBCharacteristicPropertyRead

permissions CBAttributePermissionsReadable | CBAttributePermissionsWriteable

*/

CBMutableCharacteristic *readwriteCharacteristic = [[CBMutableCharacteristic alloc]initWithType:[CBUUID UUIDWithString:readwriteCharacteristicUUID] properties:CBCharacteristicPropertyWrite | CBCharacteristicPropertyRead value:nilpermissions:CBAttributePermissionsReadable | CBAttributePermissionsWriteable];

//設置descriptor

CBMutableDescriptor *readwriteCharacteristicDescription1 = [[CBMutableDescriptor alloc]initWithType: CBUUIDCharacteristicUserDescriptionStringUUID value:@"name"];

[readwriteCharacteristic setDescriptors:@[readwriteCharacteristicDescription1]];

/*

只讀的Characteristic

properties:CBCharacteristicPropertyRead

permissions CBAttributePermissionsReadable

*/

CBMutableCharacteristic *readCharacteristic = [[CBMutableCharacteristic alloc]initWithType:[CBUUID UUIDWithString:readCharacteristicUUID] properties:CBCharacteristicPropertyRead value:nilpermissions:CBAttributePermissionsReadable];

//service1初始化并加入兩個characteristics

CBMutableService *service1 = [[CBMutableService alloc]initWithType:[CBUUID UUIDWithString:ServiceUUID1] primary:YES];

[service1 setCharacteristics:@[notiyCharacteristic,readwriteCharacteristic]];

//service2初始化并加入一個characteristics

CBMutableService *service2 = [[CBMutableService alloc]initWithType:[CBUUID UUIDWithString:ServiceUUID2] primary:YES];

[service2 setCharacteristics:@[readCharacteristic]];

//添加后就會調用代理的- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error

[peripheralManager addService:service1];

[peripheralManager addService:service2];

}

#pragma mark - <CBPeripheralManagerDelegate>

//檢測藍牙狀態(tài)變化贴妻,當藍牙狀態(tài)改變時,自動回調

- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral

{

switch(peripheral.state) {

//在這里判斷藍牙設別的狀態(tài)當開啟了則可調用setUp方法(自定義)

caseCBManagerStatePoweredOn:

NSLog(@"powered on");

//運行初始化方法

[selfsetUp];

break;

caseCBManagerStatePoweredOff:

NSLog(@"powered off");

break;

default:

break;

}

}

//添加了服務蝙斜,添加服務后需要廣播名惩,一旦廣播,外圍設備就可以被中心設備發(fā)現(xiàn)孕荠,同樣外圍設備所攜帶的數(shù)據(jù)也能被中心設備捕獲

- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error

{

if(error) {

NSLog(@"%@",[error localizedDescription]);

return;

}

//添加服務后娩鹉,發(fā)送廣播

//發(fā)送廣播后會自動調用

// - (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error

[peripheralManager startAdvertising:@{

CBAdvertisementDataServiceUUIDsKey :@[[CBUUID UUIDWithString:ServiceUUID1],[CBUUID UUIDWithString:ServiceUUID2]],

CBAdvertisementDataLocalNameKey : LocalNameKey

}];

}

//通知發(fā)送了廣播

- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error

{

NSLog(@"已經(jīng)開始廣播");

}

//中心設備訂閱特征后會調用這個方法

- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic

{

NSLog(@"訂閱了%@的數(shù)據(jù)",characteristic.UUID);

//分配定時任務

timer = [NSTimer scheduledTimerWithTimeInterval:1

target:self

selector:@selector(sendData:)

userInfo:characteristic

repeats:YES];

}

//中心設備取消訂閱特征后調用這個方法

-(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic{

NSLog(@"取消訂閱%@的數(shù)據(jù)",characteristic.UUID);

//取消定時器

[timer invalidate];

}

//發(fā)送數(shù)據(jù)

- (void)sendData:(NSTimer *)t{

CBMutableCharacteristic *characteristic = t.userInfo;

if([peripheralManager updateValue:[[NSString stringWithFormat:@"Sending Data"] dataUsingEncoding:NSUTF8StringEncoding]forCharacteristic:characteristic onSubscribedCentrals:nil]) {

NSLog(@"發(fā)送數(shù)據(jù)成功");

}else{

NSLog(@"發(fā)送數(shù)據(jù)錯誤");

}

}

//中心設備讀characteristics請求

- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request{

NSLog(@"didReceiveReadRequest");

//判斷是否有讀數(shù)據(jù)的權限

if(request.characteristic.properties & CBCharacteristicPropertyRead) {

//NSData *data = request.characteristic.value;

NSData *data = [[NSString stringWithFormat:@"通過characteristics讀請求"] dataUsingEncoding:NSUTF8StringEncoding];

[request setValue:data];

//對請求作出成功響應

[peripheralManager respondToRequest:request withResult:CBATTErrorSuccess];

}else{

[peripheralManager respondToRequest:request withResult:CBATTErrorWriteNotPermitted];

}

}

//外圍設備寫characteristics請求

- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests{

NSLog(@"didReceiveWriteRequests");

CBATTRequest *request = requests[0];

//判斷是否有寫數(shù)據(jù)的權限

if(request.characteristic.properties & CBCharacteristicPropertyWrite) {

//需要轉換成CBMutableCharacteristic對象才能進行寫值

CBMutableCharacteristic *c =(CBMutableCharacteristic *)request.characteristic;

c.value = request.value;

NSLog(@"收到中心設備發(fā)送信息:%@",[[NSString alloc] initWithData:c.value encoding:NSUTF8StringEncoding]);

[peripheralManager respondToRequest:request withResult:CBATTErrorSuccess];

}else{

[peripheralManager respondToRequest:request withResult:CBATTErrorWriteNotPermitted];

}

}

//外圍設備更新描述后調用

- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral{

NSLog(@"peripheralManagerIsReadyToUpdateSubscribers");

}

@end

  • 我們嘗試用lighblue來鏈接一下外圍設備試試,結果如圖
外圍設備運行結果

創(chuàng)建中心設備

  • 中心設備的工作流程為:

1、創(chuàng)建中心設備
2稚伍、發(fā)現(xiàn)外圍設備
3弯予、鏈接外圍設備
4、發(fā)現(xiàn)服務和特征

4.1 獲取服務
4.2 獲取特征值
4.3 獲取特征描述

5槐瑞、 數(shù)據(jù)交互
6熙涤、 訂閱通知
7、 斷開鏈接

  • 中心設備中讀取外圍設備的數(shù)據(jù)可以使用訂閱外圍設備通知或者是調用[peripheral readValueForCharacteristic:<#(nonnull CBCharacteristic *)#>][peripheral readValueForDescriptor:<#(nonnull CBDescriptor *)#>]方法來獲取特征或者描述的數(shù)據(jù)困檩,至于需要獲取那一層的祠挫,則需要自己定義。* 我是在特征值這一層通過訂閱外圍設備通知的方式獲取數(shù)據(jù)悼沿,所以需要在- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error掃描到匹配的特征后等舔,進行數(shù)據(jù)訂閱。

  • 值得注意的是糟趾,中心設備掃描到外圍設備后慌植,想要保持連接甚牲,需要將外圍設備保留下來〉粒可以使用一個強引用變量引用丈钙,也可以將外圍設備添加到數(shù)組。推薦使用后者

  • 同樣交汤,也需要遵守CBCentralManagerDelegateCBPeripheralDelegate協(xié)議


//

//LARCentralBlueTooth.m

//Unity-iPhone

//

//Created by柳鈺柯on 2016/11/18.

//

//

#import"LARCentralBlueTooth.h"

staticNSString *constServiceUUID1 =@"FFF0";

staticNSString *constnotiyCharacteristicUUID =@"FFF1";

staticNSString *constreadwriteCharacteristicUUID =@"FFF2";

@interfaceLARCentralBlueTooth ()

/**系統(tǒng)藍牙管理對象*/

@property(strong,nonatomic,readwrite) CBCentralManager *manager;

/**掃描到的設備*/

@property(strong,nonatomic,readwrite) NSMutableArray *discoverPeripheral;

/**當前連接設備*/

@property(strong,nonatomic) CBPeripheral *currentPeripheral;

@end

@implementationLARCentralBlueTooth

+ (instancetype)shareInstance{

staticLARCentralBlueTooth *blueTooth;

staticdispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

blueTooth = [[selfalloc] init];

});

returnblueTooth;

}

- (instancetype)init

{

if(self= [superinit]){

NSLog(@"單例實例化");

_manager = [[CBCentralManager alloc] initWithDelegate:selfqueue:dispatch_get_global_queue(0,0)];

_discoverPeripheral = [[NSMutableArray alloc] init];

}

returnself;

}

#pragma mark -

//檢查設備藍牙開關的狀態(tài)

- (void)centralManagerDidUpdateState:(CBCentralManager *)central

{

if(central.state == CBManagerStatePoweredOn) {

NSLog(@"藍牙已打開");

//開始掃描設備

//掃描到設備之后會進入

//-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI方法

[_manager scanForPeripheralsWithServices:niloptions:nil];

}else{

NSLog(@"藍牙已關閉");

}

}

//發(fā)現(xiàn)設備后,根據(jù)過濾設置進行連接

-(void)centralManager:(CBCentralManager *)central

didDiscoverPeripheral:(CBPeripheral *)peripheral

advertisementData:(NSDictionary *)advertisementData

RSSI:(NSNumber *)RSSI

{

NSLog(@"搜索到了設備%@",peripheral.name);

//我的另外一個設備的名字以閆開頭雏赦,可以在這里自行設置過濾

if([peripheral.name hasPrefix:@"閆"]) {

//持有設備

if(![self.discoverPeripheral containsObject:peripheral]) {

//數(shù)組或者變量保留外圍設備二者選其一

//使用數(shù)組保留外圍設備引用

// [self.discoverPeripheral addObject:peripheral];

//使用一個strong變量強引用持有外圍設備

self.currentPeripheral = peripheral;

//連接設備

[_manager connectPeripheral:peripheral options:nil];

NSLog(@"準備連接設備%@",peripheral.name);

}

}

}

#pragma mark -連接狀態(tài)

//連接設備失敗自動調用

- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error

{

NSLog(@">>>連接%@失敗>>>錯誤:%@",peripheral.name,[error localizedDescription]);

}

//斷開連接自動調用

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral

{

NSLog(@">>>斷開%@連接",peripheral.name);

}

//連接成功自動調用

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral

{

NSLog(@">>>連接%@成功",peripheral.name);

//設置外圍設備代理

[peripheral setDelegate:self];

//開始掃描外圍設備的服務

//掃描到服務會進入

// - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error

[peripheral discoverServices:nil];

}

#pragma mark -

//掃描到設備的服務后會進入這個方法

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error

{

if(error){

NSLog(@"掃描服務錯誤:%@",[error localizedDescription]);

}else{

for(CBService *serverinperipheral.services) {

//掃描服務的特征

//掃描到后會進入

// - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error

[peripheral discoverCharacteristics:nilforService:server];

NSLog(@"搜索到了一個服務:%@",server.UUID.UUIDString);

}

}

}

//掃描到服務的特征值

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error

{

if(error) {

NSLog(@"掃描服務:%@的特征值錯誤:%@",service.UUID,[error localizedDescription]);

return;

}

//獲取到特征值

for(CBCharacteristic *characteristicinservice.characteristics){

if([characteristic.UUID isEqual:[CBUUID UUIDWithString:notiyCharacteristicUUID]]) {

//訂閱特征值的數(shù)據(jù)

[selfnotifyCharacteristic:peripheral characteristic:characteristic];

//讀取發(fā)送的數(shù)據(jù)

[peripheral readValueForCharacteristic:characteristic];

}

}

}

//當獲取到外圍設備更新的描述信息后(即數(shù)據(jù))會調用此方法

-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{

if(error)

{

NSLog(@"更新特征值數(shù)據(jù): %@錯誤: %@", characteristic.UUID,[error localizedDescription]);

}

//這里對收到的數(shù)據(jù)進行處理,需要和發(fā)送端一致

if(characteristic.value !=nil) {

NSString *data = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];

NSLog(@"收到外圍設備發(fā)送的信息:%@",data);

[peripheral writeValue:[[NSString stringWithFormat:@"get"] dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];

}

}

//設置通知

- (void)notifyCharacteristic:(CBPeripheral *)peripheral

characteristic:(CBCharacteristic *)characteristic{

NSLog(@"訂閱通知成功");

//設置通知

[peripheral setNotifyValue:YESforCharacteristic:characteristic];

}

//取消通知

- (void)cancelNotifyCharacteristic:(CBPeripheral *)peripheral

characteristic:(CBCharacteristic *)characteristic{

[peripheral setNotifyValue:NOforCharacteristic:characteristic];

}

//停止掃描并斷開連接

-(void)disconnectPeripheral:(CBCentralManager *)centralManager

peripheral:(CBPeripheral *)peripheral{

//停止掃描

[centralManager stopScan];

//斷開連接

[centralManager cancelPeripheralConnection:peripheral];

}

@end

  • 測試結果如下圖所示:
中心設備獲取數(shù)據(jù)

結語

  • 寫了幾個小時終于寫完了芙扎,覺得不錯的話星岗,請點個贊~
  • 這個也是我自己琢磨、學習了幾天之后學會的戒洼,難免有錯誤俏橘,請發(fā)現(xiàn)錯誤后聯(lián)系我,我會及時糾正圈浇。謝謝寥掐!
  • 如果有疑問,歡迎留言或者給我發(fā)郵件:449618602@qq.com
  • 項目地址:藍牙Demo
  • 不要臉的安利一下自己的博客地址,博客搭建好沒多久汉额,后續(xù)會平均一周更新一次:Larry代碼成詩

參考

Core Bluetooth Overview

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末曹仗,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蠕搜,更是在濱河造成了極大的恐慌怎茫,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妓灌,死亡現(xiàn)場離奇詭異轨蛤,居然都是意外死亡,警方通過查閱死者的電腦和手機虫埂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門祥山,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人掉伏,你說我怎么就攤上這事缝呕。” “怎么了斧散?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵供常,是天一觀的道長。 經(jīng)常有香客問我鸡捐,道長栈暇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任箍镜,我火速辦了婚禮源祈,結果婚禮上煎源,老公的妹妹穿的比我還像新娘。我一直安慰自己香缺,他們只是感情好手销,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著图张,像睡著了一般原献。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上埂淮,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機與錄音写隶,去河邊找鬼倔撞。 笑死,一個胖子當著我的面吹牛慕趴,可吹牛的內(nèi)容都是我干的痪蝇。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼冕房,長吁一口氣:“原來是場噩夢啊……” “哼躏啰!你這毒婦竟也來了?” 一聲冷哼從身側響起耙册,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤给僵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后详拙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體帝际,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年饶辙,在試婚紗的時候發(fā)現(xiàn)自己被綠了蹲诀。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡弃揽,死狀恐怖脯爪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情矿微,我是刑警寧澤痕慢,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站冷冗,受9級特大地震影響守屉,放射性物質發(fā)生泄漏。R本人自食惡果不足惜蒿辙,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一拇泛、第九天 我趴在偏房一處隱蔽的房頂上張望滨巴。 院中可真熱鬧,春花似錦俺叭、人聲如沸恭取。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蜈垮。三九已至,卻和暖如春裕照,著一層夾襖步出監(jiān)牢的瞬間攒发,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工晋南, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留惠猿,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓负间,卻偏偏與公主長得像偶妖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子政溃,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 隨著智能家具趾访、智能穿戴等的興起,藍牙開發(fā)應用越來越廣泛董虱,有關藍牙方面的問題扼鞋,今天就給大家進行詳細的講解,想要了解藍...
    知易行難880721閱讀 602評論 0 0
  • Guide to BluetoothSecurity原文 本出版物可免費從以下網(wǎng)址獲得:https://doi.o...
    公子小水閱讀 7,984評論 0 6
  • 前言# 什么是藍牙?#### 隨著藍牙低功耗技術BLE(Bluetooth Low Energy)的發(fā)展空扎,藍牙技術...
    maybe_mylove閱讀 966評論 1 5
  • 其實在我們生活當中藏鹊,很多人都已經(jīng)沒有夢想了,他們有的只是幻想转锈。因為他們從來都沒有或者沒有能力為來支撐自己...
    感恩成長路閱讀 551評論 1 8
  • 有一天醒來盘寡,腦袋一片空白 有一天睡去,夢境卻清楚明白 ——《現(xiàn)在才明白》
    長椅閱讀 121評論 0 0