藍(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è)流程就跑完啦粹排!