iOS--CBCentralManager實(shí)現(xiàn)

執(zhí)行通用中心角色任務(wù)

在BLE通信中實(shí)現(xiàn)中心角色的設(shè)備執(zhí)行一些通用任務(wù)屎慢,例如:搜索并連接設(shè)備,掃描并且和提供數(shù)據(jù)的周邊交互。對比著看湿弦,實(shí)現(xiàn)周邊角色的設(shè)備也在執(zhí)行一些通用的,但是不同的任務(wù)腾夯,例如:公開并廣告服務(wù)颊埃,響應(yīng)連接的中心設(shè)備的讀寫,訂閱(read,write俯在,subscription)請求竟秫。

在這一章娃惯,你會學(xué)到怎樣通過CoreBluetooth執(zhí)行中心角色這邊的最基本的BLE任務(wù)跷乐。下面的示例代碼可以幫助你在設(shè)備上開發(fā)app實(shí)現(xiàn)這一功能。特別地趾浅,你將學(xué)習(xí)怎樣:

?開始一個中心管理對象

?發(fā)現(xiàn)并且連接廣告中的設(shè)備

?在連接設(shè)備之后掃描數(shù)據(jù)愕提。

?針對設(shè)備服務(wù)的特征發(fā)送讀寫請求

?訂閱支持notified(在數(shù)據(jù)更新時會主動上報)的特征。

在下一章皿哨,你會學(xué)習(xí)怎樣在你的設(shè)備上通過開發(fā)實(shí)現(xiàn)一個周邊角色浅侨。

本章的示例代碼簡單抽象证膨;當(dāng)你把它們遷入你的app中時可能需要做一點(diǎn)修改如输。更多和中心角色相關(guān)的高級課題(像貼士,技巧和最佳練習(xí))在后面的章節(jié)將概括到央勒。iOS應(yīng)用CoreBluetooth的后臺執(zhí)行(Core Bluetooth Background Processing for iOS Apps)和與遠(yuǎn)程設(shè)備通訊的最佳訓(xùn)練(Best Practices for Interacting with a Remote Peripheral Device.)

開始一個中心管理對象

CBCentralManager對象是本地中心設(shè)備的CoreBluetooth面向?qū)ο蟮南笳鞑患谀憧梢詧?zhí)行任何BLE痛信之前你必須分配并且初始化一個中心管理者的實(shí)例。你可以通過調(diào)用CBCentralManager類中的initWithDelegate:queue:options: 方法來實(shí)例化一個中心管理者崔步,就像這樣:

myCentralManager =

