你好,歡迎來到IOS教程網

 Ios教程網 >> IOS訊息 >> 關於IOS >> 【投稿】iOS 藍牙開發(二)iOS 連接外設的代碼實現

【投稿】iOS 藍牙開發(二)iOS 連接外設的代碼實現

編輯:關於IOS

【投稿】iOS 藍牙開發(二)iOS 連接外設的代碼實現

上一篇文章介紹了藍牙的技術知識,這裡我們具體說明一下中心模式的應用場景。主設備(手機去掃描連接外設,發現外設服務和屬性,操作服務和屬性的應用。一般來說,外設(藍牙設備,比如智能手環之類的東西),會由硬件工程師開發好,並定義好設備提供的服務,每個服務對於的特征,每個特征的屬性(只讀,只寫,通知等等),本文例子的業務場景,就是用一手機app去讀寫藍牙設備。

iOS連接外設的代碼實現流程

1. 建立中心角色

2. 掃描外設(discover)

3. 連接外設(connect)

4. 掃描外設中的服務和特征(discover)

? ? - 4.1 獲取外設的services

? ? - 4.2 獲取外設的Characteristics,獲取Characteristics的值,獲取Characteristics的Descriptor和Descriptor的值

5. 與外設做數據交互(explore and interact)

6. 訂閱Characteristic的通知

7. 斷開連接(disconnect)

准備環境

? 1 Xcode

? 2 開發證書和手機(藍牙程序需要使用使用真機調試,使用模擬器也可以調試,但是方法很蛋疼,我會放在最後說)

? 3 藍牙外設

實現步驟

1 導入CoreBluetooth頭文件,建立主設備管理類,設置主設備委托

????#import?<corebluetooth> ????@interface?ViewController?:?UIViewController<cbcentralmanagerdelegate> ????@interface?ViewController?(){ ????????//系統藍牙設備管理對象,可以把他理解為主設備,通過他,可以去掃描和鏈接外設 ????????CBCentralManager?*manager; ????} ????-?(void)viewDidLoad?{ ????????[super?viewDidLoad]; ????????/* ?????????設置主設備的委托,CBCentralManagerDelegate ????????????必須實現的: ????????????-?(void)centralManagerDidUpdateState:(CBCentralManager?*)central;//主設備狀態改變的委托,在初始化CBCentralManager的適合會打開設備,只有當設備正確打開後才能使用 ????????????其他選擇實現的委托中比較重要的: ????????????-?(void)centralManager:(CBCentralManager?*)central?didDiscoverPeripheral:(CBPeripheral?*)peripheral?advertisementData:(NSDictionary?*)advertisementData?RSSI:(NSNumber?*)RSSI;?//找到外設的委托 ????????????-?(void)centralManager:(CBCentralManager?*)central?didConnectPeripheral:(CBPeripheral?*)peripheral;//連接外設成功的委托 ????????????-?(void)centralManager:(CBCentralManager?*)central?didFailToConnectPeripheral:(CBPeripheral?*)peripheral?error:(NSError?*)error;//外設連接失敗的委托 ????????????-?(void)centralManager:(CBCentralManager?*)central?didDisconnectPeripheral:(CBPeripheral?*)peripheral?error:(NSError?*)error;//斷開外設的委托 ????????*/ ?????????//初始化並設置委托和線程隊列,最好一個線程的參數可以為nil,默認會就main線程 ?????????manager?=?[[CBCentralManager?alloc]initWithDelegate:self?queue:dispatch_get_main_queue()];

2 掃描外設(discover),掃描外設的方法我們放在centralManager成功打開的委托中,因為只有設備成功打開,才能開始掃描,否則會報錯。

????????-(void)centralManagerDidUpdateState:(CBCentralManager?*)central{ ????????????switch?(central.state)?{ ????????????????case?CBCentralManagerStateUnknown: ????????????????????NSLog(@">>>CBCentralManagerStateUnknown"); ????????????????????break; ????????????????case?CBCentralManagerStateResetting: ????????????????????NSLog(@">>>CBCentralManagerStateResetting"); ????????????????????break; ????????????????case?CBCentralManagerStateUnsupported: ????????????????????NSLog(@">>>CBCentralManagerStateUnsupported"); ????????????????????break; ????????????????case?CBCentralManagerStateUnauthorized: ????????????????????NSLog(@">>>CBCentralManagerStateUnauthorized"); ????????????????????break; ????????????????case?CBCentralManagerStatePoweredOff: ????????????????????NSLog(@">>>CBCentralManagerStatePoweredOff"); ????????????????????break; ????????????????case?CBCentralManagerStatePoweredOn: ????????????????????NSLog(@">>>CBCentralManagerStatePoweredOn"); ????????????????????//開始掃描周圍的外設 ????????????????????/* ?????????????????????第一個參數nil就是掃描周圍所有的外設,掃描到外設後會進入 ??????????????????????????-?(void)centralManager:(CBCentralManager?*)central?didDiscoverPeripheral:(CBPeripheral?*)peripheral?advertisementData:(NSDictionary?*)advertisementData?RSSI:(NSNumber?*)RSSI; ?????????????????????*/ ????????????????????[manager?scanForPeripheralsWithServices:nil?options:nil]; ????????????????????break; ????????????????default: ????????????????????break; ????????????} ????????} ????????//掃描到設備會進入方法 ????????-(void)centralManager:(CBCentralManager?*)central?didDiscoverPeripheral:(CBPeripheral?*)peripheral?advertisementData:(NSDictionary?*)advertisementData?RSSI:(NSNumber?*)RSSI{ ????????????NSLog(@"當掃描到設備:%@",peripheral.name); ????????????//接下來可以連接設備 ????????}

3 連接外設(connect)

????????//掃描到設備會進入方法 ????????-(void)centralManager:(CBCentralManager?*)central?didDiscoverPeripheral:(CBPeripheral?*)peripheral?advertisementData:(NSDictionary?*)advertisementData?RSSI:(NSNumber?*)RSSI{ ????????????//接下連接我們的測試設備,如果你沒有設備,可以下載一個app叫lightbule的app去模擬一個設備 ????????????//這裡自己去設置下連接規則,我設置的是P開頭的設備 ???????????????????if?([peripheral.name?hasPrefix:@"P"]){ ???????????????????/* ???????????????????????一個主設備最多能連7個外設,每個外設最多只能給一個主設備連接,連接成功,失敗,斷開會進入各自的委托 ????????????????????-?(void)centralManager:(CBCentralManager?*)central?didConnectPeripheral:(CBPeripheral?*)peripheral;//連接外設成功的委托 ????????????????????-?(void)centralManager:(CBCentralManager?*)central?didFailToConnectPeripheral:(CBPeripheral?*)peripheral?error:(NSError?*)error;//外設連接失敗的委托 ????????????????????-?(void)centralManager:(CBCentralManager?*)central?didDisconnectPeripheral:(CBPeripheral?*)peripheral?error:(NSError?*)error;//斷開外設的委托 ????????????????????*/ ????????????????????//連接設備 ???????????????????[manager?connectPeripheral:peripheral?options:nil]; ???????????????} ????????} ????????//連接到Peripherals-成功 ????????-?(void)centralManager:(CBCentralManager?*)central?didConnectPeripheral:(CBPeripheral?*)peripheral ????????{ ????????????NSLog(@">>>連接到名稱為(%@)的設備-成功",peripheral.name); ????????} ????????//連接到Peripherals-失敗 ????????-(void)centralManager:(CBCentralManager?*)central?didFailToConnectPeripheral:(CBPeripheral?*)peripheral?error:(NSError?*)error ????????{ ????????????NSLog(@">>>連接到名稱為(%@)的設備-失敗,原因:%@",[peripheral?name],[error?localizedDescription]); ????????} ????????//Peripherals斷開連接 ????????-?(void)centralManager:(CBCentralManager?*)central?didDisconnectPeripheral:(CBPeripheral?*)peripheral?error:(NSError?*)error{ ????????????NSLog(@">>>外設連接斷開連接?%@:?%@/n",?[peripheral?name],?[error?localizedDescription]); ????????}

4 掃描外設中的服務和特征(discover)

設備連接成功後,就可以掃描設備的服務了,同樣是通過委托形式,掃描到結果後會進入委托方法。但是這個委托已經不再是主設備的委托(CBCentralManagerDelegate),而是外設的委托(CBPeripheralDelegate),這個委托包含了主設備與外設交互的許多 回叫方法,包括獲取services,獲取characteristics,獲取characteristics的值,獲取characteristics的Descriptor,和Descriptor的值,寫數據,讀rssi,用通知的方式訂閱數據等等。

4.1 獲取外設的services

????????//連接到Peripherals-成功 ????????-?(void)centralManager:(CBCentralManager?*)central?didConnectPeripheral:(CBPeripheral?*)peripheral ????????{ ????????????NSLog(@">>>連接到名稱為(%@)的設備-成功",peripheral.name); ????????????//設置的peripheral委托CBPeripheralDelegate ????????????//@interface?ViewController?:?UIViewController<CBCentralManagerDelegate,CBPeripheralDelegate> ????????????[peripheral?setDelegate:self]; ????????????//掃描外設Services,成功後會進入方法:-(void)peripheral:(CBPeripheral?*)peripheral?didDiscoverServices:(NSError?*)error{ ????????????[peripheral?discoverServices:nil]; ????????} ????????//掃描到Services ????????-(void)peripheral:(CBPeripheral?*)peripheral?didDiscoverServices:(NSError?*)error{ ????????????//??NSLog(@">>>掃描到服務:%@",peripheral.services); ????????????if?(error) ????????????{ ????????????????NSLog(@">>>Discovered?services?for?%@?with?error:?%@",?peripheral.name,?[error?localizedDescription]); ????????????????return; ????????????} ????????????for?(CBService?*service?in?peripheral.services)?{ ?????????????????????????????NSLog(@"%@",service.UUID); ?????????????????????????????//掃描每個service的Characteristics,掃描到後會進入方法:?-(void)peripheral:(CBPeripheral?*)peripheral?didDiscoverCharacteristicsForService:(CBService?*)service?error:(NSError?*)error ?????????????????????????????[peripheral?discoverCharacteristics:nil?forService:service]; ?????????????????????????} ????????}

4.2 獲取外設的Characteristics,獲取Characteristics的值,獲取Characteristics的Descriptor和Descriptor的值

?????//掃描到Characteristics ?????-(void)peripheral:(CBPeripheral?*)peripheral?didDiscoverCharacteristicsForService:(CBService?*)service?error:(NSError?*)error{ ?????????if?(error) ?????????{ ?????????????NSLog(@"error?Discovered?characteristics?for?%@?with?error:?%@",?service.UUID,?[error?localizedDescription]); ?????????????return; ?????????} ?????????for?(CBCharacteristic?*characteristic?in?service.characteristics) ?????????{ ?????????????NSLog(@"service:%@?的?Characteristic:?%@",service.UUID,characteristic.UUID); ?????????} ?????????//獲取Characteristic的值,讀到數據會進入方法:-(void)peripheral:(CBPeripheral?*)peripheral?didUpdateValueForCharacteristic:(CBCharacteristic?*)characteristic?error:(NSError?*)error ?????????for?(CBCharacteristic?*characteristic?in?service.characteristics){ ?????????????{ ?????????????????[peripheral?readValueForCharacteristic:characteristic]; ?????????????} ?????????} ?????????//搜索Characteristic的Descriptors,讀到數據會進入方法:-(void)peripheral:(CBPeripheral?*)peripheral?didDiscoverDescriptorsForCharacteristic:(CBCharacteristic?*)characteristic?error:(NSError?*)error ?????????for?(CBCharacteristic?*characteristic?in?service.characteristics){ ?????????????[peripheral?discoverDescriptorsForCharacteristic:characteristic]; ?????????} ?????} ????//獲取的charateristic的值 ????-(void)peripheral:(CBPeripheral?*)peripheral?didUpdateValueForCharacteristic:(CBCharacteristic?*)characteristic?error:(NSError?*)error{ ????????//打印出characteristic的UUID和值 ????????//!注意,value的類型是NSData,具體開發時,會根據外設協議制定的方式去解析數據 ????????NSLog(@"characteristic?uuid:%@??value:%@",characteristic.UUID,characteristic.value); ????} ????//搜索到Characteristic的Descriptors ????-(void)peripheral:(CBPeripheral?*)peripheral?didDiscoverDescriptorsForCharacteristic:(CBCharacteristic?*)characteristic?error:(NSError?*)error{ ????????//打印出Characteristic和他的Descriptors ?????????NSLog(@"characteristic?uuid:%@",characteristic.UUID); ????????for?(CBDescriptor?*d?in?characteristic.descriptors)?{ ????????????NSLog(@"Descriptor?uuid:%@",d.UUID); ????????} ????} ????//獲取到Descriptors的值 ????-(void)peripheral:(CBPeripheral?*)peripheral?didUpdateValueForDescriptor:(CBDescriptor?*)descriptor?error:(NSError?*)error{ ????????//打印出DescriptorsUUID?和value ????????//這個descriptor都是對於characteristic的描述,一般都是字符串,所以這裡我們轉換成字符串去解析 ????????NSLog(@"characteristic?uuid:%@??value:%@",[NSString?stringWithFormat:@"%@",descriptor.UUID],descriptor.value); ????}

5 把數據寫到Characteristic中

????//寫數據 ????-(void)writeCharacteristic:(CBPeripheral?*)peripheral ????????????????characteristic:(CBCharacteristic?*)characteristic ?????????????????????????value:(NSData?*)value{ ????????//打印出?characteristic?的權限,可以看到有很多種,這是一個NS_OPTIONS,就是可以同時用於好幾個值,常見的有read,write,notify,indicate,知知道這幾個基本就夠用了,前連個是讀寫權限,後兩個都是通知,兩種不同的通知方式。 ????????/* ?????????typedef?NS_OPTIONS(NSUInteger,?CBCharacteristicProperties)?{ ?????????CBCharacteristicPropertyBroadcast??????????????????????????????????????????????=?0x01, ?????????CBCharacteristicPropertyRead???????????????????????????????????????????????????=?0x02, ?????????CBCharacteristicPropertyWriteWithoutResponse???????????????????????????????????=?0x04, ?????????CBCharacteristicPropertyWrite??????????????????????????????????????????????????=?0x08, ?????????CBCharacteristicPropertyNotify?????????????????????????????????????????????????=?0x10, ?????????CBCharacteristicPropertyIndicate???????????????????????????????????????????????=?0x20, ?????????CBCharacteristicPropertyAuthenticatedSignedWrites??????????????????????????????=?0x40, ?????????CBCharacteristicPropertyExtendedProperties?????????????????????????????????????=?0x80, ?????????CBCharacteristicPropertyNotifyEncryptionRequired?NS_ENUM_AVAILABLE(NA,?6_0)????????=?0x100, ?????????CBCharacteristicPropertyIndicateEncryptionRequired?NS_ENUM_AVAILABLE(NA,?6_0)??=?0x200 ?????????}; ?????????*/ ????????NSLog(@"%lu",?(unsigned?long)characteristic.properties); ????????//只有?characteristic.properties?有write的權限才可以寫 ????????if(characteristic.properties?&?CBCharacteristicPropertyWrite){ ????????????/* ????????????????最好一個type參數可以為CBCharacteristicWriteWithResponse或type:CBCharacteristicWriteWithResponse,區別是是否會有反饋 ????????????*/ ????????????[peripheral?writeValue:value?forCharacteristic:characteristic?type:CBCharacteristicWriteWithResponse]; ????????}else{ ????????????NSLog(@"該字段不可寫!"); ????????} ????}

6 訂閱Characteristic的通知

????//設置通知 ????-(void)notifyCharacteristic:(CBPeripheral?*)peripheral ????????????????characteristic:(CBCharacteristic?*)characteristic{ ????????//設置通知,數據通知會進入:didUpdateValueForCharacteristic方法 ????????[peripheral?setNotifyValue:YES?forCharacteristic:characteristic]; ????} ????//取消通知 ????-(void)cancelNotifyCharacteristic:(CBPeripheral?*)peripheral ?????????????????characteristic:(CBCharacteristic?*)characteristic{ ?????????[peripheral?setNotifyValue:NO?forCharacteristic:characteristic]; ????}

7 斷開連接(disconnect)

????//停止掃描並斷開連接 ????-(void)disconnectPeripheral:(CBCentralManager?*)centralManager ?????????????????????peripheral:(CBPeripheral?*)peripheral{ ????????//停止掃描 ????????[centralManager?stopScan]; ????????//斷開連接 ????????[centralManager?cancelPeripheralConnection:peripheral]; ????}

8 模擬器藍牙調試,慎用,最好還是用真機去調試。

由於在iPhone 4s之後的iOS才支持BLE,新一代的這些iOS設備又都不便宜,在做測試的時候,用iOS模擬器進行調試,可以節約一些開發成本。怎麼在iOS模擬器上調試BLE,

蘋果最初給出的說明是,支持BLE的mac機子上可以用模擬器進行調試,並給出了一份技術文檔(傳送門),惡心的是,後來蘋果抽風,又把這份文檔移除,

並且把iOS 7.0的模擬器上對BLE的支持也移除掉了(難道是想讓大家多買設備測試?Apple sucks.)後面,網上搜了一下,解決辦法如下:

1. 買一個CSR藍牙4.0 USB適配器(某寶上大概30塊錢),在機子上插入該物(你懂的)

2. 在Terminal下敲入sudo nvram bluetoothHostControllerSwitchBehavior="never" , 重啟Mac。

3. 用XCode 4.6調試代碼,在iOS 6.1的模擬器上跑程序(用XCode 5.0跑iOS 7.0模擬器會拋異常,原因上面詳訴過了,Apple sucks,你懂的)

如何降低模擬器的iOS版本呢?

XCode->Preferences->Downloads裡面有很多simulators你可以下載

選擇個6.1的下載好了

代碼下載:

我博客中大部分示例代碼都上傳到了github,地址是:https://github.com/coolnameismy/demo

本文代碼存放目錄是BleDemo

如果大家支持,請follow我的github賬號,並star我的項目,有其他問題可以在blog中給我留言 blog的RSS訂閱

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved