藍牙通信

在iOS開發(fā)中榄审,實現(xiàn)藍牙通信有兩種方式链患,一種是使用傳統(tǒng)的GameKit.framework,另一種就是使用在iOS 5中加入的CoreBluetooth.framework蛹批。

利用CoreBluetooth框架仰泻,我們可以輕松實現(xiàn)兩個iOS設(shè)備荆陆、iOS設(shè)備與非iOS藍牙設(shè)備的交互。要注意的一點是目前這個框架只能支持藍牙4.0BLE標準集侯,所以對硬件上是有一定要求的被啼,iPhone 4S及以后的設(shè)備,第三代iPad及以后的設(shè)備是支持這一標準的棠枉。

術(shù)語解釋

我們首先看一下CoreBluetooth框架的結(jié)構(gòu)浓体。這是CoreBluetooth/CoreBluetooth.h文件中的聲明。

#ifndef?_CORE_BLUETOOTH_H_

#define?_CORE_BLUETOOTH_H_

#endif

#import?#import?#import?#import?#import?#import?#import?#import?#import?#import?#import

其中辈讶,CBCentral開頭的都是中心設(shè)備類命浴,CBPeripheral開頭的都是外設(shè)類。這就要講到藍牙設(shè)備的兩個角色了荞估。

中心設(shè)備:中心設(shè)備可以理解為是處理數(shù)據(jù)的iOS設(shè)備,比如你的 iPhone稚新、iPad 等勘伺。

外設(shè):外設(shè)顧名思義,就是產(chǎn)生數(shù)據(jù)的外部設(shè)備褂删。這個外部設(shè)備可以是單片機飞醉、嵌入式設(shè)備甚至是另一個iOS設(shè)備等等。外設(shè)可以通過其傳感器等產(chǎn)生有用數(shù)據(jù)屯阀,數(shù)據(jù)后通過藍牙傳給中心設(shè)備使用缅帘。

在建立連接的之前,外設(shè)向外發(fā)出廣播數(shù)據(jù)(advertisementData难衰,官方描述“A dictionary containing any advertisement and scan response data.”)钦无,廣播數(shù)據(jù)是一個字典類數(shù)據(jù),中心設(shè)備可以獲取一定范圍內(nèi)的外設(shè)發(fā)出的廣播數(shù)據(jù)盖袭。

現(xiàn)在開始

初始化

為了使用CoreBluetooth框架中的回調(diào)方法失暂,我們要使用CBCentralManagerDelegate、CBPeripheralDelegate這兩個協(xié)議鳄虱。

我們先要初始化一個CBCentralManager類的對象弟塞。代碼如下:

@interface?SKBluetoothManager?:?NSObject{

CBCentralManager?*manager;

id?delegate;

}

manager?=?[[CBCentralManager?alloc]?initWithDelegate:self?queue:nil];

manager.delegate?=?self;

掃描外設(shè)

初始化完成,我們就可以讓管理器開始掃描外設(shè)了:

[manager?scanForPeripheralsWithServices:nil?options:nil];

在設(shè)備發(fā)現(xiàn)周圍外設(shè)的advertisementData后拙已,會回調(diào)這個方法:

-?(void)centralManager:(CBCentralManager?*)central?didDiscoverPeripheral:(CBPeripheral?*)peripheral?advertisementData:(NSDictionary?*)advertisementData?RSSI:(NSNumber?*)RSSI;

其中參數(shù)central指回調(diào)這個方法的中心設(shè)備决记,peripheral指發(fā)現(xiàn)的外設(shè)對象CBPeripheral,advertisementData就是前面說的字典類型廣播數(shù)據(jù)倍踪,RSSI是當前外設(shè)的信號強度系宫,單位是dbm索昂。

剛開始對陌生的藍牙設(shè)備調(diào)試時,建議我們先用一個數(shù)組NSArray將所掃描到的外設(shè)進行保存:

[_peripherals?addObject:peripheral];

連接外設(shè)

