侧边栏壁纸
博主头像
钱学超博主等级

火星人,1万小时法则的忠实拥趸。技术宅,象棋和羽毛球爱好者,马拉松PB成绩:4小时零8分。坚持认为算法是计算机的灵魂。喜欢解决问题,喜欢手工,喜欢与朋友们聊天喝酒吹牛X。

  • 累计撰写 83 篇文章
  • 累计创建 464 个标签
  • 累计收到 88 条评论
标签搜索

目 录CONTENT

文章目录

flutter开发蓝牙设备连接App的坑

钱学超
2023-06-16 / 0 评论 / 0 点赞 / 708 阅读 / 1,079 字 / 正在检测是否收录...
广告 广告
  1. 如果你刚要开始做一个连接蓝牙设备的App,你就看到了这篇文章,恭喜你,节省了至少一天的时间。

  2. 如果你遇到了IOS和安卓连接蓝牙设备不一样的问题,恭喜你找对地方了。

  3. 本文阐述了一下ios和安卓连接蓝牙遇到的问题,主要是设备id的获取方式的问题。其他问题请绕路。

  4. 坑:安卓设备获取蓝牙设备的device id,得到的是一个mac地址,通过蓝牙扫描协议可以查看到的。而IOS为了安全起见,隐藏了蓝牙设备的mac地址,device id返回了一个uuid,并且不同的扫描批次,拿到的uuid是不一致的。

  5. deviceId,天生就具有迷惑性,我们理所当然的看到他,就认为这是设备的唯一ID,无论安卓还是IOS都是一样的,这就错了。ios的deviceid,只是这次扫描到了比如100个蓝牙设备,用来区分这100个设备的。你可以通过他指定我要连接哪一个,但是无法在系统中用作唯一连接标识符。

  6. 这是不合理的,尤其是在工业上,比如我用三个蓝牙测振仪,放在一台机器的三个部位上。如果要进行连接,你扫描到的是完全一模一样的三个设备。UUID又是变化的,我tm怎么区分哪个是哪个?

  7. 当然,可以使用rssi来进行判断。我通过实验发现,当手机贴近蓝牙设备时,就是紧紧贴在一起,rssi一般可以达到-30甚至更大(-20),稍远一点的距离,rssi一般是达到60-100。我们可以根据实际手机贴近蓝牙设备时,rssi变化最趋近实际情况的那个设备,来判定是否是我们要连接的设备。

  8. 这是一个相对靠谱,但是需要连接时进行移动操作(贴近蓝牙设备)的,如果实际情况不允许这么干,那就无法做到(比如蓝牙设备在玻璃盒子里,或者距离较远)。

  9. 回头仔细观察扫描结果,发现有一个advertisementData字段,查看相关资料,发现这里边存放有一些厂商的特别信息。

  10. 比如我连接的测振仪,就把mac地址,以byte数组的格式放到 r.advertisementData?.manufacturerData里边了。这是一个map,key有点没看懂,直接用values就可以了。(解完发现这个byte数组转成16进制字符串,用:分隔开,比安卓获取的deviceId多几位)具体干啥的不清楚,但是完整的mac地址是包含在内的。

  11. 这个办法行,但是也有点问题,有些设备,根本就没有manufactureData字段,或者内容是空的。那就不行了,只能通过rssi的变化趋势去判定哪个设备是哪一个了。因为根据列表选择,你也无法判断一大堆名字都叫nxf54的设备哪个对应实际的哪一个。

  12. 上代码

if (Platform.isAndroid) {
          device = scanResults.firstWhere((r) {
            return item?.deviceCheckItem?.checkConfig?.seismic?.sn == r.device.id?.toString();
          }, orElse: () {
            return ScanResult();
          })?.device;
        } else {
          scanResults.sort((a, b) => b.rssi - a.rssi);
          for (var r in scanResults) {
            debugPrint(r.rssi.toString());
            if (r.advertisementData?.manufacturerData?.values?.isEmpty ?? false) {
              continue;
            }
            var listInt = r.advertisementData?.manufacturerData?.values?.first ?? <int>[];
            var address = "";
            for (var x in listInt) {
              var hex = '${x.toRadixString(16)}'.padLeft(2, '0');
              address = "${address.isEmpty ? '' : '$address:'}$hex";
            }
            address = address.toLowerCase();
            if (address.endsWith(item?.deviceCheckItem?.checkConfig?.seismic?.sn?.toLowerCase() ?? '===')) {
              device = r.device;
              debugPrint("IOS 连接到精确设备:${device.name}(${device.id})");
              break;
            }
          }
          // 要是还是找不到,就按照最近的一个蓝牙设备,名称是nRF52连接即可。
          if (device == null) {
            for (var r in scanResults) {
              if (r.rssi >= -40 && r.device.name.isNotEmpty && r.device.name == 'nRF52') {
                device = r.device;
                debugPrint("IOS 连接到最近的一个设备:${device.name}(${device.id})");
                break;
              }
            }
          }
          // IOS
        }
0

评论区