flutter_blue 蓝牙插件实战及那些坑

项目场景: 地下车库无网路的情况下需要使用蓝牙对小区门禁进行开门

本人掘金文章

坑一: 安卓端引入flutter_blue运行项目报错

1. 原因: 安卓sdk版本需要28以上

2. 解决: android/build.gradle 下修改 compileSdkVersion  targetSdkVersion 为 28;  minSdkVersion 修改为19

android {
.............
    compileSdkVersion 28
.............
    defaultConfig {
        minSdkVersion 19
        targetSdkVersion 28
    }
.............
}

坑二: ios引入flutter_blue运行项目报错

1. 原因: windows 创建的 flutter swift 语言, 而ios要的是 objc

2. 解决: 新建空目录使用 flutter create -i objc my-flutter-app 创建新项目, 在把原项目下lib文件夹下的所有文件替换新创建的lib文件夹, 这就可以了;Android\ios 端都没问题

附上实际项目的源码; 其他的坑暂时就没想起来了,反正坑蛮多,初期运行时也是控制台各种报错

需求简介:
  1. 执行完一次蓝牙开门之后,就断开连接蓝牙,以降低手机耗能;
  2. 20s扫码一次蓝牙,扫描时长为10s,以便根据距离搜索新的及强度高的蓝牙设备
  3. 初始化项目即执行一次蓝牙扫描
