苹果在iOS 6系统之后开始支持蓝牙BLE 4.0,iPhone4s,iPod 5,iPad 3等之后的机型开始内嵌BLE4.0硬件,因此在开发前请先确认你的开发环境符合上述要求,并且苹果在BLE4.0之后,对外部的连接设备已经不再需要MFI认证了,当然你的外设肯定得要有蓝牙4.0模块。
BLE:(Bluetooth low energy)蓝牙4.0设备因为低耗电
一、主要角色:
Central: 中心设备,发起蓝牙连接的设备(一般指手机)
Peripheral: 外设,被蓝牙连接的设备(一般是运动手环/蓝牙模块)
Service:服务,每个设备会提供服务,一个设备有很多服务
Characteristic:特征,每个服务中包含很多个特征,这些特征的权限一般分为:读(read)/写(write)/通知(notice)几种,可以通过特征进行读写数据(重要角色)
Descriptor:描述者,每个特征可以对应一个或者多个描述者,用于描述特征的信息或者属性
<一般开发中用到特征读写数据就结束了,一般不会用到描述者>
<特征就是具体的键值对,每个特征中都有一个对应的特征值,特征的属性分为读(read)/写(write)/通知(notice)等>
<每个描述者都有一个对应的描述值>
二、简述蓝牙通讯的过程:
- 建立中心角色
- 扫描外设(Discover Peripheral)
- 连接外设(Connect Peripheral)
- 扫描外设中的服务和特征 (Discover Service and Characteristic)
4.1 获取外设中的server
4.2 获取外设的特征 和 特征值
4.3 获取特征中的描述者 和描述者的值 - 利用特征与外设做数据交互
- 订阅特征中的通知
- 断开连接
三、项目中的相关代码
一、在项目中导入<CoreBluetooth/CoreBluetooth.h>框架并在类中遵循两个协议
<CBCentralManagerDelegate,CBPeripheralDelegate>
二、初始化中心管理者对象(主线程):
- (CBCentralManager *)CentralManager
{
if (!_CentralManager) {
_CentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue() options:nil];
}
return _CentralManager;
}
三、触发初始化中心管理者代理:初始化成功后开始通过服务扫描外设
//创建完成CBCentralManager对象之后会回调的代理方法
- (void)centralManagerDidUpdateState:(CBCentralManager *)central;
{
if (central.state == CBCentralManagerStatePoweredOff) {
NSLog(@"系统蓝牙关闭了,请先打开蓝牙");
}if (central.state == CBCentralManagerStateUnauthorized) {
NSLog(@"系统蓝未被授权");
}if (central.state == CBCentralManagerStateUnknown) {
NSLog(@"系统蓝牙当前状态不明确");
}if (central.state == CBCentralManagerStateUnsupported) {
NSLog(@"系统蓝牙设备不支持");
}if (central.state == CBCentralManagerStatePoweredOn) {
//扫描外设
[_centralManager scanForPeripheralsWithServices:nil options:nil];//如果你将第一个参数设置为nil,Central Manager就会开始寻找所有的服务。
}
}
四、扫描到外设,触发代理方法,根据外设name属性连接相应外设
//执行扫描的动作之后,如果扫描到外设了,就会自动回调下面的协议方法了
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI;{
//根据名字有选择性地连接蓝牙设备
if([peripheral.name isEqualToString:PERIPHERAL_NAME]){
_myPeripheral = peripheral;
_myPeripheral.delegate = self;
//连接外设
[_centralManager connectPeripheral:_myPeripheral options:nil];
}
}
五、连接外设有三种不同情况的回调,只有成功连接到指定外设再开始进行下一步:停止扫描其他的外设,一次性读出外设的所有服务
//如果连接成功,就会回调下面的协议方法了
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;{
//停止中心管理设备的扫描动作,要不然在你和已经连接好的外设进行数据沟通时,如果又有一个外设进行广播且符合你的连接条件,那么你的iOS设备也会去连接这个设备(因为iOS BLE4.0是支持一对多连接的),导致数据的混乱。
[_centralManager stopScan];
//一次性读出外设的所有服务
[_myPeripheral discoverServices:nil];
}
//掉线
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
NSLog(@"掉线");
}
//连接外设失败
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;
{
NSLog(@"连接外设失败");
}
六、读取外设服务回调,遍历发现服务
//一旦我们读取到外设的相关服务UUID就会回调下面的方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error;
{
//到这里,说明你上面调用的 [_peripheral discoverServices:nil]; 方法起效果了,我们接着来找找特征值UUID
NSLog(@"发现服务");
for (CBService *s in [peripheral services]) {
[peripheral discoverCharacteristics:nil forService:s];
}
}
七、在发现服务的回调中,获取特征值,根据特征值UUID保存对应的特征值Characteristic
//如果我们成功读取某个特征值UUID,就会回调下面的方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error;{
for(int i=0; i < service.characteristics.count; i++) {
CBCharacteristic *c = [service.characteristics objectAtIndex:i];
NSLog(@"特征 UUID: %@ (%@)", c.UUID.data, c.UUID);
if ([[c UUID] isEqual:[CBUUID UUIDWithString:@"0000fff6-0000-1000-8000-00805f9b34fb"]]){
// 根据特征属性来判断特征值
if(c.properties & CBCharacteristicPropertyWrite && c.properties & CBCharacteristicPropertyRead){
_lockUnlockCharacteristic = c;
}
NSLog(@“找到可读写特征lockUnlockCharacteristic : %@", c);
}
//读取蓝牙4.0设备电量的特征值、订阅这个特征值以监听电量变化
if ([[c UUID] isEqual:[CBUUID UUIDWithString:@"0000fff4-0000-1000-8000-00805f9b34fb"]]){
self.readPowerCharacteristic = c;
// 获取特征对应的描述 会回调didUpdateValueForDescriptor
// [peripheral discoverDescriptorsForCharacteristic:cha];
// 获取特征的值 会回调didUpdateValueForCharacteristic
// [peripheral readValueForCharacteristic:cha];
NSLog(@"找到可读特征readPowerCharacteristic : %@", c);
[self.myPeripheral setNotifyValue:YES forCharacteristic:_readPowerCharacteristic];
}
}
}
八、发送数据
#pragma 发送数据
-(void)sendDataToBLE:(NSString*)data{
NSData* myData = [data dataUsingEncoding:NSUTF8StringEncoding];
if(nil != self.lockUnlockCharacteristic){
[self.myPeripheral writeValue:myData forCharacteristic:self.lockUnlockCharacteristic type:CBCharacteristicWriteWithResponse];
}
}
九、监听发送回调、通知回调
//向peripheral中写入数据后的回调函数
-(void)peripheral:(CBPeripheral*)peripheral didWriteValueForCharacteristic:(CBCharacteristic*)characteristic error:(NSError *)error{
NSLog(@"write value success(写入成功) : %@", characteristic);
}
//获取外设发来的数据,不论是read和notify,获取数据都从这个方法中读取
-(void)peripheral:(CBPeripheral*)peripheral didUpdateValueForCharacteristic:(CBCharacteristic*)characteristic error:(NSError *)error{
[peripheral readRSSI];
NSNumber* rssi = [peripheral RSSI];
//读取BLE4.0设备的电量
if([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"0000fff4-0000-1000-8000-00805f9b34fb"]]){
NSData* data = characteristic.value;
NSString* value = [self hexadecimalString:data];
NSLog(@"characteristic(读取到的) : %@, data : %@, value : %@", characteristic, data, value);
// 在此处读取描述即可
for (CBDescriptor *descriptor in characteristic.descriptors) {
self.mDescriptor = descriptor;
NSLog(@"发现外设的特征descriptor==%@",descriptor);
} }
}
十、根据业务去求,封装对应的数据格式转换的方法
//将传入的NSData类型转换成NSString并返回
}
- (NSString*)hexadecimalString:(NSData *)data{
NSString* result;
const unsigned char* dataBuffer = (const unsigned char*)[data bytes];
if(!dataBuffer){
return nil;
}
NSUInteger dataLength = [data length];
NSMutableString* hexString = [NSMutableString stringWithCapacity:(dataLength * 2)];
for(int i = 0; i < dataLength; i++){
[hexString appendString:[NSString stringWithFormat:@"%02lx", (unsigned long)dataBuffer[i]]];
}
result = [NSString stringWithString:hexString];
return result;
}
//将传入的NSString类型转换成ASCII码并返回
- (NSData*)dataWithString:(NSString *)string{
unsigned char *bytes = (unsigned char *)[string UTF8String];
NSInteger len = string.length;
return [NSData dataWithBytes:bytes length:len];
}
Snip20180315_2.png
参考博客:
http://blog.csdn.net/Alexander_Wei/article/details/69664308
http://blog.csdn.net/qq_30379689/article/details/61413950
网友评论