[[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil];

在這個例子中稳吮,self作為接受中心角色事件的委托。指定dispatchQueue為nil井濒,中心對象使用main queue派遣中心角色事件灶似。

當(dāng)你創(chuàng)建了中心管理者列林。中心管理者將為它的委托對象調(diào)用centralManagerDidUpdateState:方法。你必須實(shí)現(xiàn)這個委托方法用于驗(yàn)證在這個中心設(shè)備上對BLE的支持是否完備酪惭。不會實(shí)現(xiàn)這個委托方法希痴?請看 CBCentralManagerDelegate 協(xié)議參考(CBCentralManagerDelegate Protocol Reference.)

發(fā)現(xiàn)正在廣告的周邊設(shè)備

你要執(zhí)行的中心這邊的任務(wù)第一任務(wù)就是發(fā)現(xiàn)周圍可以被你連接的周邊設(shè)備。像之前提到的中心發(fā)現(xiàn)并連接廣告中的周邊設(shè)備( Centrals Discover and Connect to Peripherals That Are Advertising),廣告是周邊設(shè)備證明自己存在的基礎(chǔ)方式春感。你可以通過CBCentralManager類中的scanForPeripheralsWithServices:options: 方法發(fā)現(xiàn)周圍正在廣告的周邊設(shè)備润梯。就像這樣:

[myCentralManager scanForPeripheralsWithServices:nil options:nil];

注意:如果第一個參數(shù)你傳了nil,中心管理者會返回所有被發(fā)現(xiàn)的周邊甥厦,不管它們所支持的服務(wù)是什么纺铭。在實(shí)際的app中,你可以指定一個 CBUUID 對象的數(shù)組刀疙,每個CBUUID對象對應(yīng)周邊設(shè)備正在廣告的服務(wù)的唯一表示符(UUID)舶赔。當(dāng)你指定了服務(wù)的UUID,中心管理者將只返回正在廣告這些服務(wù)的周邊谦秧,幫助你只搜索你感興趣的設(shè)備竟纳。

UUIDs,CBUUID的對象和它們對應(yīng)疚鲤,更多相關(guān)討論請看 Services and Characteristics Are Identified by UUIDs.

在你調(diào)用 scanForPeripheralsWithServices:options: 發(fā)現(xiàn)可用的周邊之后锥累,中心管理者會為他的委托對象調(diào)用 centralManager:didDiscoverPeripheral:advertisementData:RSSI:方法返回它所發(fā)現(xiàn)的每一臺周邊。所有周邊被發(fā)現(xiàn)的周邊被 CBPeripheral 對象抽象返回集歇。像下面展示的這樣桶略,你可以實(shí)現(xiàn)這個委托方法來排列被發(fā)現(xiàn)的周邊:

- (void)centralManager:(CBCentralManager *)central

didDiscoverPeripheral:(CBPeripheral *)peripheral

advertisementData:(NSDictionary *)advertisementData

RSSI:(NSNumber *)RSSI {

NSLog(@"Discovered %@", peripheral.name);

...

當(dāng)你發(fā)現(xiàn)了你想要連接的周邊設(shè)備,停止掃描來節(jié)省電量诲宇。

[myCentralManager stopScan];

NSLog(@"Scanning stopped");

連接你所發(fā)現(xiàn)的周邊設(shè)備(Connecting to a Peripheral Device After You’ve Discovered It)

在你發(fā)現(xiàn)了你感興趣的正在廣告服務(wù)的周邊設(shè)備之后际歼,你調(diào)用CBCentralManager中的connectPeripheral:options: 方法去請求連接周邊。簡單調(diào)用這個方法并且指定你想連接的已被發(fā)現(xiàn)的周邊姑蓝,就像這樣:

[myCentralManager connectPeripheral:peripheral options:nil];

假設(shè)連接請求成功了鹅心,中心管理者將為它的委托對象調(diào)用 centralManager:didConnectPeripheral:,你可以通過實(shí)現(xiàn)這個方法來打印信息確定連接成功纺荧。想下面寫的這樣:

- (void)centralManager:(CBCentralManager *)central

didConnectPeripheral:(CBPeripheral *)peripheral {

NSLog(@"Peripheral connected");

...

在你和周邊通信之前旭愧,你應(yīng)該設(shè)置周邊的委托以確保它可以收到合適的回調(diào),像這樣:

peripheral.delegate = self;

發(fā)現(xiàn)你連接的周邊的服務(wù)(Discovering the Services of a Peripheral That You’re Connected To)

和周邊建立了連接之后宙暇,你可以開始探測它的數(shù)據(jù)输枯,探索周邊提供的第一步是發(fā)現(xiàn)它支持的服務(wù),因?yàn)檫@里對周邊的數(shù)據(jù)量有大小的限制客给,你可以發(fā)現(xiàn)一個周邊廣告好幾個服務(wù)(在他的廣告包里)用押。你可以通過調(diào)用CBPeripheral類中的discoverServices: 方法發(fā)現(xiàn)周邊的所有服務(wù),像這樣:

[peripheral discoverServices:nil];

注意:在實(shí)際的app中靶剑,你不太可能會發(fā)nil作為參數(shù)蜻拨,因?yàn)檫@樣會返回周邊上支持的所有的服務(wù)池充。由于一個周邊上可能含有很多你不太感興趣的服務(wù),搜索它們只是浪費(fèi)電池生命和搜索的時間缎讼。大多數(shù)情況下收夸,你可以指定搜索你所感興趣并且早就知道的服務(wù)的UUIDs,像明智地探索周邊數(shù)據(jù)(Explore a Peripheral’s Data Wisely)里介紹的那樣血崭。

當(dāng)指定的服務(wù)被發(fā)現(xiàn)時卧惜,周邊(你連接的那個周邊對象)會為他的委托對象調(diào)用peripheral:didDiscoverServices: 方法。Core Bluetooth創(chuàng)建了一個CBService對象的數(shù)組-每一個對象對應(yīng)周邊上發(fā)現(xiàn)的服務(wù)夹纫。就像下面展示的這樣咽瓷,你可以實(shí)現(xiàn)這個委托方法去接收這個已發(fā)現(xiàn)的服務(wù)數(shù)組。

- (void)peripheral:(CBPeripheral *)peripheral

didDiscoverServices:(NSError *)error {

for (CBService *service in peripheral.services) {

NSLog(@"Discovered service %@", service);

...

}

...

發(fā)現(xiàn)服務(wù)的特征(Discovering the Characteristics of a Service)

當(dāng)你發(fā)現(xiàn)了你感興趣的服務(wù)之后舰讹,下一步就是探索這個周邊的所有特征查看它提供了啥茅姜。發(fā)現(xiàn)服務(wù)的特征很簡單,指定對應(yīng)的服務(wù)月匣,調(diào)用CBPeriphral的discoverCharacteristics:forService:方法就好了钻洒,就像這樣:

NSLog(@"Discovering characteristics for service %@", interestingService);

[peripheral discoverCharacteristics:nil forService:interestingService];

注意:在實(shí)際開發(fā)中,你不太可能在第一個參數(shù)傳入nil锄开,這樣做的話會返回這個服務(wù)的所有特征素标,因?yàn)橹苓叺姆?wù)可能保護(hù)一些你不感興趣的特征,發(fā)現(xiàn)它們在電量和時間上都是浪費(fèi)萍悴,更多條件下头遭,你應(yīng)該指定搜索你早就知道的感性趣的特征的UUIDs。

