IOS9 BLE 與外設(shè)交互及設(shè)備綁定

最近在做一個(gè)項(xiàng)目,是關(guān)于運(yùn)動手表的,APP獲取手表傳來的步數(shù)繼而進(jìn)行接下來的一些操作枫笛。也屬于第一次接觸藍(lán)牙相關(guān)的項(xiàng)目,就開始猛啃藍(lán)牙的相關(guān)信息堡纬。我沒有去深入研究BabyTooth庫,總感覺CoreBluetooth能讓我更好的理解整個(gè)流程...當(dāng)然大家可以把這認(rèn)為是懶..,好了言歸正傳斥难。

BLE屬于低功耗藍(lán)牙,但傳輸速率在我感覺有點(diǎn)慢帘饶。

外圍設(shè)備和中央設(shè)備在CoreBluetooth中使用CBPeripheralManager和CBCentralManager表示哑诊。

CBPeripheralManager:外圍設(shè)備通常用于發(fā)布服務(wù)、生成數(shù)據(jù)及刻、保存數(shù)據(jù)镀裤。外圍設(shè)備發(fā)布并廣播服務(wù),告訴周圍的中央設(shè)備它的可用服務(wù)和特征缴饭。

CBCentralManager:中央設(shè)備使用外圍設(shè)備的數(shù)據(jù).中央設(shè)備掃描到外圍設(shè)備后會就會試圖建立連接暑劝,一旦連接成功就可以使用這些服務(wù)和特征。

外圍設(shè)備和中央設(shè)備之間交互的橋梁是服務(wù)(CBService)和特征(CBCharacteristic)颗搂,二者都有一個(gè)唯一的標(biāo)識UUID(CBUUID類型)來唯一確定一個(gè)服務(wù)或者特征担猛,每個(gè)服務(wù)可以擁有多個(gè)特征,UUID這個(gè)坑我已深陷多回..這后面再詳說丢氢。下面是他們之間的關(guān)系:

一些UUID的宏設(shè)置

#define kSeverviceUUID @"3D9E5046-325A-A248-F1FE-15380D827D21"http://獲取到的設(shè)備的UUID傅联,測試綁定的時(shí)候用的

#define kStepServiceUUID @"0C301900-BEB8-5C69-8714-099C77103418"http://服務(wù)的UUID

#define kStepRecordsUUID @"0C302ABC-BEB8-5C69-8714-099C77103418"http://特征的UUID

#define kStepControl @"0C302ABE-BEB8-5C69-8714-099C77103418"

1.創(chuàng)建中心設(shè)備

#pragma mark -掃描藍(lán)牙外設(shè)

- (void)scanBtnClick

{

//創(chuàng)建中心設(shè)備管理器并設(shè)置當(dāng)前控制器試圖為代理

_centralManage= [[CBCentralManager alloc] initWithDelegate:self queue:nil];

}

接下來進(jìn)入CBCentralManagerDelegate代理方法

2.中心服務(wù)器狀態(tài)

#pragma mark - CBCentralManagerDelegate代理方法

//中心服務(wù)器狀態(tài)更新后

- (void)centralManagerDidUpdateState:(CBCentralManager*)central

{

switch(central.state)

{

//藍(lán)牙為開啟狀態(tài),iOS應(yīng)該是8以后吧卖丸,不加狀態(tài)判斷崩潰

case CBCentralManagerStatePoweredOn:

NSLog(@"BLE已打開");

{

_hud= [MBProgressHUD showHUDAddedTo:self.view.window animated:YES];

_hud.delegate=self;

_hud.labelText=@"掃描外設(shè)中..";

self.centralManage= central;

//這里填寫nil纺且,會掃描所有外設(shè)盏道,但是當(dāng)我寫入一個(gè)指定的外設(shè)UUID的時(shí)候稍浆,卻掃不到任何設(shè)備,目前不清楚是什么原因猜嘱,希望大家告知衅枫。

[central scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}];

}

break;

default:

NSLog(@"此設(shè)備不支持BLE或未打開藍(lán)牙功能,無法作為外圍設(shè)備");

break;

}

}

#pragma mark - 發(fā)現(xiàn)外設(shè)

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

