(轉(zhuǎn))iOS邊城之藍(lán)牙編程(Core Bluetooth)

藍(lán)牙技術(shù)卢鹦,很早以前就被有了臀脏,如今已更新4.0版本。很多熱門(mén)技術(shù)都是基于它工作的冀自,如Android平臺(tái)的NFC揉稚,iOS的iBeancon等,現(xiàn)在的智能家居基本也是基于藍(lán)牙4.0與APP進(jìn)行通信熬粗。在iOS中窃植,藍(lán)牙是基于4.0標(biāo)準(zhǔn)的,設(shè)備間低功耗通信荐糜。

核心成員

在開(kāi)始前我們回憶下傳統(tǒng)的Socket編程巷怜,里面有Server服務(wù)端與Client端的區(qū)別。那么在藍(lán)牙編程也是如此暴氏,其中Peripheral外設(shè)相當(dāng)于Socket編程中的Server服務(wù)端延塑,Central中心相當(dāng)于Client客戶端(ps吐槽下,Central中心答渔,作為服務(wù)端关带,不更適合嗎!)

你可以理解外設(shè)是一個(gè)廣播數(shù)據(jù)的設(shè)備沼撕,它開(kāi)始告訴外面的世界說(shuō)它這兒有一些數(shù)據(jù)宋雏,并且能提供一些服務(wù)。另一邊中心開(kāi)始掃描周邊有沒(méi)有合適的設(shè)備务豺,如果發(fā)現(xiàn)后磨总,會(huì)和外設(shè)做連接請(qǐng)求,一旦連接確定后笼沥,兩個(gè)設(shè)備就可以傳輸數(shù)據(jù)了蚪燕。

在iOS6之后,iOS 設(shè)備可以是外設(shè)奔浅,也可以是中心馆纳,就像Socket編程中一樣,你可以是服務(wù)端也可以是客戶端汹桦,但與Socket不同的是不能在同時(shí)間扮演兩個(gè)角色鲁驶。

服務(wù)(service)和特征(characteristic)

每個(gè)藍(lán)牙4.0的設(shè)備都是通過(guò)服務(wù)和特征來(lái)展示自己的,一個(gè)設(shè)備必然包含一個(gè)或多個(gè)服務(wù)舞骆,每個(gè)服務(wù)下面又包含若干個(gè)特征钥弯。特征是與外界交互的最小單位壹罚。比如說(shuō),智能音響設(shè)備寿羞,用服務(wù)A標(biāo)識(shí)播放模塊猖凛,特征A1來(lái)表示播放上一首,特征A2來(lái)表示播放下一首绪穆;服務(wù)B標(biāo)識(shí)設(shè)置模塊辨泳,特征B1設(shè)置彩燈顏色。這樣做的目的主要為了模塊化玖院。

上面說(shuō)了設(shè)備可以是外設(shè)菠红,也可以是中心,也就是 本地中心->遠(yuǎn)程外設(shè)? 难菌、本地外設(shè)與遠(yuǎn)程中心试溯,

不過(guò)在智能家居開(kāi)發(fā)中,大部分硬件藍(lán)牙都是擔(dān)任外設(shè)的角色郊酒,也就是說(shuō)我們應(yīng)用只要扮演中心即可了遇绞。下面我們一一到來(lái):

本地中心與遠(yuǎn)程外設(shè)

在中心這邊,由CBCentralManager對(duì)象管理本地中心燎窘,來(lái)發(fā)現(xiàn)或連接遠(yuǎn)程外設(shè)摹闽。此時(shí)

正在連接的外設(shè)用CBPeripheral 對(duì)象表示。

遠(yuǎn)程外設(shè)的數(shù)據(jù)由CBService和CBCharacteristic對(duì)象表示

當(dāng)你與遠(yuǎn)程外設(shè)CBPeripheral對(duì)象進(jìn)行數(shù)據(jù)交互時(shí)褐健,是由一個(gè)服務(wù)與特征操作的付鹿。

本地外設(shè)與遠(yuǎn)程中心

外設(shè)方面,由本地的外設(shè)CBPeripheralManager對(duì)象表示蚜迅,同樣舵匾,正在連接中的遠(yuǎn)程中心用CBCentral表示