保存后笙瑟,可根據(jù)設(shè)備的UUID來確定該設(shè)備是否為我們需要進行操作的藍牙設(shè)備楼镐,在確認外設(shè)身份后,即可發(fā)起對外設(shè)的連接操作:

if?([peripheral.identifier.UUIDString?isEqualToString:kPeripheralUUID])?{

[manager?stopScan];

[manager?connectPeripheral:peripheral?options:nil];

NSLog(@"連接外設(shè):%@",peripheral.description);

self.peripheral?=?peripheral;

}

在此步操作后往枷,我們完成了對藍牙設(shè)備的掃描工作框产,接下來的回調(diào)方法分為兩種情況:

連接到外設(shè)后

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

NSLog(@"已經(jīng)連接到:%@",?peripheral.description);

peripheral.delegate?=?self;

[central?stopScan];

[peripheral?discoverServices:nil];

}

一旦連接好外設(shè),我們就可以馬上停止掃描错洁。然后發(fā)起對服務的搜索:

-?(void)discoverServices:(NSArray?*)serviceUUIDs;

此處參數(shù)位需要掃描的服務的UUID的數(shù)組秉宿。文檔中特別提到,若該參數(shù)為nil屯碴,將會掃描所有的服務描睦。

連接失敗后

在連接外設(shè)失敗的回調(diào)方法中,提供了error參數(shù)导而,可根據(jù)實際需要來做異常處理忱叭,在此不做過多說明

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

NSLog(@"連接%@失敗",peripheral);

}

在搜索到藍牙設(shè)備的服務后,將會回調(diào)

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

若有錯誤發(fā)生今艺,通過NSError異常處理韵丑。

掃描服務

由于服務在peripheral里是以NSArray的形式存在的,所以我們要對peripheral中的所有服務進行遍歷:

for?(CBService?*service?in?peripheral.services)?{

//發(fā)現(xiàn)服務

if?([service.UUID?isEqual:[CBUUID?UUIDWithString:kServiceUUID]])?{

NSLog(@"發(fā)現(xiàn)服務:%@",?service.UUID);

[peripheral?discoverCharacteristics:nil?forService:service];

break;

}

}

掃描特征值

在遍歷中虚缎,趁熱打鐵撵彻,直接對其特征值進行掃描,

[peripheral?discoverCharacteristics:nil?forService:service];

這里與掃描service是相同的实牡,若掃描所有的特征值陌僵,直接傳入nil作為參數(shù)即可。

這里的kServiceUUID是我們根據(jù)藍牙設(shè)備的具體情況创坞,提前設(shè)置好的UUID常量碗短。本文所有kXxxxxUUID均為預設(shè)的UUID常量。

同樣的题涨,characteristics也是一個數(shù)組豪椿,我們利用像遍歷services一樣的方式來遍歷所有的特征值。

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

if?(error)?{

NSLog(@"搜索特征%@時發(fā)生錯誤:%@",?service.UUID,?[error?localizedDescription]);

return;

}

NSLog(@"服務:%@",service.UUID);

for?(CBCharacteristic?*characteristic?in?service.characteristics)?{

//????????NSLog(@"特征:%@",characteristic);

//發(fā)現(xiàn)特征

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

_writeCharacteristic?=?characteristic;

}

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

NSLog(@"監(jiān)聽特征:%@",characteristic);//監(jiān)聽特征

[self.peripheral?setNotifyValue:YES?forCharacteristic:characteristic];

_isConnected?=?YES;

}

}

}

特別要提到的是携栋,我們不同的藍牙設(shè)備有不同的服務和特征值搭盾。我的藍牙模塊的說明文檔中已經(jīng)說清楚了,write特征婉支、read特征鸯隅、notify特征,所以在此根據(jù)自身需要,來對不同的特征值進行操作蝌以。

設(shè)置監(jiān)聽

我在此要解釋一下炕舵,當我們試圖去讀取藍牙外設(shè)發(fā)過來的數(shù)據(jù)時,一定要找準特征值跟畅,用這個方法進行訂閱咽筋。每次特征值變化的時候,就會有回調(diào)方法執(zhí)行徊件,從而達到讀取數(shù)據(jù)的目的奸攻。容易出錯誤,一定分清楚到底哪個特征值該被訂閱虱痕。

