在上篇文章中我們提到了 iOS 開(kāi)發(fā)中,使用GameKit 框架實(shí)現(xiàn)相同網(wǎng)絡(luò)的 iOS 設(shè)備之間傳輸數(shù)據(jù).但是 GameKit 框架在 iOS7 之后就過(guò)時(shí)了,那么本文將介紹另一種關(guān)于藍(lán)牙的框架 CoreBluetooth.
CoreBluetooth
簡(jiǎn)介
- CoreBlueTooth.framework
使用 CoreBluetooth 要求設(shè)備必須要支持藍(lán)牙4.0(一般也叫BLE<Bluetooth low energy>)。,并且手機(jī)型號(hào)必須是iPhone4以上,也就是至少4s手機(jī).使用CoreBluetooth進(jìn)行開(kāi)發(fā)可實(shí)現(xiàn)與第三方設(shè)備的數(shù)據(jù)交互.
上圖是CoreBluetooth 的頭文件,在這個(gè)框架中最核心的兩個(gè)東西就是 Central (中心)和 Peripheral(外設(shè)).
CoreBluetooth 中的對(duì)象模型
CBCentralManager
它用于管理發(fā)現(xiàn)或遠(yuǎn)程連接外圍設(shè)備(CBPeripheral對(duì)象),包括掃描,發(fā)現(xiàn)和外圍設(shè)備連接到廣告.CBPeripheralManager
它用于管理服務(wù)在當(dāng)?shù)匕l(fā)表外圍設(shè)備的通用屬性配置文件數(shù)據(jù)庫(kù)和通知這些服務(wù)的中心設(shè)備(CBCentral對(duì)象).CBPeripheral
它代表遠(yuǎn)程周邊設(shè)備,你的應(yīng)用程序的中央管理器(CBCentralManager)的一個(gè)實(shí)例——發(fā)現(xiàn)廣告或當(dāng)前連接.CBCentral
它代表遠(yuǎn)程中央設(shè)備連接到一個(gè)應(yīng)用程序在本地設(shè)備上實(shí)現(xiàn)外圍的作用.CBService 和 CBMutableService
代表外圍的業(yè)務(wù)數(shù)據(jù)收集,相關(guān)行為完成一個(gè)功能或特性的設(shè)備(或部分設(shè)備).CBMutableService類(lèi)繼承CBService類(lèi)添加寫(xiě)訪問(wèn)的所有屬性.CBCharacteristic及其子類(lèi)CBMutableCharacteristic
代表進(jìn)一步外圍的信息服務(wù).CBMutableCharacteristic對(duì)象代表當(dāng)?shù)奶厣苓叺姆?wù)CBUUID
它的實(shí)例代表128位全局唯一標(biāo)識(shí)符(uuid)屬性中使用藍(lán)牙低能量溝通,比如周邊的服務(wù),特點(diǎn),和特征描述符CBATTRequest
它代表屬性協(xié)議(ATT)讀寫(xiě)請(qǐng)求從遠(yuǎn)程中央設(shè)備(CBCentral對(duì)象)
實(shí)現(xiàn)通訊
中心管理設(shè)計(jì)模式
- First
導(dǎo)入 CoreBluetooth 頭文件,創(chuàng)建中心管理者屬性和外設(shè)屬性,并遵守中心管理者和外設(shè)的協(xié)議.
- 建立中心控制器
懶加載創(chuàng)建中心控制器, 創(chuàng)建的時(shí)候設(shè)置代理為當(dāng)前控制器,Peripheral Manager將跑在主線程中。如果你想用不同的線程做更加復(fù)雜的事情,你需創(chuàng)建一個(gè)隊(duì)列(queue)并將它放在這兒
- (CBCentralManager *)getCManager{
if (!_cManager) {
_cManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue() options:nil];
}
return _cManager;
}
-
更新?tīng)顟B(tài) (只要中心管理者初始化,就會(huì)觸發(fā)此代理方法)
中心管理器的狀態(tài)
中心管理器
- 掃描外設(shè)
// 該方法用于告訴Central Manager,要開(kāi)始尋找一個(gè)指定的服務(wù)了.不能在state非ON的情況下對(duì)我們的中心管理者進(jìn)行操作,scanForPeripheralsWithServices方法中 sercices為空則會(huì)掃描所有的設(shè)備.
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
switch (central.state) {
case CBCentralManagerStateUnknown:
NSLog(@"中心管理器狀態(tài)未知");
break;
case CBCentralManagerStateResetting:
NSLog(@"中心管理器狀態(tài)重置");
break;
case CBCentralManagerStateUnsupported:
NSLog(@"中心管理器狀態(tài)不被支持");
break;
case CBCentralManagerStateUnauthorized:
NSLog(@"中心管理器狀態(tài)未被授權(quán)");
break;
case CBCentralManagerStatePoweredOff:
NSLog(@"中心管理器狀態(tài)電源關(guān)閉");
break;
case CBCentralManagerStatePoweredOn:
{
NSLog(@"中心管理器狀態(tài)電源開(kāi)啟");
// 在中心管理者成功開(kāi)啟后開(kāi)始搜索外設(shè)
[self.cManager scanForPeripheralsWithServices:nil options:nil];
// 搜索成功之后,會(huì)調(diào)用我們找到外設(shè)的代理方法 sercices為空則會(huì)掃描所有的設(shè)備
// - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI; //找到外設(shè)
}
break;
default:
break;
}
}
- 過(guò)濾外設(shè),進(jìn)行連接
如果找到了設(shè)備,則代理會(huì)調(diào)用該方法,過(guò)濾外設(shè)
/*
* @param central 中央管理器提供此更新
* @param peripheral 一個(gè)外設(shè)對(duì)象
* @param advertisementData 一個(gè)包含任何廣播和掃描響應(yīng)數(shù)據(jù)的字典。
* @param RSSI RSSI(Received Signal Strength Indicator)是接收信號(hào)的強(qiáng)度指示
*
*/
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{
if ([peripheral.name hasPrefix:@"XXX"] && (ABS(RSSI.integerValue) > 35)) {
// 標(biāo)記我們的外設(shè),延長(zhǎng)他的生命周期
self.peripheral = peripheral;
// 進(jìn)行連接
[self.cManager connectPeripheral:self.peripheral options:nil];
}
}
- 連接狀態(tài)(成功,失敗,斷開(kāi))
中心管理者連接外設(shè)成功,連接成功之后,可以進(jìn)行服務(wù)和特征的發(fā)現(xiàn)
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
NSLog(@"%@連接成功",peripheral.name);
// 獲取外設(shè)的服務(wù)
// 設(shè)置外設(shè)的代理
self.peripheral.delegate = self;
// 外設(shè)發(fā)現(xiàn)服務(wù),傳nil代表不過(guò)濾
// 這里會(huì)觸發(fā)外設(shè)的代理方法 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
[self.peripheral discoverServices:nil];
}
// 外設(shè)連接失敗
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@"%@連接失敗",peripheral.name);
}
// 丟失連接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@"%@斷開(kāi)連接",peripheral.name);
}
- 發(fā)現(xiàn)服務(wù)以及內(nèi)部的特征
// 發(fā)現(xiàn)外設(shè)的服務(wù)后調(diào)用的方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
// 判斷沒(méi)有失敗
if (error) {
NSLog(@"error:%@",error.localizedDescription);
return;
}
for (CBService *service in peripheral.services) {
[peripheral discoverCharacteristics:nil forService:service];
}
}
// 發(fā)現(xiàn)服務(wù)后,讓設(shè)備再發(fā)現(xiàn)服務(wù)內(nèi)部的特征
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
// 遍歷特征
for (CBCharacteristic *characteristic in service.characteristics) {
// 獲取特征對(duì)應(yīng)的描述
[peripheral discoverDescriptorsForCharacteristic:characteristic];
// 獲取特征的值
[peripheral readValueForCharacteristic:characteristic];
}
}
- 更新特征
// 更新特征的描述的值的時(shí)候會(huì)調(diào)用
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error
{
[peripheral readValueForDescriptor:descriptor];
}
// 更新特征的value的時(shí)候會(huì)調(diào)用
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
for (CBDescriptor *descriptor in characteristic.descriptors) {
[peripheral readValueForDescriptor:descriptor];
}
}
- 外設(shè)寫(xiě)數(shù)據(jù)到特征中
NS_OPTIONS類(lèi)型的枚舉特征屬性,可以是多個(gè)值,這里需要注意,由于枚舉屬性是NS_OPTIONS,所以一個(gè)枚舉可能對(duì)應(yīng)多個(gè)類(lèi)型,所以在判斷的時(shí)候不能用 = ,而應(yīng)該用包含&
- (void)peripheral:(CBPeripheral *)peripheral didWriteData:(NSData *)data forCharacteristic:(nonnull CBCharacteristic *)characteristic
{
//
if (characteristic.properties & CBCharacteristicPropertyWrite) {
// 下面方法中參數(shù)的意義依次是:寫(xiě)入的數(shù)據(jù) 寫(xiě)給哪個(gè)特征 通過(guò)此響應(yīng)記錄是否成功寫(xiě)入
[peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
}
}
- 通知的訂閱和取消訂閱
一般來(lái)說(shuō)這兩個(gè)方法要根據(jù)產(chǎn)品需求來(lái)確定寫(xiě)在什么地方
- (void)peripheral:(CBPeripheral *)peripheral regNotifyWithCharacteristic:(nonnull CBCharacteristic *)characteristic
{
// 外設(shè)為特征訂閱通知
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
- (void)peripheral:(CBPeripheral *)peripheral CancleRegNotifyWithCharacteristic:(nonnull CBCharacteristic *)characteristic
{
// 外設(shè)取消訂閱通知
[peripheral setNotifyValue:NO forCharacteristic:characteristic];
}
- 斷開(kāi)連接
- (void)dismissConentedWithPeripheral:(CBPeripheral *)peripheral
{
// 停止掃描
[self.cManager stopScan];
// 斷開(kāi)連接
[self.cManager cancelPeripheralConnection:peripheral];
}
END
外設(shè)管理設(shè)計(jì)模式,跟中心管理設(shè)計(jì)模式類(lèi)似,就不贅述,需要遵守 外設(shè)管理器協(xié)議 和中心協(xié)議,設(shè)置代理,遵守其中的方法.代碼地址:https://github.com/coderqiao/CoreBluetooth.