coreBlueTooth(续)

转载 2017年07月12日 10:23:39
概述
公司的项目是医疗类的项目,所以这段一直在和蓝牙打交道。我使用的是苹果原生的框架CoreBluetooth。在对接几个蓝牙设备的过程中,也遇到一些坑,下文我会一一列举。 git上有个库BabyBluetooth 基于原生CoreBluetooth框架进行了封装,使用起来也很方便,大家可以尝试一下。 那么我们开始吧!

正文
在了解下文内容之前,我已默认你已经了解一些基本概念:
什么是中心设备
什么是外围设备
什么是服务(service)
什么是特性(characteristic)
什么是订阅(notify)
什么是UUID
...
基本了解了以上一些概念,下面的内容将比较好理解。

需要注明,下面的UUID是我的蓝牙设备中的Service和Characteristic的UUID,要注意根据自己的蓝牙设备提供的Service和Characteristic的UUID来替换

// 蓝牙设备提供的服务的UUID
#define kCGMServiceTwoUUID @"0000FFF0-0000-1000-8000-00805F9B34FB"
// 蓝牙设备提供的写入特性
#define kCGMCharacteristicOneUUID @"0000FFF1-0000-1000-8000-00805F9B34FB"
// 蓝牙设备提供的notify特性
#define kCGMCharacteristicTwoUUID @"0000FFF2-0000-1000-8000-00805F9B34FB"

那么,先让我们了解下蓝牙交互流程中几个常用的回调。
中心设备CBCentralManager更新设备蓝牙状态的回调
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{ 
 switch (central.state) 
 case CBCentralManagerStatePoweredOn: 
  {
  // 扫描外围设备 
  [self.centeralManager scanForPeripheralsWithServices:nil options:nil]; 
 
 break;
 default:
 NSLog(@"设备蓝牙未开启"); 
 break; 
 }
}
中心设备已经发现外围设备回调

这里有几个问题值得注意:
1. 在ios中蓝牙广播信息中通常会包含以下4种类型的信息。ios的蓝牙通信协议中不接受其他类型的广播信息。因此需要注意的是,如果需要在扫描设备时,通过蓝牙设备的Mac地址来唯一辨别设备,那么需要与蓝牙设备的硬件工程师沟通好:将所需要的Mac地址放到一下几种类型的广播信息中。通常放到kCBAdvDataManufacturerData这个字段中。kCBAdvDataIsConnectable = 1;
kCBAdvDataLocalName = XXXXXX;
kCBAdvDataManufacturerData =XXXX;
kCBAdvDataTxPowerLevel = 0;
2. 设备的UUID(peripheral.identifier)是由两个设备的mac通过算法得到的,所以不同的手机连接相同的设备,它的UUID都是不同的,无法标识设备。
3. 苹果与蓝牙设备连接通信时,使用的并不是苹果蓝牙模块的Mac地址,使用的是苹果随机生成的十六进制码作为手机蓝牙的Mac与外围蓝牙设备进行交互。如果蓝牙设备与手机在一定时间内多次通信,那么使用的是首次连接时随机生成的十六进制码作为Mac地址,超过这个固定的时间段,手机会清空已随机生成的Mac地址,重新生成。也就是说外围设备是不能通过与苹果手机的交互时所获取的蓝牙Mac地址作为手机的唯一标识的。(这是在与写蓝牙设备的固件工程师联调时根据问题的现象推测的。至于苹果蓝牙通讯协议的底层是否确实完全像我所说的这样,希望了解的读者能提供帮助。在此先谢过。)

 - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
NSLog(@"advertisementData.kCBAdvDataManufacturerData = %@", advertisementData[@"kCBAdvDataManufacturerData"]); 
 _connectPeripheral = peripheral;
// [self.centeralManager connectPeripheral:peripheral options:nil]; 
 if ([advertisementData[@"kCBAdvDataLocalName"] hasPrefix:@"SN"]){
 NSLog(@"已搜索到设备");
 NSLog(@"peripheral.identifier = %@ peripheral.name = %@", peripheral.identifier, peripheral.name);
 [_delegate getAdvertisementData:advertisementData andPeripheral:peripheral];
 [_peripheralArray addObject:peripheral]; 
 }
}

中心设备设备连接成功回调
 - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
 // 设备停止扫描
 [self.centeralManager stopScan];
 peripheral.delegate = self; 
 dispatch_after(2, dispatch_get_main_queue(), ^{ 
 // 查找服务
 [_connectPeripheral discoverServices:@[[CBUUID UUIDWithString:kCGMServiceTwoUUID]]]; 
 });
}

中心设备设备连接失败回调
 - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
 [_operationDelegate failToConnect];
}

中心设备设备连接中断回调
 - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
 NSLog(@"连接断开 %@", [error localizedDescription]);
 [_operationDelegate disconnected];
}