當(dāng)你設(shè)置好和本地Peripheral(表示為CBPeripheralManager)數(shù)據(jù)交互,就可以處理Service和Characteristic的可變版本谁不。在Core Bluetooth框架中坐梯,本地Peripheral的Service表示為CBMutableService。同樣地拍谐,本地Peripheral中Service的Characteristic表示為CBMutableCharacteristic烛缔。如下圖所示:

使用

我們?cè)谶@里只介紹本地中心與遠(yuǎn)程外設(shè)馏段,如果你需要自己創(chuàng)建外設(shè)轩拨,請(qǐng)前往創(chuàng)建外設(shè)。

編程步驟:建立中心角色—掃描外設(shè)(discover)—連接外設(shè)(connect)—掃描外設(shè)中的服務(wù)和特征(discover)—與外設(shè)做數(shù)據(jù)交互(exploreand interact)—斷開(kāi)連接(disconnect)院喜。

1亡蓉、建立中心角色

_manager = [[CBCentralManageralloc]initWithDelegate:selfqueue:nil];

需要實(shí)現(xiàn)CBCentralManagerDelegate,queue為執(zhí)行隊(duì)列喷舀,默認(rèn)為主線程

之后會(huì)回調(diào)砍濒,返回當(dāng)前設(shè)備藍(lán)牙狀態(tài)

-(void)centralManagerDidUpdateState:(CBCentralManager *)central

{

switch (central.state){

case CBCentralManagerStatePoweredOn:

NSLog(@"藍(lán)牙已打開(kāi),請(qǐng)掃描外設(shè)");

[selfscan];//掃描

break;

case CBCentralManagerStateUnsupported:

[AlertUtilsshowAlert:@"您的設(shè)備不支持藍(lán)牙或藍(lán)牙4.0"];

break;

case CBCentralManagerStateUnauthorized:

NSLog(@"未授權(quán)");

break;

caseCBCentralManagerStatePoweredOff://藍(lán)牙未打開(kāi)淋肾,系統(tǒng)會(huì)自動(dòng)提示打開(kāi),所以不用自行提示

default:

break;

}

}

2爸邢、掃描外設(shè)(discover)

//掃描

-(void)scan{

NSLog(@"開(kāi)始掃描樊卓。。");

[_managerscanForPeripheralsWithServices:niloptions:@{CBCentralManagerScanOptionAllowDuplicatesKey :@NO}];

//30秒以后停止

double delayInSeconds = 30.0;

dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds*NSEC_PER_SEC));

dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

[_managerstopScan];//停止掃描

NSLog(@"停止掃描杠河。碌尔。");

});

}

使用scanForPeripheralsWithServices:options:進(jìn)行掃描,第一個(gè)參數(shù)為Services的UUID(外設(shè)端的UUID)券敌,如果你只想發(fā)現(xiàn)周邊特定的設(shè)備(自家的音響)唾戚,那么就可以通過(guò)設(shè)備的UUID來(lái)限制。第二參數(shù)的CBCentralManagerScanOptionAllowDuplicatesKey為已發(fā)現(xiàn)的設(shè)備是否重復(fù)掃描待诅,如果是同一設(shè)備會(huì)多次回調(diào)叹坦。

在開(kāi)始掃描后,我們啟動(dòng)了一個(gè)延時(shí)隊(duì)列卑雁,用于30秒后停止掃描募书,要知道掃描是件非常耗電的操作,因此你的應(yīng)用不應(yīng)該實(shí)時(shí)掃描周邊設(shè)備测蹲。

發(fā)現(xiàn)外設(shè)锐膜,回調(diào)

//發(fā)現(xiàn)設(shè)備

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

if (![_peripheralscontainsObject:peripheral]) {

[_peripheralsaddObject:peripheral];

NSLog(@"發(fā)現(xiàn)設(shè)備:%@",_peripherals);

[_tViewreloadData];

}

}

3、連接外設(shè)

//連接設(shè)備

-(BOOL)connect:(CBPeripheral*)peripheral{

NSLog(@"connectstart");

_currentPeripheral = nil;

[_managerconnectPeripheral:peripheraloptions:[NSDictionarydictionaryWithObject:[NSNumbernumberWithBool:YES]forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey]];

//開(kāi)一個(gè)定時(shí)器監(jiān)控連接超時(shí)的情況

connectTimer = [NSTimer scheduledTimerWithTimeInterval:5.0ftarget:self selector:@selector(connectTimeout:) userInfo:peripheral repeats:NO];

return YES;

}

