藍(lán)牙功能,必不可少的就是CoreBluetooth
框架。
在使用藍(lán)牙的過程中增炭,如果是iOS10及以上機(jī)型需要在info.plist
文件中添加NSBluetoothPeripheralUsageDescription
描述字段睦刃,向用戶聲明使用藍(lán)牙的意圖
藍(lán)牙開發(fā)分為兩種:中心者模式和管理者模式
- 中心者模式
我們的手機(jī)作為中心設(shè)備,連接藍(lán)牙設(shè)備(這也是最常用的一種模式禾嫉,比如使用我們的手機(jī)連接小米手環(huán)、空氣凈化器等湃番;我們以下的開發(fā)也是基于這種模式夭织。) - 管理者模式
我們的手機(jī)作為外設(shè),自己創(chuàng)建服務(wù)于特征吠撮,供其他設(shè)備連接我們的手機(jī)
關(guān)鍵詞
- 中心設(shè)備:用于掃描周邊藍(lán)牙外設(shè)的設(shè)備尊惰,比如我們上面所說的中心者模式讲竿,此時(shí)我們的手機(jī)就是中心設(shè)備。
- 外設(shè):被掃描的藍(lán)牙設(shè)備弄屡,比如我們上面所說的用我們的手機(jī)連接小米手環(huán)题禀,這時(shí)候小米手環(huán)就是外設(shè)。
- 廣播:外部設(shè)備不停的散播的藍(lán)牙信號(hào)膀捷,讓中心設(shè)備可以掃描到迈嘹,也是我們開發(fā)中接收數(shù)據(jù)的入口。
- 服務(wù)(Service):外部設(shè)備在與中心設(shè)備連接后會(huì)有服務(wù)全庸,可以理解成一個(gè)功能模塊秀仲,中心設(shè)備可以讀取服務(wù),篩選我們想要的服務(wù)壶笼,并從中獲取出我們想要特征神僵。(外設(shè)可以有多個(gè)服務(wù))
- 特征(Characteristic):服務(wù)中的一個(gè)單位,一個(gè)服務(wù)可以多個(gè)特征覆劈,而特征會(huì)有一個(gè)value保礼,一般我們向藍(lán)牙設(shè)備寫入數(shù)據(jù)、從藍(lán)牙設(shè)備讀取數(shù)據(jù)就是這個(gè)value
- UUID:區(qū)分不同服務(wù)和特征的唯一標(biāo)識(shí)责语,使用該字端我們可以獲取我們想要的服務(wù)或者特征硼莽。
CBCentralManager
- 初始化
CBCentralManager 對(duì)象用于掃描萧朝、發(fā)現(xiàn)仔役、連接遠(yuǎn)程的外圍設(shè)備间护。系統(tǒng)提供了兩個(gè)初始化該類的方法
- (instancetype)initWithDelegate:(id)delegate queue:(dispatch_queue_t)queue;
- (instancetype)initWithDelegate:(id)delegate queue:(dispatch_queue_t)queue options:(NSDictionary *)options;
在第二個(gè)初始化方法中,初始化的選項(xiàng)情況如下:
-
CBCentralManagerOptionShowPowerAlertKey
用于當(dāng)中心管理類被初始化時(shí)若此時(shí)藍(lán)牙系統(tǒng)為關(guān)閉狀態(tài)铐拐,是否向用戶顯示警告對(duì)話框徘键。該字段對(duì)應(yīng)的是NSNumber
類型的對(duì)象,默認(rèn)值為NO -
CBCentralManagerOptionRestoreIdentifierKey
中心管理器的唯一標(biāo)識(shí)符遍蟋,系統(tǒng)根據(jù)這個(gè)標(biāo)識(shí)識(shí)別特定的中心管理器,為了繼續(xù)執(zhí)行應(yīng)用程序螟凭,標(biāo)識(shí)符必須保持不變虚青,才能還原中心管理類
(1) 導(dǎo)入CoreBluetooth
頭文件,并遵循兩個(gè)協(xié)議
(2) 建立中心角色(將手機(jī)作為中心角色螺男,可以搜索外部藍(lán)牙設(shè)備)
/*中心角色*/
@property (nonatomic, strong) CBCentralManager *mgr;
/*外設(shè)角色棒厘,我們當(dāng)選中某個(gè)外設(shè)連接成功后,將外設(shè)對(duì)象賦值給該對(duì)象*/
@property (nonatomic, strong) CBPeripheral *peripheral;
/*在viewDidLoad中實(shí)例化并設(shè)置代理*/
_mgr = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
- 狀態(tài)的監(jiān)控
當(dāng)藍(lán)牙狀態(tài)發(fā)現(xiàn)變化時(shí)回調(diào)
/*
* CBCentralManagerStateUnknown 狀態(tài)未知
* CBCentralManagerStateResetting 連接斷開 即將重置
* CBCentralManagerStateUnsupported 該平臺(tái)不支持藍(lán)牙
* CBCentralManagerStateUnauthorized 未授權(quán)藍(lán)牙使用
* CBCentralManagerStatePoweredOff 藍(lán)牙關(guān)閉
* CBCentralManagerStatePoweredOn 藍(lán)牙正常開啟
*
* 該方法必須實(shí)現(xiàn)下隧,否則系統(tǒng)報(bào)錯(cuò)
*/
- (void)centralManagerDidUpdateState:(CBCentralManager *)central;
當(dāng)系統(tǒng)恢復(fù)時(shí)先調(diào)用此方法
/*
*app狀態(tài)的保存或者恢復(fù)奢人,這是第一個(gè)被調(diào)用的方法當(dāng)APP進(jìn)入后臺(tái)去完成一些藍(lán)牙有關(guān)的工作設(shè)置,使用這個(gè)方法同步app狀態(tài)通過藍(lán)牙系統(tǒng)
*
* dic中的信息
* CBCentralManagerRestoredStatePeripheralsKey 在系統(tǒng)終止程序時(shí)淆院,包含的已經(jīng)連接或者正在連接的外設(shè)的集合
* CBCentralManagerRestoredStateScanServicesKey 系統(tǒng)終止應(yīng)用程序時(shí)中心管理器連接的服務(wù)UUID數(shù)組
* CBCentralManagerRestoredStateScanOptionsKey 系統(tǒng)終止應(yīng)用程序時(shí)中心管理器正在使用的外設(shè)選項(xiàng)
*/
- (void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary *)dict;
中心角色一旦創(chuàng)建何乎,藍(lán)牙狀態(tài)改變的代理方法就會(huì)自動(dòng)執(zhí)行,返回當(dāng)前藍(lán)牙狀態(tài)
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
switch (central.state) {
case 0:
NSLog(@"CBCentralManagerStateUnknown");//設(shè)備類型位置
break;
case 1:
NSLog(@"CBCentralManagerStateResetting");//設(shè)備初始化中
break;
case 2:
NSLog(@"CBCentralManagerStateUnsupported");//不支持藍(lán)牙
break;
case 3:
NSLog(@"CBCentralManagerStateUnauthorized");//設(shè)備未授權(quán)
break;
case 4:
{
NSLog(@"CBCentralManagerStatePoweredOff");//藍(lán)牙未開啟
}
break;
case 5:
{
NSLog(@"CBCentralManagerStatePoweredOn");//藍(lán)牙已開始
//如果想自動(dòng)掃描,在此處開始掃描即可
}
break;
default:
break;
}
}
3.開啟掃描
當(dāng)系統(tǒng)第一次發(fā)現(xiàn)外設(shè)時(shí)支救,會(huì)根據(jù)mac地址等生成一個(gè)特定的標(biāo)識(shí)符抢野,此時(shí)我們可以保存這個(gè)特定的標(biāo)識(shí)符用于后續(xù)的重連操作 系統(tǒng)提供唯一的方法進(jìn)行對(duì)周邊設(shè)備的掃描
//掃描設(shè)備
- (void)scanForPeripheralsWithServices:(NSArray *)serviceUUIDs ptions:(NSDictionary *)options;
//停止掃描設(shè)備
- (void)stopScan;
- 初始化的options選項(xiàng)詳情如下:
CBCentralManagerScanOptionAllowDuplicatesKey
是否允許重復(fù)掃描設(shè)備,默認(rèn)為NO各墨,官方建議此值為NO指孤,當(dāng)為YES時(shí),可能對(duì)電池壽命產(chǎn)生影響贬堵,建議在必要時(shí)才使用
UUID 表示外設(shè)的服務(wù)標(biāo)識(shí)恃轩,當(dāng)serviceUUIDs
參數(shù)為nil
時(shí),將返回所有發(fā)現(xiàn)的外設(shè)(蘋果不推薦此種做法)黎做;當(dāng)填寫改服務(wù)標(biāo)識(shí)時(shí)详恼,系統(tǒng)將返回對(duì)應(yīng)該服務(wù)標(biāo)識(shí)的外設(shè) - 可以指定允許應(yīng)用程序在后臺(tái)掃描設(shè)備,前提必須滿足兩個(gè)條件:
必須允許在藍(lán)牙的后臺(tái)模式
必須指定一個(gè)或多個(gè)UUID服務(wù)標(biāo)識(shí)
手動(dòng)開啟掃描
- (void)searchDevcie{
if(_mgr!=nil&& _mgr.state==5){
[self. mgr scanForPeripheralsWithServices:nil options:nil];
}
}
每當(dāng)搜索到一個(gè)外設(shè)之后引几,都會(huì)自動(dòng)觸發(fā)以下方法昧互,每發(fā)現(xiàn)一個(gè)藍(lán)牙設(shè)備都會(huì)調(diào)用此函數(shù),因?yàn)槟壳八{(lán)牙設(shè)備越來越多(小米伟桅、顯示器敞掘、ofo...),所以我在此處做了篩選楣铁,只要我的設(shè)備
- (void)centralManager:(CBCentralManager *)central // 中心管理者didDiscoverPeripheral:(CBPeripheral *)peripheral // 外設(shè)advertisementData:(NSDictionary *)advertisementData // 外設(shè)攜帶的數(shù)據(jù)
RSSI:(NSNumber *)RSSI{ // 外設(shè)發(fā)出的藍(lán)牙信號(hào)強(qiáng)度
if ([peripheral.name hasPrefix:@"HT"]) {
NSLog(@"%@",peripheral.name);//能夠進(jìn)來的 都是我們想要的設(shè)備了
//我們的邏輯是玖雁,搜索到一個(gè)設(shè)備(peripheral)放到一個(gè)集合,然后給用戶進(jìn)行選擇
}
}
4.根據(jù)上面掃描的設(shè)備列表盖腕,接下來做的就是連接設(shè)備了赫冬。
//連接外設(shè)
- (void)connectPeripheral:(CBPeripheral *)peripheral options:(NSDictionary *)options;
//斷開與外設(shè)的連接
- (void)cancelPeripheralConnection:(CBPeripheral *)peripheral;
連接設(shè)備時(shí)選項(xiàng)情況如下:
-
CBConnectPeripheralOptionNotifyOnConnectionKey
應(yīng)用程序被掛起時(shí),成功連接到外設(shè)溃列,是否向用戶顯示警告對(duì)話框劲厌,對(duì)應(yīng)NSNumber對(duì)象,默認(rèn)值為NO -
CBConnectPeripheralOptionNotifyOnDisconnectionKey
應(yīng)用程序被掛起時(shí)听隐,與外設(shè)斷開連接补鼻,是否向用戶顯示警告對(duì)話框,對(duì)應(yīng)NSNumber對(duì)象雅任,默認(rèn)值為NO -
CBConnectPeripheralOptionNotifyOnNotificationKey
應(yīng)用程序被掛起時(shí)风范,只要接收到給定peripheral的通知,是否就彈框顯示
官方建議如果連接設(shè)備不成功且沒有進(jìn)行重連沪么,要明確取消與外設(shè)的連接(即調(diào)用斷開與外設(shè)連接的方法) 當(dāng)調(diào)用斷開方法硼婿,斷開與設(shè)備連接時(shí),官方明確表明取消本地連接不能保證物理鏈接立即斷開禽车。當(dāng)設(shè)備連接時(shí)間超過8秒后寇漫,調(diào)用斷開的API能立即斷開刊殉;但是連接未超過8秒,就調(diào)用斷開API需要幾秒后系統(tǒng)才與設(shè)備斷開連接
- 通過搜索系統(tǒng)獲取periphera對(duì)象
//獲取與系統(tǒng)已經(jīng)連接的外設(shè)對(duì)象猪腕,如果設(shè)備已經(jīng)與系統(tǒng)連接冗澈,通過該方法獲取到外設(shè)對(duì)象后可以直接對(duì)CBPeripheral對(duì)象發(fā)起連接
- (NSArray *)retrieveConnectedPeripheralsWithServices:(NSArray *)serviceUUIDs;
//獲取一個(gè)已知CBPeripheral的列表(過去曾經(jīng)發(fā)現(xiàn)過或者連接過的peripheral)
- (NSArray *)retrievePeripheralsWithIdentifiers:(NSArray *)identifiers;
CBCentralManagerDelegate
啟動(dòng)搜索發(fā)現(xiàn)設(shè)備后調(diào)用此代理
/*
* advertisementData 廣播中的信息
*
* CBAdvertisementDataLocalNameKey 對(duì)應(yīng)設(shè)置NSString類型的廣播名
* CBAdvertisementDataManufacturerDataKey 外設(shè)制造商的NSData數(shù)據(jù)
* CBAdvertisementDataServiceDataKey 外設(shè)制造商的CBUUID數(shù)據(jù)
* CBAdvertisementDataServiceUUIDsKey 服務(wù)的UUID與其對(duì)應(yīng)的服務(wù)數(shù)據(jù)字典數(shù)組
* CBAdvertisementDataOverflowServiceUUIDsKey 附加服務(wù)的UUID數(shù)組
* CBAdvertisementDataTxPowerLevelKey 外設(shè)的發(fā)送功率 NSNumber類型
* CBAdvertisementDataIsConnectable 外設(shè)是否可以連接
* CBAdvertisementDataSolicitedServiceUUIDsKey 服務(wù)的UUID數(shù)組
*
* RSSI 收到當(dāng)前信號(hào)的強(qiáng)度 單位為分貝
*
* 如果后續(xù)要使用peripheral對(duì)象,必須在引用該對(duì)象陋葡,否則后續(xù)操作無法進(jìn)行
*/
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI;
當(dāng)設(shè)備連接成功后調(diào)用此代理
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;
當(dāng)設(shè)備斷開連接后調(diào)用此代理方法
//當(dāng)斷開連接后亚亲,外設(shè)中所有的服務(wù)、特征腐缤、特征描述都將失效
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;
當(dāng)連接失敗后調(diào)用此代理方法
//在ios系統(tǒng)的藍(lán)牙連接中捌归,不存在超時(shí)的現(xiàn)象,因此連接通常表示為一個(gè)暫時(shí)性的問題岭粤,可在改方法中再次嘗試連接
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;
下面
//從設(shè)備列表選中我們要的設(shè)備 連接設(shè)備
- (void)connectDevice:(CBPeripheral *)peripheral{
[self.mgr connectPeripheral:peripheral options:nil];
}
連接相關(guān)的代理方法:
// 中心管理者連接外設(shè)成功(如果外設(shè)成功與中心設(shè)備連接成功之后會(huì)自動(dòng)觸發(fā)該方法)
- (void)centralManager:(CBCentralManager *)central // 中心管理者
didConnectPeripheral:(CBPeripheral *)peripheral // 外設(shè)
{
NSLog(@"連接成功");
// 標(biāo)記我們的外設(shè),讓他的生命周期 = ViewController
self.peripheral = peripheral;
// 設(shè)置外設(shè)的代理
self.peripheral.delegate = self;
// 外設(shè)發(fā)現(xiàn)服務(wù),傳nil代表不過濾
//調(diào)用該方法后惜索,將會(huì)自動(dòng)調(diào)用didDiscoverServices()代理方法,用于發(fā)現(xiàn)服務(wù)
[self.peripheral discoverServices:nil];
//既然連接上了剃浇,為了解決性能巾兆,就停止掃描吧
[_mgr stopScan];
}
// 外設(shè)連接失敗
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@"連接失敗");
}
// 丟失連接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@"斷開連接");
}
發(fā)現(xiàn)特征
/*
* 參數(shù)characteristicUUIDs不為空時(shí),返回對(duì)應(yīng)的特征值虎囚,當(dāng)參數(shù)為nil時(shí)角塑,返回該服務(wù)中的所有特征值
*/
- (void)discoverCharacteristics:(NSArray *)characteristicUUIDs forService:(CBService *)service;
//發(fā)現(xiàn)特征值描述
- (void)discoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic;
發(fā)現(xiàn)服務(wù)的回調(diào)
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error;
發(fā)現(xiàn)服務(wù)中的服務(wù)的回調(diào)
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverIncludedServicesForService:(CBService *)service error:(NSError *)error;
發(fā)現(xiàn)特征的回調(diào)
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error;
發(fā)現(xiàn)特征描述的回調(diào)
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;
當(dāng)調(diào)用[self.peripheral discoverServices:nil];方法之后,當(dāng)發(fā)現(xiàn)服務(wù)后就會(huì)自動(dòng)調(diào)用以下的didDiscoverServices()代理方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
NSLog(@"didDiscoverServices");
if (error)
{
NSLog(@"Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]);
return;
}
//服務(wù)并不是我們的目標(biāo)淘讥,也沒有實(shí)際意義圃伶。我們需要用的是服務(wù)下的特征,查詢(每一個(gè)服務(wù)下的若干)特征
for (CBService *service in peripheral.services)
{
//好蒲列,發(fā)現(xiàn)了服務(wù) 接下來就是最重要的特征了
//調(diào)用該方法后窒朋,當(dāng)發(fā)現(xiàn)了service服務(wù)中的特征后,將會(huì)自動(dòng)觸發(fā)didDiscoverCharacteristicsForService()方法
[peripheral discoverCharacteristics:nil forService:service];
}
}
當(dāng)特征值發(fā)現(xiàn)變化時(shí)回調(diào)
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;
當(dāng)特征值描述發(fā)生變化時(shí)回調(diào)
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error;
發(fā)現(xiàn)外設(shè)服務(wù)里的特征的時(shí)候調(diào)用的代理方法(這個(gè)是比較重要的方法蝗岖,你在這里可以通過事先知道UUID找到你需要的特征侥猩,訂閱特征,或者這里寫入數(shù)據(jù)給特征也可以)
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
NSLog(@"didDiscoverCharacteristicsForService");
//在此處可以獲取服務(wù)中的特征了剪侮,與硬件工程師溝通后得知拭宁,uuid為ffe2的特征是用于向外部藍(lán)牙設(shè)備寫數(shù)據(jù)的,uuid為ffe1的特征是用于從外部藍(lán)牙設(shè)備讀取數(shù)據(jù)的瓣俯,那讀信息,因?yàn)槲以谙旅嫦蛩{(lán)牙外部設(shè)備寫數(shù)據(jù)的時(shí)候兵怯,我使用了一個(gè)參數(shù):CBCharacteristicWriteWithoutResponse(也就是說彩匕,沒有回調(diào),因那沒有回調(diào)就取不到數(shù)據(jù)咯媒区?但是我們可以給讀取數(shù)據(jù)的服務(wù)設(shè)置一個(gè)通知驼仪,也就是下面的setNotifyValue:方法了掸犬,一旦設(shè)置,如果外部藍(lán)牙設(shè)備給中心設(shè)備發(fā)送信息绪爸,我們就能在didUpdateValueForCharacteristic代理方法中進(jìn)行獲取了)
for (CBCharacteristic *cha in service.characteristics) {
if([[cha.UUID.UUIDString lowercaseString] isEqualToString:@"ffe2"]){
self.characteristic = cha;
}else if([[cha.UUID.UUIDString lowercaseString] isEqualToString:@"ffe1"]){
self.readcharacteristic = cha;
[self.peripheral setNotifyValue:YES forCharacteristic:self.readcharacteristic];
}
}
}
接下來我們就能從外部藍(lán)牙設(shè)備中接收數(shù)據(jù)了
讀取數(shù)據(jù)
/* 讀取特征值
* 并非所有特征都有特征值湾碎,需通過CBCharacteristicProperties枚舉判斷該特征是否可讀
*/
- (void)readValueForCharacteristic:(CBCharacteristic *)characteristic;
//讀取特征值描述
- (void)readValueForDescriptor:(CBDescriptor *)descriptor;
//從外圍設(shè)備獲取數(shù)據(jù)
// 更新特征的value的時(shí)候會(huì)調(diào)用 (凡是從藍(lán)牙傳過來的數(shù)據(jù)都要經(jīng)過這個(gè)回調(diào),簡單的說這個(gè)方法就是你拿數(shù)據(jù)的唯一方法) 你可以判斷是否
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
//因?yàn)槲覀兪莾蓚€(gè)特征 一個(gè)讀 一個(gè)寫 所以我讀取數(shù)據(jù)奠货,只要從讀的特征中獲取就可以了
if (characteristic == self.readcharacteristic) {
//characteristic.value 就是我們想要的數(shù)據(jù)了
}
}
重頭戲到了介褥,接下來就是向外部藍(lán)牙設(shè)備寫數(shù)據(jù)了
寫入數(shù)據(jù)
/*
* 寫入數(shù)據(jù),只允許對(duì)其特定的類型進(jìn)行寫入操作
* 通過characteristic的properties的判斷递惋,判別支持那種類型的寫入
* CBCharacteristicWriteWithResponse 如果寫入不成功柔滔,將以詳細(xì)錯(cuò)誤說明進(jìn)行響應(yīng)
* CBCharacteristicWriteWithoutResponse 如果寫入失敗,則不會(huì)收到通知
*/
- (void)writeValue:(NSData *)data forCharacteristic:(CBCharacteristic *)characteristic type:(CBCharacteristicWriteType)type;
//寫入特征值的描述萍虽,一般為字符串對(duì)characteristic的描述
- (void)writeValue:(NSData *)data forDescriptor:(CBDescriptor *)descriptor;
設(shè)置特征值的通知
//如果設(shè)置為YES睛廊,當(dāng)特征值發(fā)現(xiàn)變化時(shí)則會(huì)發(fā)起通知
- (void)setNotifyValue:(BOOL)enabled forCharacteristic:(CBCharacteristic *)characteristic;
只需要調(diào)用以下方法就可以實(shí)現(xiàn)數(shù)據(jù)寫入了,【subData就是我們的需要寫入外部藍(lán)牙設(shè)備的數(shù)據(jù)了;self.characteristic是我們寫的服務(wù)杉编;CBCharacteristicWriteWithoutResponse 不需要回調(diào)函數(shù)(一開始踩了個(gè)坑設(shè)置的CBCharacteristicWriteWithResponse超全,報(bào)錯(cuò)"writing is not permitted")】
[self.peripheral writeValue:subData forCharacteristic:self.characteristic type:CBCharacteristicWriteWithoutResponse];
遇到的坑:我們?cè)谙驍z像頭藍(lán)牙設(shè)備寫入指令的時(shí)候,我們的指令比較長(達(dá)到了200byte左右邓馒,但是我們的攝像頭設(shè)備藍(lán)牙內(nèi)部接收緩沖區(qū)只有16個(gè)字節(jié))嘶朱,所以我們只能選擇分包發(fā)送了,將200byte的指令拆開發(fā)送
如果你們的指令正好在你們的緩沖區(qū)閥值之內(nèi)绒净,那就無須使用以下代碼了
-(void)sendDataWithSubPackage:(NSData*)goalData
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
for (int i = 0; i < [msgData length]; i += 16) {
// 預(yù)加 最大包長度见咒,如果依然小于總數(shù)據(jù)長度,可以取最大包數(shù)據(jù)大小
if ((i + 16) < [msgData length]) {
NSRange range = NSMakeRange(i, 16);
NSData *subData = [msgData subdataWithRange:range];
[self.peripheral writeValue:subData forCharacteristic:self.characteristic type:CBCharacteristicWriteWithoutResponse];
//根據(jù)接收模塊的處理能力做相應(yīng)延時(shí),因?yàn)樗{(lán)牙設(shè)備處理指令需要時(shí)間挂疆,所以我這邊給了500毫秒
usleep(500 * 1000);
}else {
NSString *rangeStr = [NSString stringWithFormat:@"%i,%i", i, (int)([msgData length] - i)];
NSData *subData = [msgData subdataWithRange:NSRangeFromString(rangeStr)];
[self.peripheral writeValue:subData forCharacteristic:self.characteristic type:CBCharacteristicWriteWithoutResponse];
usleep(500 * 1000);
}
}
});
}
發(fā)現(xiàn)服務(wù)
- 發(fā)現(xiàn)外設(shè)指定的服務(wù)
* 當(dāng)設(shè)置serviceUUIDs參數(shù)時(shí)改览,只返回指定的服務(wù)(官方推薦做法)
* 當(dāng)為指定serviceUUIDs參數(shù)時(shí),將返回外設(shè)中所有可用的服務(wù)
*/
- (void)discoverServices:(NSArray *)serviceUUIDs;
從服務(wù)中發(fā)現(xiàn)服務(wù)
- (void)discoverIncludedServices:(NSArray *)includedServiceUUIDs forService:(CBService *)service;
讀取RSSI
//當(dāng)調(diào)用此方法時(shí)缤言,外設(shè)會(huì)調(diào)用peripheral:didReadRSSI:error:代理方法
- (void)readRSSI;
獲取最大的寫入長度
/* 根據(jù)寫入類型獲取最大的寫入長度
* CBCharacteristicWriteWithResponse宝当、CBCharacteristicWriteWithoutResponse
*/
- (NSUInteger)maximumWriteValueLengthForType:(CBCharacteristicWriteType)type;
CBPeripheralDelegate
寫入特征值時(shí)回調(diào)
//只有指定寫入類型有回應(yīng)時(shí)才回到此方法
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;
寫入特征值描述時(shí)回調(diào)
//當(dāng)調(diào)用寫入特征值描述時(shí)回調(diào)該方法
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error;
當(dāng)外設(shè)啟動(dòng)或者停止指定特征值的通知時(shí)回調(diào)
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;
當(dāng)連接外設(shè)成功后獲取信號(hào)強(qiáng)度的方法后回調(diào)
- (void)peripheral:(CBPeripheral *)peripheral didReadRSSI:(NSNumber *)RSSI error:(NSError *)error;
當(dāng)外設(shè)名稱發(fā)生變化時(shí)回調(diào)
//由于外設(shè)可以改變其設(shè)備名稱,因此若要顯示該設(shè)備的當(dāng)前名稱可在該方法中處理
- (void)peripheralDidUpdateName:(CBPeripheral *)peripheral;
當(dāng)外設(shè)服務(wù)發(fā)生變化時(shí)回調(diào)
- (void)peripheral:(CBPeripheral *)peripheral didModifyServices:(NSArray *)invalidatedServices;
CBCharacteristic
擁有的屬性
- service 該特征所屬的服務(wù)
- value 該特征的值
- isNotifying 是否訂閱特征值
- descriptors 該特征的描述列表
- properties 性質(zhì)特點(diǎn)
1胆萧、CBCharacteristicPropertyBroadcast 該屬性為廣播類型
2庆揩、CBCharacteristicPropertyRead 可讀
3、CBCharacteristicPropertyWriteWithoutResponse 寫-沒有響應(yīng)
4跌穗、CBCharacteristicPropertyWrite 可寫
5订晌、CBCharacteristicPropertyNotify 通知
6、CBCharacteristicPropertyIndicate 聲明
7蚌吸、CBCharacteristicPropertyAuthenticatedSignedWrites 通過驗(yàn)證的
8锈拨、CBCharacteristicPropertyExtendedProperties 拓展
9、CBCharacteristicPropertyNotifyEncryptionRequired 需要加密的通知
10羹唠、CBCharacteristicPropertyIndicateEncryptionRequired 需要加密的申明