外围设备(CBPeripheral)发现服务(service)回调
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
 if (error) 
{
// 输出错误信息 
 NSLog(@"discoverServices.error============ %@", [error localizedDescription]); 
 return;
 } 
 // 遍历设备提供的服务 
 for (CBService *service in peripheral.services) 
 NSLog(@"service.UUID = ------------- = %@", service.UUID.UUIDString);
 // 找到需要的服务,并获取该服务响应的特性 
 if([service.UUID isEqual:[CBUUID UUIDWithString:kCGMServiceTwoUUID]])
 { 
 [service.peripheral discoverCharacteristics:nil forService:service];
 NSLog(@"开始查找cgm的characteristic");
 } 
 }
}

外围设备发现特性(characteristic)回调 
 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
 if (error) { 
 // 输出错误信息 
 NSLog(@"discoverCharacteristics.error=========== %@", [error localizedDescription]);
 return;
 } 
 // 遍历服务中的所有特性 
 for (CBCharacteristic *characteristic in service.characteristics) 
 if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kCGMCharacteristicOneUUID]]) 
{
 // 设置读写的特性
 _readAndWriteCharacteristic = characteristic;
 } else if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kCGMCharacteristicTwoUUID]]) 
 // 设置需要订阅的特性 _notifyCharacteristic = characteristic; 
 [_connectPeripheral setNotifyValue:YES forCharacteristic:_notifyCharacteristic]; 
 }
}
}

外围设备数据更新回调, 可以在此回调方法中读取信息(无论是read的回调,还是notify(订阅)的回调都是此方法)
 - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{ 
 if (error) { 
 // 输出错误信息 
 NSLog(@"didupadteValueForCharacteristic error ============ %@", [error localizedDescription]); 
 return; 
 } 
 NSLog(@"value ============= %@", characteristic.value); 
 // 解析数据 
 NSData *data = characteristic.value; 
 // 将NSData转Byte数组 
 NSUInteger len = [data length]; 
 Byte *byteData = (Byte *)malloc(len);
 memcpy(byteData, [data bytes], len); 
 NSMutableArray *commandArray = [NSMutableArray arrayWithCapacity:0];
 // Byte数组转字符串
 for (int i = 0; i < len; i++) { 
 NSString *str = [NSString stringWithFormat:@"%02x", byteData[i]];
 [commandArray addObject:str]; 
 NSLog(@"byteData = %@", str); 
 } 
 // 输出数据 
 [_operationDelegate dataWithCharacteristic:commandArray];
 }

特性已写入外围设备的回调(如果写入类型为CBCharacteristicWriteWithResponse 回调此方法,如果写入类型为CBCharacteristicWriteWithoutResponse不回调此方法)
 - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{ 
 if (error) {
 NSLog(@"write.error=======%@",error.userInfo); 
 } /* When a write occurs, need to set off a re-read of the local CBCharacteristic to update its value */
 // 读数据 
 if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kCGMCharacteristicOneUUID]]) { 
 [self readCharacter]; 
 }
}

外围设备订阅特征值状态改变成功的回调需要注意的是这里是对kCGMCharacteristicOneUUID这个特性进行写入,这里之所以这样操作是因为我的蓝牙设备的蓝牙协议是这样定义的,所以这里不要照抄照搬,要按照你的蓝牙设备的通讯协议来确定,对哪一个特性进行read,对哪个特性进行write,以及对哪个特性进行设置Notify 

- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
 if (error) { 
 NSLog(@"error = %@", [error localizedDescription]);
 } 
 // 对特性kCGMCharacteristicTwoUUID设置notify(订阅),成功以后回
     if ([characteristic.UUID.UUIDString isEqualToString:kCGMCharacteristicTwoUUID] && characteristic.isNotifying) {
 // 写数据 回调-didWriteValueForCharacteristic
 NSLog(@"写数据到cgm设备的characteristic = %@", _readAndWriteCharacteristic.UUID.UUIDString); 
[_operationDelegate writeCharacteristic]; 
 }
}