{

//根據(jù)外設(shè)名的前綴來查找相應(yīng)的外設(shè),本來在綁定的時(shí)候我打算通過判斷外設(shè)的名字來綁定設(shè)備的朗伶,但是發(fā)現(xiàn)行不通弦撩,當(dāng)時(shí)就這個(gè)綁定問題很是苦惱

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

{

_hud.labelText= [NSString stringWithFormat:@"掃描到外設(shè)%@,開始連接...",peripheral.name];

//坑來啦!就是這個(gè)坑啊,在這里可以獲取到外設(shè)的 identifier论皆,name 和 RSSI(信號強(qiáng)弱)益楼,我一直以為identifier就是外設(shè)的UUID,就一直用peripheral.identifier來做判斷点晴,一直就不走方法感凤,打印出來的identifier你會發(fā)現(xiàn)是這樣一串字符"<__NSConcreteUUID 0x15106e470> 3D9E5046-325A-A248-F1FE-15380D827D21",UUID前面還有一串字符粒督,所以說identifier并不是真正的UUID陪竿。最后發(fā)現(xiàn)identifier還有個(gè)UUIDString的方法,接下來就可以通過判斷UUIDString和當(dāng)前設(shè)備的UUID是否一致來選擇是否連接該設(shè)備來實(shí)現(xiàn)綁定屠橄。

[USER_D setObject:peripheral.identifier.UUIDString forKey:@"peripheralUUID"];

//停止掃描

[self.centralManage stopScan];

NSLog(@"獲得的外設(shè)的UUID---%@",peripheral.identifier.UUIDString);

NSLog(@"advertisementData--%@",advertisementData);

NSLog(@"*****沒有綁定*****");

self.peripheral= peripheral;

NSLog(@"開始連接外圍設(shè)備");

//[self.centralManage connectPeripheral:peripheral options:nil];

[self.centralManage connectPeripheral:peripheral options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES]forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey]];

}

}

#pragma mark -連接到外圍設(shè)備

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

{

NSLog(@"連接外圍設(shè)備成功");

_hud.labelText=@"連接外設(shè)成功";

//連接成功后建立一個(gè)通知,通知相機(jī)連接已完成(這個(gè)是寫的自定義相機(jī)來實(shí)現(xiàn)藍(lán)牙控制拍照)

[[NSNotificationCenter defaultCenter] postNotificationName:@"connected" object:nil];

//設(shè)置外圍設(shè)備的代理為當(dāng)前控制器

peripheral.delegate=self;

//外圍設(shè)備開始尋找服務(wù)

[peripheral discoverServices:@[[CBUUID UUIDWithString:kStepServiceUUID]]];

}

#pragma mark - CBPeripheralDelegate代理方法

//外圍設(shè)備尋找到服務(wù)器后

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

{

NSLog(@"已發(fā)現(xiàn)可用服務(wù)...");

if(error)

{

NSLog(@"外圍設(shè)備尋找服務(wù)過程中發(fā)生錯(cuò)誤,錯(cuò)誤信息:%@",error.localizedDescription);

}

//遍歷查找到的服務(wù)

CBUUID*serviceUUID = [CBUUID UUIDWithString:kStepServiceUUID];

CBUUID*stepRecordsUUID = [CBUUID UUIDWithString:kStepRecordsUUID];

CBUUID*stepControl = [CBUUID UUIDWithString:kStepControl];

for(CBService*service in peripheral.services)

{

if([service.UUID isEqual:serviceUUID])

{

//外圍設(shè)備查找指定服務(wù)中的特征

[peripheral discoverCharacteristics:@[stepRecordsUUID,stepControl] forService:service];

}

}

}

#pragma mark - 外圍設(shè)備尋找到特征后

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

{

? ? ?//在這里向外設(shè)寫入內(nèi)容族跛,先遍歷特征闰挡,遍歷到可寫入的特征

? ? //寫入特征也比較坑,當(dāng)時(shí)我拿到的硬件文檔純英文的不說礁哄,而且給的東西很少长酗,很不清晰,你所寫入的數(shù)據(jù)應(yīng)該是硬件那邊提供的姐仅,寫入的分方法就是writeValue

//寫入目標(biāo)

[peripheral writeValue:[NSDatadataWithBytes:(uint8_t[]){43, goal, goal>>8,0,2} length:5] forCharacteristic:characterstic type:CBCharacteristicWriteWithResponse];//這是我寫入目標(biāo)的一種數(shù)據(jù)格式

}

#pragma mark - 特征值被更新后

- (void)peripheral:(CBPeripheral*)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic*)characteristic error:(nullableNSError*)error

{

NSLog(@"收到特征更新通知...");

if(error)

{

NSLog(@"更新通知狀態(tài)時(shí)發(fā)生錯(cuò)誤,錯(cuò)誤信息:%@",error.localizedDescription);

}

//給特征值設(shè)置新的值

CBUUID *stepRecordsUUID = [CBUUID UUIDWithString:kStepRecordsUUID];

if([characteristic.UUID isEqual:stepRecordsUUID])

{

if(characteristic.isNotifying)

{

if(characteristic.properties == CBCharacteristicPropertyNotify)

{

NSLog(@"已訂閱特征通知");

[peripheral readValueForCharacteristic:characteristic];

return;

}

elseif(characteristic.properties == CBCharacteristicPropertyRead)

{

//從外圍設(shè)備讀取新值,調(diào)用此方法會觸發(fā)代理方法:- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error

[peripheral readValueForCharacteristic:characteristic];

}

else

{

NSLog(@"停止已停止");

//取消連接

[self.centralManage cancelPeripheralConnection:peripheral];

}

}

}

}

