flutter_blue 蓝牙插件实战及那些坑

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

本人掘金文章

坑一: 安卓端引入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创建的 flutterswift 语言, 而ios要的是 objc

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

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

需求简介:
  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();
});
}
有问题欢迎留言

免责声明:文章转载自《flutter_blue 蓝牙插件实战及那些坑》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Struts 2.x仍然明显落后于时代。 Struts 2.x这一类老牌Web MVC开发框架仅能用于开发瘦客户端应用,无法用来开发对于交互体验要求更高的应用。记一次线上OOM问题分析与解决下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

MyEclipse的多模块Maven web(ssm框架整合)

  Maven的多模块可以让项目结构更明确,提高功能的内聚,降低项目的耦合度,真正的体现出分层这一概念。   我们在操作中,要明白为什么这样做,要了解到更深的层次,这样,我们就不限于个别软件了。   话不多说,直入主题:   如果对Maven还不够熟悉,请看该博客:Maven基础   整个项目做完之后的结构是这样的:         在开始之前我放出这两张...

zjfc1076 online judge 对多行字符串输入做处理

题目描述 Ignatius is building an Online Judge, now he has worked out all the problems except the Judge System. The system has to read data from correct output file and user's result...

python——pandas初体验

一、pandas简介 Pandas是面向数据分析场景设计的Python开源软件工具包,其名字来自英文词组panel data,作为经济界的术语指多维结构化的数据集。从命名来看,Pandas特别适合处理序列数据、表格数据等具有良好结构的数据。在软件使用上,由于Pandsa是基于BSD开源软件许可证发布的,能够很方便地在学习、办公和工业应用等场合使用。 二、p...

Ubuntu下设置开机自动挂载硬盘

Ubuntu下设置开机自动挂载硬盘       我们在linux中常常用mount命令把硬盘分区或者光盘挂载到文件系统中。/etc/fstab就是在开机引导的时候自动挂载到linux的文件系统。   如果给计算机配了一块新磁盘,已经分区,格式化,挂载,但当计算机重启后,然后我们想让计算机启动时自动挂载,方法就是修改文件 /etc/fstab,...

springboot使用xml配置dubbo读取yml占位符

约定优于配置是springboot简化配置的思路,其中它提供的自动配置、基于注解配置为我们搭建项目框架带来了很大的便利。 使用springboot的项目跟仅使用spring的项目相比,少了很多xml配置文件,基于自动配置或者使用注解和配置类就可完成大多数配置。 springboot + dubbo搭建微服务工程:(springboot版本2.0.4.REL...

web app会遇到那些问题

Html在移动设备上显示会遇到那些问题:    1. 限制HTTP请求:3G信号传输费用昂贵,可能的话要限制图像显示。    2. 不同的屏幕尺寸:移动设备屏幕尺寸宽度一般来说从320到480不等,但是也会因为设备的不同有很大差异   3. 禁用悬停:触摸屏不能很好地支持hover,所以做菜单时最好不要使用下拉菜单等形式。   4. 跨浏览器支持。    ...