連接成功回調(diào)

//連接外設(shè)成功

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

{

//[connectTimerinvalidate];//停止時(shí)鐘

NSLog(@"Did connect toperipheral: %@", peripheral);

_currentPeripheral = peripheral;

[peripheral setDelegate:self];

[peripheraldiscoverServices:nil];//發(fā)現(xiàn)服務(wù)

}

//連接外設(shè)失敗

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

{

NSLog(@"%@",error);

}

4弛房、發(fā)現(xiàn)服務(wù)與特征

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

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

for (CBService*s in peripheral.services){

[_serversaddObject:s];

}

for (CBService*s in peripheral.services){

NSLog(@"服務(wù) UUID: %@(%@)",s.UUID.data,s.UUID);

[peripheral discoverCharacteristics:nil forService:s];

}

}

//已搜索到Characteristics

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

NSLog(@"發(fā)現(xiàn)特征的服務(wù):%@ (%@)",service.UUID.data ,service.UUID);

for (CBCharacteristic *c in service.characteristics) {

NSLog(@"特征UUID: %@ (%@)",c.UUID.data,c.UUID);

//? ? ? ? if ([c.UUID isEqual:[CBUUIDUUIDWithString:@"2A06"]]) {//設(shè)置

//? ? ? ? ? _writeCharacteristic = c;

//? ? ? }

//? ? ? ? if ([c.UUID isEqual:[CBUUIDUUIDWithString:@"2A19"]]) {//讀取

//? ? ? ? ? [_peripheral readValueForCharacteristic:c];

//? ? ? }

//

//? ? ? if ([c.UUID isEqual:[CBUUIDUUIDWithString:@"FFA1"]]) {

//? ? ? ? ? [_peripheral readRSSI];

//? ? ? }

//? ? ? [_nCharacteristics addObject:c];

}

}

5道盏、數(shù)據(jù)交互,分為兩種文捶,一種是直接讀荷逞,另外一種訂閱

6、斷開(kāi)連接

//主動(dòng)斷開(kāi)設(shè)備

-(void)disConnect

{

if (_currentPeripheral != nil)

{

NSLog(@"disConnectstart");

[_managercancelPeripheralConnection:_currentPeripheral];

}

}

至此整個(gè)流程就跑完啦粹排!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末种远,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子顽耳,更是在濱河造成了極大的恐慌坠敷,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件射富,死亡現(xiàn)場(chǎng)離奇詭異膝迎,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)胰耗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)限次,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事卖漫》丫。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵羊始,是天一觀的道長(zhǎng)旱幼。 經(jīng)常有香客問(wèn)我,道長(zhǎng)突委,這世上最難降的妖魔是什么速警? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮鸯两,結(jié)果婚禮上闷旧,老公的妹妹穿的比我還像新娘。我一直安慰自己钧唐,他們只是感情好忙灼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著钝侠,像睡著了一般该园。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上帅韧,一...
    開(kāi)封第一講書(shū)人閱讀 51,482評(píng)論 1 302
  • 那天里初,我揣著相機(jī)與錄音,去河邊找鬼忽舟。 笑死双妨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的叮阅。 我是一名探鬼主播刁品,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼浩姥!你這毒婦竟也來(lái)了挑随?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤勒叠,失蹤者是張志新(化名)和其女友劉穎兜挨,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體眯分,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拌汇,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了颗搂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片担猛。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖丢氢,靈堂內(nèi)的尸體忽然破棺而出傅联,到底是詐尸還是另有隱情,我是刑警寧澤疚察,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布蒸走,位于F島的核電站,受9級(jí)特大地震影響貌嫡,放射性物質(zhì)發(fā)生泄漏比驻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一岛抄、第九天 我趴在偏房一處隱蔽的房頂上張望别惦。 院中可真熱鬧,春花似錦夫椭、人聲如沸掸掸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)扰付。三九已至,卻和暖如春仁讨,著一層夾襖步出監(jiān)牢的瞬間羽莺,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工洞豁, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盐固,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓丈挟,卻偏偏與公主長(zhǎng)得像闰挡,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子礁哄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

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