iOS藍(lán)牙開發(fā)有三個(gè)框架
1.GameKit.framework:iOS7之前的藍(lán)牙通訊框架昧谊,從iOS7開始過期凤价。
2.MultipeerConnectivity.framework:iOS7開始引入的新的藍(lán)牙通訊開發(fā)框架鸽斟,用于取代GameKit。
3.CoreBluetooth.framework:功能強(qiáng)大的藍(lán)牙開發(fā)框架利诺,要求設(shè)備必須支持藍(lán)牙4.0富蓄。目前藍(lán)牙開發(fā)多半基于此框架,此筆記也是寫基于此框架慢逾。
藍(lán)牙開發(fā)有兩種模式:
1.手機(jī)作為中心設(shè)備立倍,獲取外設(shè)的數(shù)據(jù)
2.手機(jī)作為外設(shè)躏吊,對(duì)外提供數(shù)據(jù)(這里不做討論)
本文記錄的是利用tableView展示所有掃描到的外設(shè),點(diǎn)擊某行時(shí)連接對(duì)應(yīng)的外設(shè)進(jìn)行數(shù)據(jù)交互
實(shí)現(xiàn)流程如下:
1.導(dǎo)入藍(lán)牙庫帐萎,宏定義服務(wù)UUID、讀數(shù)據(jù)UUID胜卤、寫數(shù)據(jù)UUID
#import <CoreBluetooth/CoreBluetooth.h>
#define kServiceUUID @"1234"http://服務(wù)UUID
#define kReadUUID @"1236"http://讀數(shù)據(jù)UUID
#define kWriteUUID @"1235"http://寫數(shù)據(jù)UUID
@property (nonatomic, strong) CBPeripheral *peripheral; //外設(shè)
@property (nonatomic, strong) CBCentralManager *myCentralManager; //管理中心
@property (nonatomic, strong) CBCharacteristic *readCharacteristic; //讀取數(shù)據(jù)特性
@property (nonatomic, strong) CBCharacteristic *writeCharacteristic; //寫數(shù)據(jù)特性
2.創(chuàng)建藍(lán)牙管理中心
_myCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];//如果設(shè)置為nil疆导,默認(rèn)在主線程中跑。設(shè)置了代理為self葛躏,記得遵守協(xié)議
3.監(jiān)測藍(lán)牙狀態(tài)澈段,如果藍(lán)牙開啟則掃描外設(shè)
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
switch (central.state){
case CBCentralManagerStateUnknown:
break;
case CBCentralManagerStateUnsupported:
JCLog(@"模擬器不支持藍(lán)牙調(diào)試");
break;
case CBCentralManagerStateUnauthorized:
break;
case CBCentralManagerStatePoweredOff:{
JCLog(@"藍(lán)牙處于關(guān)閉狀態(tài)");
}
break;
case CBCentralManagerStateResetting:
break;
case CBCentralManagerStatePoweredOn:{
JCLog(@"藍(lán)牙已開啟");
//開始掃描外設(shè)
[_myCentralManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey:[NSNumber numberWithBool:NO]}];
}
break;
}
}
4.實(shí)現(xiàn)代理方法。當(dāng)掃描到外部設(shè)備時(shí)會(huì)進(jìn)入 發(fā)現(xiàn)外設(shè) 的代理方法
- (void)centralManager:(CBCentralManager *)central //管理中心
didDiscoverPeripheral:(CBPeripheral *)peripheral //發(fā)現(xiàn)的外設(shè)
advertisementData:(NSDictionary *)advertisementData //外設(shè)中的廣播數(shù)據(jù)
RSSI:(NSNumber *)RSSI //外設(shè)信號(hào)強(qiáng)度
{
// JCLog(@"藍(lán)牙廣播數(shù)據(jù)------>>%@",advertisementData);
//每次掃描出一個(gè)外設(shè)都會(huì)進(jìn)入此代理方法舰攒,在此方法中可以將外設(shè)添加到外設(shè)數(shù)組中败富,在添加進(jìn)數(shù)組之前,判斷一下數(shù)組中是否已經(jīng)添加過這個(gè)外設(shè)摩窃,如果添加過兽叮,則不再添加。
if(![_allperipherals containsObject:peripheral]){
[_allperipherals addObject:peripheral];
//添加了新的外設(shè)進(jìn)去猾愿,刷新tableview
[_tableView reloadData];
}
5.連接外設(shè)
//在選中某行cell的代理方法中鹦聪,調(diào)用連接藍(lán)牙外設(shè)的方法
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//需要連接的外設(shè)必須強(qiáng)引用,否則出了此方法作用域后會(huì)被釋放掉蒂秘,導(dǎo)致藍(lán)牙斷開連接泽本,控制臺(tái)輸出錯(cuò)誤信息
_peripheral = _allperipherals[indexPath.row];
JCLog(@"連接藍(lán)牙:%@",_peripheral.name);
[_myCentralManager connectPeripheral:_peripheral options:nil];//連接藍(lán)牙
}
6.藍(lán)牙連接成功,會(huì)調(diào)用代理方法
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
// JCLog(@"成功連接%@",peripheral.name);
_peripheral = peripheral;
peripheral.delegate = self;
//開始尋找外設(shè)服務(wù)
[peripheral discoverServices:nil];
/*
關(guān)于外設(shè)服務(wù)是什么的理解:
每個(gè)藍(lán)牙4.0的設(shè)備都是通過服務(wù)和特征來展示自己的姻僧,一個(gè)設(shè)備必然包含一個(gè)或多個(gè)服務(wù)规丽,每個(gè)服務(wù)下面又包含若干個(gè)特征。
特征是與外界交互的最小單位撇贺。比如說赌莺,一臺(tái)藍(lán)牙4.0設(shè)備,用特征A來描述自己的出廠信息显熏,用特征B來與收發(fā)數(shù)據(jù)等雄嚣。
此處應(yīng)用時(shí)可以借助一個(gè)叫:LightBlue的App來理解藍(lán)牙外設(shè)的服務(wù)及特征值。
最近做的一個(gè)藍(lán)牙項(xiàng)目中喘蟆,硬件工程師選擇的藍(lán)牙模塊有提供開發(fā)文檔缓升,文檔中有提供 服務(wù)值 及 讀取數(shù)據(jù) 和 寫數(shù)據(jù) 的特征值。按照文檔中提供的對(duì)應(yīng)的值填寫即可蕴轨。借助LightBlue也可以看到服務(wù)值和讀寫數(shù)據(jù)特征值港谊。具體值,參考步驟1中的三個(gè)宏定義橙弱。
理解不是很到位歧寺,請(qǐng)見諒燥狰。
*/
}
連接外部藍(lán)牙設(shè)備失敗調(diào)用此方法,可在此再次連接外設(shè)
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
//如何實(shí)現(xiàn)自動(dòng)斷線重連斜筐,就是在斷開的委托方法中龙致,執(zhí)行連接藍(lán)牙的方法 可以在此處重新調(diào)用連接藍(lán)牙方法
// JCLog(@"連接%@失敗--error:%@",peripheral.name,error);
[_myCentralManager connectPeripheral:_peripheral options:nil];//連接藍(lán)牙
}
7.發(fā)現(xiàn)藍(lán)牙外設(shè)服務(wù),調(diào)用此方法
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
if(error){
JCLog(@"外圍設(shè)備尋找服務(wù)過程中發(fā)生錯(cuò)誤顷链,錯(cuò)誤信息:%@",error.localizedDescription);
}
//遍歷查找到的服務(wù)
CBUUID *serviceUUID=[CBUUID UUIDWithString:kServiceUUID];
for (CBService *service in peripheral.services) {
if([service.UUID isEqual:serviceUUID]){
//外圍設(shè)備查找指定服務(wù)中的特征
[peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:kReadUUID],[CBUUID UUIDWithString:kWriteUUID]] forService:service];
}
}
}
8.尋找藍(lán)牙服務(wù)中的特性
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
if (error) {//報(bào)錯(cuò)直接返回退出
JCLog(@"didDiscoverCharacteristicsForService error : %@", [error localizedDescription]);
return;
}
for (CBCharacteristic *characteristic in service.characteristics)//遍歷服務(wù)中的所有特性
{
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kReadUUID]]){//找到收數(shù)據(jù)特性
[peripheral setNotifyValue:YES forCharacteristic:characteristic];//訂閱其特性(這個(gè)特性只有訂閱方式)
_readCharacteristic = characteristic;
}
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kWriteUUID]]) {//找到發(fā)數(shù)據(jù)特性
_writeCharacteristic = characteristic;
}
}
}
9.收到外設(shè)更新發(fā)送過來的數(shù)據(jù)
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
if (error) {
JCLog(@"更新特征值時(shí)發(fā)生錯(cuò)誤目代,錯(cuò)誤信息:%@",error.localizedDescription);
return;
}
NSString *value=[[NSString alloc]initWithData:characteristic.value encoding:NSUTF8StringEncoding];
JCLog(@"讀取到特征值:%@",value);//即收到的數(shù)據(jù)
}
10.發(fā)送數(shù)據(jù)到外設(shè)
-(void)sendString:(NSString *)string{
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
[_eripheral writeValue:data
forCharacteristic:_writeCharacteristic
type:CBCharacteristicWriteWithoutResponse];
}
/*======至此,藍(lán)牙收發(fā)數(shù)據(jù)的流程基本結(jié)束======*/
/*
注意點(diǎn):
1.發(fā)送到外設(shè)的數(shù)據(jù)最大為20字節(jié)
2.接收的數(shù)據(jù)也為20字節(jié)
3.MAC端藍(lán)牙調(diào)試助手推薦使用CoolTerm嗤练,相當(dāng)于windows中的串口調(diào)試助手
4.iPhone手機(jī)端調(diào)試榛了,推薦LightBlue
*/
/*
關(guān)于服務(wù)UUID,特征值UUID的解釋
1.此文介紹的藍(lán)牙開發(fā)是固定的服務(wù)UUID煞抬、固定的特征值UUID霜大。即已獲知項(xiàng)目中使用的外設(shè)藍(lán)牙模塊的服務(wù)UUID、特征值UUID革答,這兩個(gè)數(shù)據(jù)可以在硬件工程師那里拿到战坤,藍(lán)牙模塊文檔中一般會(huì)提及。如果沒有蝗碎,則使用上文中提到的調(diào)試工具LightBlue可以獲取得到湖笨。
2.最近開發(fā)項(xiàng)目中的服務(wù)UUID、特征值UUID都是使用LightBlue獲知蹦骑。
*/
如有錯(cuò)誤之處慈省,望看到此文的大神批評(píng)指正,謝謝眠菇!