另外,除了回调以外,还有几个点需要注意:
搜索外围设备
- (void)searchlinkDevice{ 
 // 实现代理 // 扫描设备//
 _centeralManager = [[CBCentralManager alloc] initWithDelegate:self// queue:nil]; 
 if(self.centeralManager.state == CBCentralManagerStatePoweredOff) { 
 // 蓝牙关闭的 
 } else if(self.centeralManager.state == CBCentralManagerStateUnsupported) { 
 // 设备不支持蓝牙
 } else if(self.centeralManager.state == CBCentralManagerStatePoweredOn || self.centeralManager.state == CBCentralManagerStateUnknown) {
 // 开启的话开始扫描蓝牙设备
 [self.centeralManager scanForPeripheralsWithServices:nil options:nil]; 
 double delayInSeconds = 20.0;
 // 扫描20s后未扫描到设备停止扫描 
 dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 
 dispatch_after(popTime, dispatch_get_main_queue(), ^(void) { [self stopScan]; });
 }
}

对某个特性(characteristic)写入数据
- (void)writeCharacter:(NSData *)data{
 NSLog(@" characteristic.uuid = %@ data ==== %@", _readAndWriteCharacteristic.UUID.UUIDString, data); 
if ([_readAndWriteCharacteristic.UUID isEqual:[CBUUID UUIDWithString:kCGMCharacteristicOneUUID]]) { 
 [_connectPeripheral writeValue:data forCharacteristic:_readAndWriteCharacteristic type:CBCharacteristicWriteWithResponse];
 } else { 
 [_connectPeripheral writeValue:data forCharacteristic:_readAndWriteCharacteristic type:CBCharacteristicWriteWithoutResponse];
 }
}

读数据
需要注意的是这里读取蓝牙信息 (但并不是在返回值中接收,要在
 - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;这个回调方法中接收)
 - (void)readCharacter{
 [_connectPeripheral readValueForCharacteristic:_readAndWriteCharacteristic];
}

另外完整的源码请到这里https://github.com/xuzhengquan/BlueToothDemo/查看,demo中提供了蓝牙操作的工具类,由于蓝牙通讯协议的不同,所以在UI上没有做更多的工作,只是提供了搜索设备时展示了一下外围设备信息,还请谅解。

链接:http://www.jianshu.com/p/3b404bd672a8

iOS之蓝牙开发—CoreBluetooth详解一

最近开始进行蓝牙模块的开发,下载一个名叫lightBlue的app,通过它可以扫描到周围开启的外部设别,并且可以进行连接,连接外部设备成功之后,就可以看到外部设别的相关信息,包含服务和特征的所有相关的...
  • wuzesong
  • wuzesong
  • 2016年03月18日 16:25
  • 2892

ios蓝牙框架CoreBluetooth使用

ios CoreBluetooth 蓝牙框架
  • u010745324
  • u010745324
  • 2016年11月06日 14:56
  • 509

继电器与续流二极管

转自:http://liuyunfeng484.blog.163.com/blog/static/6683171520127219531631/ 在电路中反向并联在继电器或电感线圈的两端,当电感...
  • yc550370460
  • yc550370460
  • 2013年01月21日 10:20
  • 1793

浅谈iOS中的蓝牙技术(二) -- CoreBluetooth

在上篇文章中我们提到了 iOS 开发中,使用GameKit 框架实现相同网络的 iOS 设备之间传输数据.但是 GameKit 框架在 iOS7 之后就过时了,那么本文将介绍另一种关于蓝牙的框架 Co...
  • qq_30513483
  • qq_30513483
  • 2016年04月28日 10:09
  • 3788

java--IO流-文件的续写

/* 文件续写 */ import java.io.*; //导入IO包 class FileWriterDemo3 { public static void main...
  • qiuxuewei2012
  • qiuxuewei2012
  • 2013年08月10日 10:49
  • 2264

C++续行符(反斜杠符号)

原文:http://blog.csdn.net/zhu2695/article/details/9152069 参考一: 由于最近好几次碰到反斜杠,不明白是什么意思,后来查了下...
  • tutuzhuz
  • tutuzhuz
  • 2015年01月09日 16:58
  • 2571

iOS coreBluetooth编程中需要注意的问题

iOS 设备作为中心设备(central device)时需要注意:(1)一定要对central Manager保持强引用,也就是说central Manager需要是一个全局变量不能是局部变量,否则...
  • ohyeahhhh
  • ohyeahhhh
  • 2016年08月10日 19:01
  • 2092

已知二叉树的前序和中序序列,构建二叉树并求后序序列,java实现。

已知二叉树的前序和中序序列,或者已知二叉树的后序和中序序列,是能够唯一确定一棵二叉树的。但是如果仅知道二叉树的前序和后序序列,一般是不能唯一确定一棵二叉树的,但是可以分析有多少种可能的二叉树,这个没有...
  • u010465615
  • u010465615
  • 2016年04月16日 15:17
  • 119

hdu1429胜利大逃亡(续)(状态压缩+bfs)

题目链接: 啊哈哈,点我点我 题意及思路 两个状态压缩+bfs的题,两个题其实是一样的,所以我讲一个。。。就选1429吧。。 最开始我以为跟普通的bfs一样,所以直接写了一个朴素的bfs,一跑,前两...
  • u014303647
  • u014303647
  • 2014年08月18日 13:23
  • 957

自己写的IOS 蓝牙连接demo 用的是coreBluetooth

服务器端 头文件 #import #import  @interface ViewController : UIViewController @property (stro...
  • w8561469
  • w8561469
  • 2015年06月18日 14:52
  • 1653
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:coreBlueTooth(续)
举报原因:
原因补充:

(最多只允许输入30个字)