在指定服務(wù)的特征被發(fā)現(xiàn)時退腥,周邊會為它的委托對象調(diào)用 peripheral:didDiscoverCharacteristicsForService:error:方法任岸。CoreBluetooth創(chuàng)造了一個CBCharacteristic 對象的數(shù)組再榄,數(shù)組中每一個對象對應(yīng)相應(yīng)的特征狡刘。下面的例子告訴你該如何實(shí)現(xiàn)這個委托方法并且簡單打印出被發(fā)現(xiàn)的特征。

- (void)peripheral:(CBPeripheral *)peripheral

didDiscoverCharacteristicsForService:(CBService *)service

error:(NSError *)error {

for (CBCharacteristic *characteristic in service.characteristics) {

NSLog(@"Discovered characteristic %@", characteristic);

...

}

...

獲取特征的值 (Retrieving the Value of a Characteristic)

特征包含一個關(guān)于服務(wù)的更多信息的簡單值困鸥。舉例:一個健康體溫計(jì)服務(wù)的溫度測量值的特征可能表示了一個攝氏溫度值嗅蔬。你可以接受這個特征值通過訂閱它或者立馬解讀它。

讀特征值 (Reading the Value of a Characteristic)

在找到你感興趣的服務(wù)的特征之后疾就,你可以通過調(diào)用CBPeripheral的readValueForCharacteristic:方法并且指定特定的特征來閱讀特征值澜术。像這樣:

NSLog(@"Reading value for characteristic %@", interestingCharacteristic);

[peripheral readValueForCharacteristic:interestingCharacteristic];

當(dāng)你準(zhǔn)備讀一個值時,周邊為它的委托對象調(diào)用peripheral:didUpdateValueForCharacteristic:error: 方法來接受這個值猬腰,如果這個值被成功接收鸟废,你可以通過這個值的屬性接收它,像這樣:

- (void)peripheral:(CBPeripheral *)peripheral

didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic

error:(NSError *)error {

NSData *data = characteristic.value;

// parse the data as needed

...

注意:并不是所有特征都有可讀有效值姑荷,你可以通過查看constant常數(shù)來判斷特征值是否可讀盒延,詳細(xì)信息在 CBCharacteristic類文檔(CBCharacteristic Class Reference)中缩擂,如果你想讀一個不可讀的值, peripheral:didUpdateValueForCharacteristic:error:會返回對應(yīng)的錯誤添寺。

訂閱特征值(Subscribing to a Characteristic’s Value)

通過使用 readValueForCharacteristic: 方法去讀一些特征的值可以解決提供一些有效方案胯盯,但是對于經(jīng)常改變的值這個方法便不是很有效—-舉例:你的心率隨時變化—-你可以通過訂閱的方式實(shí)時獲取它們,在你訂閱了特征值之后计露,周邊的特征值在變化時會通過通知的方式讓你收到它博脑。

你可以通過CBPeriphral類中的 setNotifyValue:forCharacteristic:方法訂閱你感興趣的特征值。指定第一個參數(shù)為YES就好票罐,像這樣:

[peripheral setNotifyValue:YES forCharacteristic:interestingCharacteristic];

當(dāng)你試圖訂閱(或者取消訂閱)某一特征時叉趣,周邊會為它的委托對象調(diào)用peripheral:didUpdateNotificationStateForCharacteristic:error: 方法。如果由于一些原因訂閱請求失敗了该押,你可以通過實(shí)現(xiàn)這個委托方法來確定失敗原因君账,像下面的例子一樣:

- (void)peripheral:(CBPeripheral *)peripheral

didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic

error:(NSError *)error {

if (error) {

NSLog(@"Error changing notification state: %@",

[error localizedDescription]);

}

...

注意:并不是所有的特征的配置都允許你訂閱它,你可以通過特征屬性的枚舉來判斷它的設(shè)置沈善。詳細(xì)信息在CBCharacteristic 類相關(guān)( CBCharacteristic Class Reference.)中乡数。

在你成功訂閱特征值之后,周邊設(shè)備為你廣播這個值只要它發(fā)生了變化闻牡,每次值變化時净赴,周邊為它的委托對象調(diào)用peripheral:didUpdateValueForCharacteristic:error:方法。為了接收這個更新的值罩润,你可以像上面在讀特征值介紹過的樣子實(shí)現(xiàn)這個方法玖翅。

寫特征值(Writing the Value of a Characteristic)

在一些情形下球匕,需要給特征值寫一些信息安券,舉例:如果你的app和一個BLE的數(shù)字恒溫計(jì)工作,你可能需要為房間溫度設(shè)一個數(shù)值珊泳。如果這個特征是可寫的严沥,你可以寫一些數(shù)據(jù)(NSData實(shí)例)猜极,通過調(diào)用CBPeripheral的 writeValue:forCharacteristic:type: 類,像這樣:

NSLog(@"Writing value for characteristic %@", interestingCharacteristic);

[peripheral writeValue:dataToWrite forCharacteristic:interestingCharacteristic

type:CBCharacteristicWriteWithResponse];

當(dāng)你試圖在特征寫入值時消玄,指定你要執(zhí)行哪種寫的操作跟伏。在上面的例子中,寫操作類型是CBCharacteristicWriteWithResponse翩瓜,這表示周邊會讓你知道什么時候?qū)懗晒α耸馨狻8郈oreBluetooth框架支持的寫操作,請查閱CBPeripheral Class Reference.中的CBCharacteristicWriteType 枚舉值兔跌。

周邊會通過調(diào)用委托對象的peripheral:didWriteValueForCharacteristic:error: 方法反饋指定為CBCharacteristicWriteWithResponse的寫操作勘高。如果因?yàn)橐粚懺驅(qū)懭胧。憧梢酝ㄟ^實(shí)現(xiàn)這個方法接收信息,像下面的例子:

- (void)peripheral:(CBPeripheral *)peripheral

didWriteValueForCharacteristic:(CBCharacteristic *)characteristic

error:(NSError *)error {

if (error) {

NSLog(@"Error writing characteristic value: %@",

[error localizedDescription]);

}

...

注意:特征可能只允許某些類型的寫操作在他們的值上執(zhí)行华望。想查看特征值對寫操作的支持詳情层亿,你可以查看Characteristic Properties 枚舉的相關(guān)屬性。詳細(xì)信息在 CBCharacteristic Class Reference.中立美。

執(zhí)行通用周邊角色任務(wù)(Performing Common Peripheral Role Tasks)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末匿又,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子建蹄,更是在濱河造成了極大的恐慌碌更,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件洞慎,死亡現(xiàn)場離奇詭異痛单,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)劲腿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進(jìn)店門旭绒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人焦人,你說我怎么就攤上這事挥吵。” “怎么了花椭?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵忽匈,是天一觀的道長。 經(jīng)常有香客問我矿辽,道長丹允,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任袋倔,我火速辦了婚禮雕蔽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘宾娜。我一直安慰自己批狐,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布碳默。 她就那樣靜靜地躺著贾陷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪嘱根。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天巷懈,我揣著相機(jī)與錄音该抒,去河邊找鬼。 笑死顶燕,一個胖子當(dāng)著我的面吹牛凑保,可吹牛的內(nèi)容都是我干的冈爹。 我是一名探鬼主播,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼欧引,長吁一口氣:“原來是場噩夢啊……” “哼频伤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起芝此,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤憋肖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后婚苹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體岸更,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年膊升,在試婚紗的時候發(fā)現(xiàn)自己被綠了怎炊。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡廓译,死狀恐怖评肆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情非区,我是刑警寧澤糟港,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站院仿,受9級特大地震影響秸抚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜歹垫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一剥汤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧排惨,春花似錦吭敢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至辕宏,卻和暖如春畜晰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瑞筐。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工凄鼻, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓块蚌,卻偏偏與公主長得像闰非,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子峭范,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,666評論 2 350

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