#pragma mark -?更新特征后(調(diào)用readValueForCharactrtistic:方法或者外圍設(shè)備在訂閱后更新特征值都會調(diào)用此方法)

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

{

//在這里讀取外設(shè)傳來的數(shù)據(jù)

//這只是一部分代碼

NSData*data = characteristic.value;

uint32_t minuteTimestamp =0;

[data getBytes:&minuteTimestamp range:NSMakeRange(1,3)];

const uint8_t*bytes = data.bytes;

if(minuteTimestamp !=0)

{

NSDate*time = [NSDate dateWithTimeIntervalSince1970:SEC_FROM_1970_TO_2012 + minuteTimestamp *60];

NSTimeZone*zone = [NSTimeZone systemTimeZone];

NSInteger interval = [zone secondsFromGMTForDate:time];

NSDate*localDate = [time dateByAddingTimeInterval:interval];

[newText appendFormat:@"%@ %u, %u, %u, %u, %u\n",

localDate, bytes[4], bytes[5], bytes[6], bytes[7], bytes[8]];

NSString*dateString = [NSString stringWithFormat:@"%@",localDate];

NSLog(@"======dateString====%@",dateString);

NSString*stepCount = [NSString stringWithFormat:@"%u",bytes[4]+bytes[5]+bytes[6]+bytes[7]+bytes[8]];

//把數(shù)據(jù)存入數(shù)據(jù)庫中

[StepDAO insertData:dateString AndSteps:stepCount];

NSLog(@"讀取到的特征時(shí)間和步數(shù):%@,%@",newText,stepCount);

//其他的卡路里什么的計(jì)算就不寫了花枫,太復(fù)雜..算法是客戶那邊提供的..看著都惡心..

}

最后再說下,我發(fā)現(xiàn)其實(shí)BLE在讀寫數(shù)據(jù)的時(shí)候已經(jīng)實(shí)現(xiàn)了綁定了掏膏,因?yàn)樵趯戇^斷開重連后劳翰,重連的只會是之前連接的那個(gè)設(shè)備,但重新掃描就不一定掃描那個(gè)設(shè)備了馒疹,所以在鏈接外設(shè)的代理方法里判斷identifier.UUIDString佳簸。

好啦,BLE的開發(fā)大概就是這樣的一個(gè)流程了颖变,其實(shí)并不是說很難生均,只要理清這個(gè)邏輯就行。第一次寫腥刹,也懶得用MarkDown來排版马胧,關(guān)于其他相關(guān)的我也會繼續(xù)研究并更新,忘大家共同學(xué)習(xí)衔峰,共同進(jìn)步佩脊。?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市垫卤,隨后出現(xiàn)的幾起案子威彰,更是在濱河造成了極大的恐慌,老刑警劉巖穴肘,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件歇盼,死亡現(xiàn)場離奇詭異,居然都是意外死亡评抚,警方通過查閱死者的電腦和手機(jī)豹缀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來慨代,“玉大人邢笙,你說我怎么就攤上這事∮阆欤” “怎么了鸣剪?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我筐骇,道長债鸡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任铛纬,我火速辦了婚禮厌均,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘告唆。我一直安慰自己棺弊,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布擒悬。 她就那樣靜靜地躺著模她,像睡著了一般。 火紅的嫁衣襯著肌膚如雪懂牧。 梳的紋絲不亂的頭發(fā)上侈净,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天,我揣著相機(jī)與錄音僧凤,去河邊找鬼畜侦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛躯保,可吹牛的內(nèi)容都是我干的旋膳。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼途事,長吁一口氣:“原來是場噩夢啊……” “哼验懊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起盯孙,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤鲁森,失蹤者是張志新(化名)和其女友劉穎祟滴,沒想到半個(gè)月后振惰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡垄懂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年骑晶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片草慧。...
    茶點(diǎn)故事閱讀 39,795評論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡桶蛔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出漫谷,到底是詐尸還是另有隱情仔雷,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站碟婆,受9級特大地震影響电抚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜竖共,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一蝙叛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧公给,春花似錦借帘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至腿准,卻和暖如春狰挡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背释涛。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工加叁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人唇撬。 一個(gè)月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓它匕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親窖认。 傳聞我的和親對象是個(gè)殘疾皇子豫柬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評論 2 354

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