Core Bluetooth 是在iOS5首次引入的,它允許iOS設備可以使用健康,運動,安全,自動化,娛樂,附近等外設數據。在iOS 6 中,這個API被擴展了,讓iOS也能成為數據提供方,也就是Server(Peripheral)
端,可能使它與其它 iOS 設備交互數據。
Core Bluetooth API 基於BLE4.0規范。這個框架涵蓋了BLE標准的所有細節. 不過,僅僅只有新的iOS設備和MAC是兼容BLE標准的: iPhone 4S, iPhone5, Mac Mini, New iPad, MacBook Air, MacBook Pro. 並且 iOS 6 iPhone 模擬器也支持一樣的標准.這對你在沒有真機時,開發APP時是非常實用的。
相關的類
在CoreBluetooth框架中,有兩個主要的角色:外設和中心(Peripheral and Central) ,整個框架都是圍繞這兩個主要角色設計的,它們之間有一系列的回調交換數據。 下圖1展示了外設和中心(Peripheral and Central
)的關系。
外設創建或提供一些數據,中心使用這些設備提供的數據。在iOS6之后,iOS 設備也可以即是外設,也可以是中心,但不能在同時間扮演兩個角色。
這兩個組件在CoreBluetooth框架中是分別用兩個類來表示的,中央是CBCentralManager
類,外設是CBPeripheralManager
類。
在中心,一個 CBPeripheral
對象表示正在連接中的外設,同樣在外設里,一個 CBCentral
表示正在連接中的中心.
你可以理解外設是一個廣播數據的設備,它開始告訴外面的世界說它這兒有一些數據,並且能提供一些服務。另一邊中心開始掃描外面有沒有 自己所需要的服務,如果發現后,會和外設做連接請求,一旦連接確定后,兩個設備就可以傳輸數據了。
除了中心與外設,我們還得考慮他們用於交互的數據結構,這些數據在Services(服務)中被結構化,每個服務由不同的Characteristics(特性)所組成。特性定義為一種屬性類型,並且對應一個邏輯值(比如0x2A49)。
你可以在developer bluetooth這里找到標准服務與特性的列表。
比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
在中心里,服務由 CBService
類表示,每個服務由代表特性的 CBCharacteristic
類所構成。
同樣,在外設中服務與特性由 CBMutableService
與 CBMutableCharacteristicclass
類表示。
下圖解釋了他們之間的關系:
CBUUID
和 CBATTRequest
是兩個蘋果提供給我們的幫助類,以便於開發者更簡單地操作數據,稍后你將看到如何使用它們。
使用
不幸的是,Apple提供的文檔目前還不完整,你只有通過WWDC上兩個關於 Core Bluetooth的視頻和頭文件,去理解這個框架是如何工作的。不過,因為我之前已經做過相關方面的事情,我決定和你分享這些內容,我希望下面的教程可以幫助到你。你也可以通過 http://training.invasivecode.com 查看我們的培訓課程.
創建外設 (Peripheral)
為了可以創建一個完整的例子,你需要兩台iOS設備,我將向你展示如何通過藍牙連接這兩個設備,並交換數據。記住先檢查一下你的設備是不是被BLE所支持的。
開始創建一個外設需要下面幾步:
1.創建並且開始Peripheral Manager
2.設置並且發布它的服務。
3.廣播這個服務。
4.和中心連接。
用Single-View Application模板創建一個新的Xcode工程。命名為BlueServer (使用ARC)。工程創建完成后,添加CoreBluetooth.framework 框架。然后打開ViewController.h文件,並且添加以下代碼:
1
|
|
使view controller 遵循 CBPeripheralManagerDelegate
協議,然后添加這個屬性:
1
|
|
在ViewController.m中,添加以下代碼到viewDidLoad方法中:
1
|
|
這行代碼初始化了一個 Peripheral Manager (計划中的第一項). 第一個參數是設置delegate(這里的例子就是view controller)。第二參數(隊列)設置為了nil,因為Peripheral Manager 將運行在主線程中。如果你想用同步的線程做更復雜的事情,你需要單獨創建一個隊列並把它放在這個參數中。
一旦Peripheral Manager被初始化后,我們需要及時檢查正在運行的App設備狀態,是不是符合BLE標准的。所以你要實現下面的這個代理方法(如果設備不支持BLE,你可以友好地提醒用戶。你還可以通過拿到的狀態值做更多事情)。
1 2 3 4 5 6 7 8 9 10 |
|
在這里,我檢查了外設的狀態,如果它的狀態是CBPeripheralManagerStatePoweredOn
,那這個設備是支持BLE並可以繼續執行。
外設的狀態包括有下面這些
1 2 3 4 5 6 7 8 |
|
服務與特性 (Service & Characteristic)
setupService 是一個輔助方法,我們讓它去准備服務和特性,對於這個例子,我們僅僅需要一個服務和一個特性。
每一個服務和特性必要有一個UUID來標識,UUID是一個16位或128位的值。如果你創建的是一個 client-server(中央-外設)應用,那么你需要創建屬於你自己的128位UUID,你必須確保它不能和其他已經存在的服務沖突,如果你要創建一個新的設備,你需要去符合標准委員會的UUID。
如果你創建的是你自己的client-server(正如我們現在做的),我建議你在Terminal下用 uuidgen 命令創建128位的UUID. 所以打開 Terminal並創建兩個(一個為服務,一個為特性).之后,你需要將他們添加到中心和外設應用。這里我們先添加下面幾行在 view controller中。
1 2 |
|
注意:這里的UUID每個人生成的都不一樣,最好是你自己生成
這里是 setupService 的實現方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
首先,我使用+UUIDWithString:
方法創建了一個 UUID 對象,之后我用這個 UUID對象創建了特性。注意,我在初始化時,第三個參數傳的是nil (那個value),之所以這樣做,是因為我告訴 Core Bluetooth我將稍候添加這個特性值,當你需要動態創建數據時,經常這么做。如果你已經有一個靜態的值,你可以直接傳它。
在這個方法中,第一個參數是先創建好的UUID,第二個參數(那個 properties)確定你將如何使用這個特性值,下面是這些可能的值:
1 2 3 4 5 6 7 8 9 10 |
|
最后一個參數是屬性的讀、寫、加密權限,有以下幾種:
1 2 3 4 |
|
創建特性后,我同樣通過+UUIDWithString:
方法創建 UUID,然后通過它創建了服務。 最后我為服務設置對應的這個特性。記住,每個服務可以包括多個特性,正如下面的圖3
所以我們需要通過一個特性數組來添加到服務中,在這個例子里,這個數組對象只有一個特性。
最后一行的代碼是將服務添加到 Peripheral Manager中,用於發布這個服務。一旦這樣做之后,Peripheral Manager 將會通知它的 delegate調用peripheralManager:didAddService:error:
方法。這里如果沒有錯誤,你可以開始廣播這個服務。
1 2 3 4 5 6 |
|
當Peripheral Manager開始廣播這個服務時,delegate 會接收到 peripheralManagerDidStartAdvertising:error:
消息。當中心訂閱 了這個服務時,它的delegate會收到 peripheralManager:central:didSubscribeToCharacteristic:
消息,這兒你可以生成動態數據給中心。
現在,發送數據給中心你需要預先寫一些數據的代碼,然后發送updateValue:forCharacteristic:onSubscribedCentrals:
到外設。
創建一個中心 (Central)
現在,我們已經有了一個外設,讓我們創建中心(client)。記住,中心是用來處理外設提供的數據的。如上面的圖2所示,這里的中心被 CBCentralManager
對象表示。
讓我們創建一個名字為 BlueClient 的 Xcode 項目,使用ARC,並添加 CoreBluetooth.framework ,在 view controller 頭添加
1
|
|
在中心,你必須遵循兩個協議: CBCentralManagerDelegate 和 CBPeripheralDelegate
1
|
|
並添加兩個屬性:
1 2 |
|
現在正如我們之前為外設創建的做法一樣,我們創建中心對象:
1
|
|
同樣,這里的第一個參數表示 CBCentralManager delegate (這里是 view controller). 第二個參數和之前一樣也表示調度隊列,如果設置為空,他會使用主隊列。
一旦 Central Manager 初始化后,我們同樣也要檢查它的狀態,是不是被 BLE 所支持的APP,實現下面的delegate 方法:
1 2 3 4 5 6 7 8 9 10 11 |
|
這個scanForPeripheralsWithServices:options:
方法用於告訴 Central Manager 開始查看特別的服務,如果你第一個參數用的是nil,這個Central Manager 開始查看所有服務。
這個 kServiceUUID 和創建外設中的 ServiceUUID 一樣。所以我們再次添加下面2行代碼在你的實現類中。
1 2 |
|
一旦一個外設在掃描時被發現后,中心 delegate 會收到下面的回調:
1
|
|
這個調用通知Central Manager delegate(在這個例子中就是view controller),一個附帶着廣播數據和信號質量(RSSI-Received Signal Strength Indicator)的周邊被發現。這是一個很酷的參數,知道了信號質量,你可以用它去估計中心與外設的距離。
任何廣播或掃描的響應數據保存在advertisementData 中,可以通過CBAdvertisementData key來訪問它。現在,你可以停止掃描,去連接外設了:
1 2 3 4 5 6 7 8 9 10 11 |
|
options 參數是一個可選的字典(NSDictionary),如果需要,可以用以下的鍵(keys), 它們的值始終是一個boolean。
1 2 3 |
|
基於連接的結果,delegate會接收
1
|
|
或者
1
|
|
中的一個。如果成功了,你可以詢問正在廣播服務的那個外設。因此,在didConnectPeripheral 回調中,你可以寫以下代碼:
1 2 3 4 5 6 7 8 |
|
現在,外設開始用一串回調通知它的delegate。在上面一個方法中,我請求外設去尋找服務,外設代理收到 -peripheral:didDiscoverServices: 如果沒有錯誤,外設可以去查找服務所提供特性,你可以這樣做。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
現在,如果一個特性被發現,外設delegate 又會接收
1
|
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
一旦特征的值用setNotifyValue:forCharacteristic:
更新后,外設就會通知它的delegate。
外設的 delegate 就會接收到
1
|
|
這里,你可以用 readValueForCharacteristic:
讀到新的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
當外設發送新的值時,外設的 delegate 會收到 peripheral:didUpdateValueForCharacteristic:error:
,這個方法的第二個參數包含特性,你可以用 -value
屬性來讀它,這是一個包含了特性值的NSData。
這個時候,你可以為其它數據斷開或等待。
總結
我為你展示了如何使用 Core Bluetooth 框架的基本示例,我希望通過這個教程,加上WWDC視頻,有用的一些文檔能幫助你創建一個 BLE 項目,同時你也可以去參考一些文檔示例,那你會發現我這教程中所有的 delegate 方法。