import ‘package:flutter_blue/flutter_blue.dart‘;
FlutterBlue flutterBlue = FlutterBlue.instance;
# // 蓝牙开门
void _blueOpenDoor (Map list) async {
var isFirstScan = true;
var isConnect = false;
_delayed?.cancel();
# // 自定义loading
cancel = BotToast.showCustomLoading(
  ignoreContentClick: true,
  toastBuilder: (cancelFunc) {
    return Loading();
  }
);
blueList.forEach((scanResult) async {
  # // if (scanResult.device.name == ‘201901012212‘) {
  if (scanResult.device.name == list["macAddress"]) {
    print(‘蓝牙设备门禁正在连接~~~~~~~~~‘);
    await scanResult.device.disconnect();
    await scanResult.device.connect();
    isConnect = true;
    print(‘蓝牙设备门禁连接成功~~~~~~~~~‘);
    # // List<BluetoothDevice> connectedDevices = await flutterBlue.connectedDevices;
    // if(connectedDevices.contains(scanResult.device)) {
    //   // TO DO
    // }
    List<BluetoothService> services = await scanResult.device.discoverServices();
    # //遍历蓝牙设备对列表
    services.forEach((service) async {
      if (service.uuid.toString().toUpperCase().substring(4, 8) == ‘FFF0‘) {
        var characteristics = service.characteristics;
        for(BluetoothCharacteristic c in characteristics) {
          if (c.uuid.toString().toUpperCase().substring(4, 8) == ‘FFF1‘) {
            # // 开门指令
            print(‘蓝牙设备门禁服务匹配成功~~~~~~~~~‘);
            await c.write([0x30, 0x10, 0x02, 0x03 ...........]);
            print(‘蓝牙设备门禁指令发送成功~~~~~~~~~‘);
            # // 开门声音
            cancel();
            _delayed?.cancel();
            showOpenDoorDialog(1, list[‘doorControlName‘]);
            await _audioPlayer.play("https://qinlin-resource.oss-cn-zhangjiakou.aliyuncs.com/wechat/opendoor.mp3");
            await scanResult.device.disconnect();
          }
           # // 监听门禁返回 并断开连接
           if (c.uuid.toString().toUpperCase().substring(4, 8) == ‘FFF2‘) {
             # // List<int> value = await c.read();
             # // print(‘88888888888888888888888$value‘);
             await c.setNotifyValue(true);
             notifySubscription = c.value.listen((value) async {
               print(‘88888888888888888888888$value‘);
               cancel();
               await scanResult.device.disconnect();
               notifySubscription.cancel();
             });
           }
        }
      }
    });
    # // 获取设备连接状态
    stateSubscription = scanResult.device.state.listen((s) async {
      print(‘连接状态连接状态$s‘);
      switch (s) {
        # // 蓝牙连接成功
        case BluetoothDeviceState.connected:
          isFirstScan = true;
          break;
        case BluetoothDeviceState.disconnected:
          if (!isFirstScan){
            cancel();
            _delayed?.cancel();
            print(‘蓝牙设备门禁连接失败~~~~~~~~~‘);
            BotToast.showText(
              text: ‘蓝牙设备连接失败,请稍后再试‘,
              align: Alignment(0, 0.1),
              onlyOne: true,
              duration: Duration(milliseconds: 2000),
              contentPadding: const EdgeInsets.all(15.0),
            );
          }
          break;
        default:
          cancel();
          _delayed?.cancel();
          print(‘蓝牙设备门禁连接失败~~~~~~~~~‘);
          BotToast.showText(
            text: ‘蓝牙设备连接失败,请稍后再试‘,
            align: Alignment(0, 0.1),
            onlyOne: true,
            duration: Duration(milliseconds: 2000),
            contentPadding: const EdgeInsets.all(15.0),
          );
          break;
      }
    });
  }
});
_delayed = Timer.periodic(new Duration(seconds: 15), (timer) {
  cancel();
  if (!isConnect) {
    BotToast.showText(
      text: ‘该门禁蓝牙信号较弱,请稍后再试‘,
      align: Alignment(0, 0.1),
      onlyOne: true,
      duration: Duration(milliseconds: 2000),
      contentPadding: const EdgeInsets.all(15.0),
    );
  }
  _delayed?.cancel();
});

}
# // 15s 定时扫描蓝牙
Future<dynamic> _scanBlue () async {
flutterBlue.state.listen((s) {
  if (s == BluetoothState.on) {
    setState(() {
      _isOpenBlue = true;
    });
    FlutterBlue.instance.stopScan();
    # // 立即执行一次
    _initScan();
    _timer = Timer.periodic(new Duration(seconds: 20), (timer) {
      setState(() {
        blueList = [];
      });
      scanSubscription = flutterBlue.scan().listen((scanResult) async {
        if (!blueList.contains(scanResult)) {
          setState(() {
            blueList.add(scanResult);
          });
        }
      });
      Future.delayed(Duration(seconds: 10), () {
        FlutterBlue.instance.stopScan();
        scanSubscription?.cancel();
      });
    });
  } else {
    _timer?.cancel();
    if (!_isOpenBlue) {
      final snackBar = new SnackBar(
        content: new Text(‘如需要蓝牙开门,请先前往手机设置开启蓝牙‘),
        backgroundColor: Colors.red,
        duration: Duration(seconds: 3),
        action: SnackBarAction(
          textColor: Colors.white,
          label: ‘关闭‘,
          onPressed: () {},
        ),
      );
      _scaffoldkey.currentState.showSnackBar(snackBar);
    }
  }
});
}
# // 初始执行扫描
void _initScan () {
setState(() {
  blueList = [];
});
scanSubscription = flutterBlue.scan().listen((scanResult) async {
  if (!blueList.contains(scanResult)) {
    setState(() {
      blueList.add(scanResult);
    });
  }
});
Future.delayed(Duration(seconds: 10), () {
  FlutterBlue.instance.stopScan();
  scanSubscription?.cancel();
});
}
有问题欢迎留言

原文地址:https://www.cnblogs.com/ljx20180807/p/12200503.html

时间: 2024-11-12 06:11:35

flutter_blue 蓝牙插件实战及那些坑的相关文章

360插件化RePlugin踩坑

点击图片购书 1.什么是RePlugin? 在Android开发领域,有关插件化的讨论一直热度不减.目前市面上的插件化方案虽然很多,但多数只能实现某些功能的插件化,距离开发者的预期尚有相当差距.对此,在近期GMTC全球移动技术大会上,360手机卫士主程序架构负责人张炅轩宣布,360的插件化框架RePlugin已经可以实现"全面插件化",同时具有出色的稳定性和灵活性,可适用于各种类型的应用上."RePlugin预计7月份开源,这将是我们献给安卓世界最好的礼物."360

Ladon插件实战 Weblogic CVE-2018-2894

前言 使用Exp生成器生成Ladon插件实战,Weblogic CVE-2018-2894漏洞检测 漏洞扫描 Weblogic CVE-2018-2894 github上有一份weblogic一键检测脚本,发现存在漏洞误报 看了下代码竟只是判断页面非404,对于返回403,500等误报 还不如写成200,虽然同样不靠谱,于是Ladon添加此POC检测 误报的POC检测脚本 存在漏洞的页面特征 EXP生成器生成POC 使用EXP生成器可简单检测,至少判断页面特征比单纯检测状态更好吧 POC测试 L

