iOS-蓝牙项目经验总结(上)

蓝牙开发中碰到的几个技术点:

0),蓝牙协议制定;  

1),蓝牙密钥配对;

2),获取蓝牙Mac地址;

3),实时获取蓝牙设备信号;

4),通过蓝牙升级硬件版本;

5),通过蓝牙上传文件;

6),封装蓝牙静态包;


蓝牙协议制定:

蓝牙封包格式依次为:包头(一个字节),指令码(一个字节),封包长度(一个字节),参数(n个字节),校验码(一个字节);

例如下图:

当然还有封包格式更简单的,只有包头,指令码,和参数组成;具体什么格式要找硬件开发人员定义,蓝牙以二进制的数据流,通过广播发送至app端, app在回调方中接收的数据为NSData类型。(接收数据处理:NSData -> byte ->NSString).

包头:是硬件返回指令包首个字节的内容,可以与硬件开发人员定义好。

指令码:是区分每个指令的内容,可以与硬件开发人员定义好。

长度:封包總長度(包含包頭、校驗碼),單位為byte。

参数:依指令碼不同而定。

校验码:Checksum , 封包中除了校驗碼以外的位元組數據總和,再除以256的餘數。

蓝牙密钥配对:

蓝牙配对分为LMP配对(PIN配对)和SSP配对,前者需要输入pin码进行蓝牙配对。后者不需要输入pin码。其中具体的原理参照如下链接:https://www.jianshu.com/p/683c287fee3e。

在这里,大家普遍踩过的坑,就是配对警告框不弹出的问题。解决办法:1),要和硬件开发人员确定蓝牙设备是否发送配对广播,这个可以让硬件开发人员确定,他们手里都有蓝牙厂商提供的相应的测试app。2),最容易忽略的一点,就是代码中在初始化蓝牙中心设备和搜索蓝牙设备的时候设置options参数为@{CBCentralManagerOptionShowPowerAlertKey:@YES}。{CBCentralManagerOptionShowPowerAlertKey:@(YES)} 允许弹出警告框。  具体代码如下:

        _centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:@{CBCentralManagerOptionShowPowerAlertKey:@(YES)}];

    [self.centralManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerOptionShowPowerAlertKey:@(YES)}];。

获取蓝牙Mac地址:

由于苹果手机的保密性,蓝牙设备通过广播携带的私有蓝牙信息会被屏蔽掉。不过还有些项目在链接蓝牙设备时,会用到蓝牙的Mac地址 蓝牙Mac地址。此时就需要获取蓝牙的Mac地址。解决办法如下:

1),不要让硬件开发人员把Mac地址写在广播字段中,应该以参数的形式添加到Advertising Packet 中(我向硬件开发人员请教了一下,官方语言:Added the mac address in Advertising Packet),传过来。iOS在 一下回调方法中解析advertisementData参数即可得到

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber*)RSSI 

解析代码,如下

     

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber*)RSSI 

{

        NSData* advertisementData = [advertisementData objectForKey:@"kCBAdvDataManufacturerData"]; //解析Mac地址, kCBAdvDataManufacturerData为advertisementData中的key值。其对应的value即为Mac地址。

        NSString *value = [self hexadecimalString:advertisementData];    //获取Mac地址

}   

-(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

//02x 表示两个位置 显示的16进制

 [hexString appendString:[NSString stringWithFormat:@"%02lx",(unsigned long)dataBuffer[i]]];  

}  

 result = [NSString stringWithString:hexString]; 

 if (result.length < 4) {        

    return @"0000"; 

   }

result = [result substringFromIndex:4];   

 return result; 

}

实时获取蓝牙设备信号:

此坑比较隐蔽,按正常蓝牙扫描链接的正常流程走,是不能实时获取蓝牙设备信号的,纵观苹果官方暴漏的蓝牙API中,只有方法 - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber*)RSSI 中的参数RSSI能解析出蓝牙信号。但是为节省系统资源,一般的做法是,一旦调用上述方法获取到相应的蓝牙设备并链接成功蓝牙后,就调用[self.centralManager stopScan]; 停止扫描。此时self.centralManager的isScaning的属性为false。此方法就不再调用。也就意味着,蓝牙设备信号,在发现蓝牙设备的时候,只能获取到一次。那么怎么才能做到事实获取信号呢?当然是在链接成功蓝牙后不要调用[self.centralManager stopScan]; 

方法 - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber*)RSSI就会一直回调,那么在此方法中解析出来你想要的蓝牙设备信号,展示在View上就OK了。

你可能感兴趣的:(iOS-蓝牙项目经验总结(上))