美文网首页
iOS-蓝牙项目经验总结(上)

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

作者: HelloKing | 来源:发表于2018-10-15 14:54 被阅读15次

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

    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<NSString *,id> *)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<dataLength; 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<NSString *,id> *)advertisementData RSSI:(NSNumber*)RSSI 中的参数RSSI能解析出蓝牙信号。但是为节省系统资源,一般的做法是,一旦调用上述方法获取到相应的蓝牙设备并链接成功蓝牙后,就调用[self.centralManager stopScan]; 停止扫描。此时self.centralManager的isScaning的属性为false。此方法就不再调用。也就意味着,蓝牙设备信号,在发现蓝牙设备的时候,只能获取到一次。那么怎么才能做到事实获取信号呢?当然是在链接成功蓝牙后不要调用[self.centralManager stopScan]; 

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

    相关文章

      网友评论

          本文标题:iOS-蓝牙项目经验总结(上)

          本文链接:https://www.haomeiwen.com/subject/xyhoaftx.html