填平新版本Xcode安装插件不成功的坑

一般情况下,安装xcode不成功现象基本上都出现在更新xcode或者重装之后出现的情况,下面原理性德东西,我就不赘述了,度娘上很容易看到,通过这段只是希望大家花费尽量少得时间将xcode插件安装成功. 首先,一般情况下,下载完插件之后,用Xcode直接运行Xcode.xcodeproj文件即可(注意:多运行几次),然后彻底退出xcode,一般情况下,会出现一个提示框,一定要勾选LoadBundel(见图1);一般程序运行完成之后在路径~/Library/Application Support/D

关于codeMirror插件使用的一个坑

codeMirror插件可以做语法高亮渲染,但它操作过程是这样的:先从 textarea中读取值放到codemirror动态生成的div中,根据textarea中的换行个数确定行数,根据正则表达来高亮语法.这就有个问 题,当你在页面上对语法做出修改提交表单时,其实只是在codemirror上的动态div上做出修改,当form表单提交时,原来textarea值并 没有变化. 所以,解决办法如下 1.需要在表单提交之前将textarea渲染的editor对象的值给读取出来,反写到textarea上去

elasticsearch-head插件安装的一些坑!es6.5.4版本

折腾了一晚上,总算成功了!,大部分坑都记录了下来,版本升级太快真实个大坑,每个版本都不一样,学的心累!! 这坑太多了!主要就是以下几点最主要的: 因为我这里只使用hear安装,不使用哪个打包工具,所以比较麻烦 首先要安装git和nodejs,新版本最好,其次需要开放9100端口 一  : nodejs配置淘宝镜像,不然慢的会卡死 二  : 如果卡在哪个包,可以停止,先npm install 这个包再安装 三  : 配置修改,细心一点就好: vim elasticsearch-head/Grunt

vue插件ele使用小坑

1.ele-table组件中selection如何默认选中 使用官网提供的api-->>Table Methods中的toggleRowSelection,关于这个api基本介绍就不说了. 在vue中使用方式:建议在computed中使用,监听table(ref="table",:data="data")中绑定的数据data变化情况,通过相关条件判定table中的row是否被勾选,代码如下: computed:{ listenData(){ for(va

Unity3D-RPG项目实战(1):引擎特殊目录

前言 从8月份开始,下定决心正式开始学习Unit3D啦!虽然自己写过两代端游引擎,被应用的项目也超过10个,Unreal Engine也搞过几年,不过做手游,哥确实还是个新手.Unity3D这个引擎我蛮喜欢的,乍看之下,不由得惊叹,这不就是我一直想搞的那套引擎嘛:整合的游戏开发工具,上层使用C#开发游戏逻辑...要是再支持LUA就好了.:) 开始使用一个新的引擎,要学的东西太多了,所以打算写这一系列笔记,一来记录.分享,二来请Unity3D的高手指点. 要用Unity3D做项目,首先困扰我的就是

网站移动版本开发踩坑实录一

最近公司项目需要开始做wap版本开发,虽然在上一家公司也有做过类似的工作,由于当时公司产品没有严格要求适配各个移动设备,也并没有很多动作效果和图片自适应这类的效果,相对来说体系没有那么成熟,更多是在wap版本上可以用就ok了(其实更多的工作集中在功能和cssser身上,交互效果没有那么强,唯一做的好玩一点的工作是菜单滑动.图片缩放[未被上线过]),因此基本上没有在移动端踩各种坑:说了这么多上一家公司的wap版本,下面开始讲讲现在做的项目让我在wap版本上踩的各种坑开始说起.   第一坑:技术选型

《锋利的jQuery》插件的使用和写法

jQuery插件的种类 1.封装对象方法 这种插件是将对象方法封装起来,用于对通过选择器获取的jQuery对象进行操作,是最常见的一种插件.此类插件可以发挥出jQuery选择器的强大优势,有相当一部分的jQuery的方法,都是在jQuery脚本库内部通过这种形式“插”在内核上的,例如parent()方法,appendTo()方法等. 2.封装全局函数 可以将独立的函数加到jQuery命名空间下.如常用的jQuery.ajax()方法.去首尾空格的jQuery.trim()方法,都是jQuery内