在訂閱了特征值后睹耐,我們嘗試用藍牙外設(shè)發(fā)送一些數(shù)據(jù)出來,即可回調(diào)下一階段的方法:

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

if?(error)?{

NSLog(@"更新特征值%@時發(fā)生錯誤:%@",?characteristic.UUID,?[error?localizedDescription]);

return;

}

//?收到數(shù)據(jù)

[delegate?didGetDataForString:[self?hexadecimalString:characteristic.value]];

//????NSLog(@"%@",[self?hexadecimalString:characteristic.value]);

}

數(shù)據(jù)的轉(zhuǎn)換

我們接收到的數(shù)據(jù)部翘,正是characteristic.value硝训,這是一個NSData類數(shù)據(jù),我們可以通過UTF8StringEncoding來轉(zhuǎn)化為NSString新思,為了代碼結(jié)構(gòu)清晰窖梁,我專門把NSData和NSString互轉(zhuǎn)寫成了兩個方法:

//將傳入的NSData類型轉(zhuǎn)換成NSString并返回

-?(NSString*)hexadecimalString:(NSData?*)data{

NSString?*result?=?[[NSString?alloc]?initWithData:data?encoding:NSUTF8StringEncoding];

return?result;

}

//將傳入的NSString類型轉(zhuǎn)換成NSData并返回

-?(NSData*)dataWithHexstring:(NSString?*)hexstring{

NSData?*aData;

return?aData?=?[hexstring?dataUsingEncoding:?NSASCIIStringEncoding];

}

在拿到字符串后,通過各種回調(diào)方法夹囚,處理UI變動纵刘。

結(jié)語

整個藍牙開發(fā)實現(xiàn)方便,但回調(diào)方法非常多崔兴,新手容易暈頭轉(zhuǎn)向彰导。按部就班把每個回調(diào)方法實現(xiàn)蛔翅,即可保證藍牙開發(fā)的順利進行敲茄。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市山析,隨后出現(xiàn)的幾起案子堰燎,更是在濱河造成了極大的恐慌,老刑警劉巖笋轨,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秆剪,死亡現(xiàn)場離奇詭異,居然都是意外死亡爵政,警方通過查閱死者的電腦和手機仅讽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來钾挟,“玉大人洁灵,你說我怎么就攤上這事〔舫觯” “怎么了徽千?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵苫费,是天一觀的道長。 經(jīng)常有香客問我双抽,道長百框,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任牍汹,我火速辦了婚禮铐维,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘柑贞。我一直安慰自己方椎,他們只是感情好,可當我...
    茶點故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布钧嘶。 她就那樣靜靜地躺著棠众,像睡著了一般。 火紅的嫁衣襯著肌膚如雪有决。 梳的紋絲不亂的頭發(fā)上闸拿,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天,我揣著相機與錄音书幕,去河邊找鬼新荤。 笑死,一個胖子當著我的面吹牛台汇,可吹牛的內(nèi)容都是我干的苛骨。 我是一名探鬼主播,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼苟呐,長吁一口氣:“原來是場噩夢啊……” “哼痒芝!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起牵素,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤严衬,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后笆呆,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體请琳,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年赠幕,在試婚紗的時候發(fā)現(xiàn)自己被綠了俄精。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡榕堰,死狀恐怖竖慧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤测蘑,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布灌危,位于F島的核電站,受9級特大地震影響碳胳,放射性物質(zhì)發(fā)生泄漏勇蝙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一挨约、第九天 我趴在偏房一處隱蔽的房頂上張望味混。 院中可真熱鬧,春花似錦诫惭、人聲如沸翁锡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽馆衔。三九已至,卻和暖如春怨绣,著一層夾襖步出監(jiān)牢的瞬間角溃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工篮撑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留减细,地道東北人。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓赢笨,卻偏偏與公主長得像未蝌,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子茧妒,可洞房花燭夜當晚...
    茶點故事閱讀 43,666評論 2 350

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