Flutter:BLE蓝牙开发

这篇具有很好参考价值的文章主要介绍了Flutter:BLE蓝牙开发。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

说明:

使用flutter_blue_plus插件实现低功耗蓝牙开发。

一、添加蓝牙权限:

1.Android网络权限(工程/android/app/src/main/AndroidManifest.xml):

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

2.iOS蓝牙权限(工程/ios/Runner/Info.plist):

<dict>
    ...
    <key>NSBluetoothAlwaysUsageDescription</key>
    <string>Need BLE permission</string>
    <key>NSBluetoothPeripheralUsageDescription</key>
    <string>Need BLE permission</string>
    <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
    <string>Need Location permission</string>
    <key>NSLocationAlwaysUsageDescription</key>
    <string>Need Location permission</string>
    <key>NSLocationWhenInUseUsageDescription</key>
    <string>Need Location permission</string>
</dict>

二、实现扫描/连接/接收BLE设备数据:

1.添加flutter_blue_plus插件依赖,在pubspec.yaml中:

dependencies:
  flutter_blue_plus: ^1.3.1     #蓝牙插件

2.实现BLE蓝牙设备扫描:

(1)蓝牙扫描类:

class ScanDevice {
  static const int SCAN_TIMEOUT = 10000;
  final String NAME_PREFIX = "T";
  final String NAME_PREFIX_2 = "HLW";
  final FlutterBluePlus _flutterBlue = FlutterBluePlus.instance; //蓝牙API
  final ScanCallback _callback; //回调接口
  var _isScanning = false;
  late Timer? _timer = null;
  ScanDevice(this._callback);
  //开始扫描
  void startScan({int timeout = SCAN_TIMEOUT}) {
    log("1.开始扫描设备 >>>>>>");
    if (_isScanning) return;
    _isScanning = true;
    _flutterBlue.scanResults.listen((results) {
      for (ScanResult item in results) {
        _handlerScanResult(item);
      }
    });
    _flutterBlue?.startScan(timeout: Duration(seconds: timeout));
    startTimer();
  }
  //N秒后停止扫描, 并回调通知外部
  void startTimer(){
    cancelTimer();
    _timer = Timer(Duration(milliseconds: SCAN_TIMEOUT), () {
      stopScan(); //停止扫描
      _callback.onStop(); //回调通知外部
    });
  }
  void cancelTimer(){
    _timer?.cancel();
    _timer = null;
  }
  //是否扫描中
  bool isScan() {
    return _isScanning;
  }
  //停止扫描
  void stopScan() {
    log("停止扫描设备 >>>>>>");
    cancelTimer();
    if (!_isScanning) return;
    _isScanning = false;
    _flutterBlue.stopScan();
  }
  //处理扫描结果
  void _handlerScanResult(ScanResult result) {
    if (!result.device.name.startsWith(NAME_PREFIX) && !result.device.name.startsWith(NAME_PREFIX_2)) return; //过滤掉非本公司的蓝牙设备
    log('扫到设备, name: ${result.device.name}');
    if (result.device.name.startsWith(NAME_PREFIX_2)) { //针对定制过的蓝牙设备,需要从广播中获取真正的设备名称
      var realName = getRealName(result);  //从广播中获取真实的设备名称
      if (realName != null && realName.startsWith("T")){
        //...
      }
      _callback.onFind(DeviceBean(result.device)); //回调到外部
      return;
    }
    _callback.onFind(DeviceBean(result.device)); //回调到外部
  }
}

(2)蓝牙扫描回调接口:

typedef OnFind = void Function(DeviceBean device);
typedef OnStop = void Function();
class ScanCallback {
  ScanCallback ({required this.onFind, required this.onStop});
  OnFind onFind;
  OnStop onStop;
}

(3)自定义实体类:

class DeviceBean {
  BluetoothDevice device; //设备
  DeviceBean(this.device);
}

3.实现连接设备/接收数据:

(1)连接设备/接收数据管理类:

class ConnectManager {
  final Guid SET_MODE_SERVICE_UUID = Guid("0000180f-0000-1000-8000-00805f9b34fb");           //设置模式-服务UUID
  final Guid SET_MODE_CHARACTERISTIC_UUID = Guid("00002a19-0000-1000-8000-00805f9b34fb");    //设置模式-特征值UUID
  final Guid SET_MODE_DESCRIPTOR_UUID = Guid("00002902-0000-1000-8000-00805f9b34fb");        //设置模式-特征值描述UUID(固定不变)
  final Guid WRITE_DATA_SERVICE_UUID = Guid("01ff0100-ba5e-f4ee-5ca1-eb1e5e4b1ce1");         //写数据-服务UUID
  final Guid WRITE_DATA_CHARACTERISTIC_UUID = Guid("01ff0101-ba5e-f4ee-5ca1-eb1e5e4b1ce1");  //写数据-特征值UUID
  final List<int> ENABLE_NOTIFICATION_VALUE = [0x01, 0x00];  //启用Notification模式
  final List<int> DISABLE_NOTIFICATION_VALUE = [0x00, 0x00]; //停用Notification模式
  final List<int> ENABLE_INDICATION_VALUE = [0x02, 0x00];    //启用Indication模式
  static const int CON_TIMEOUT = 10000;
  final GattCallback _gattCallback;
  late BluetoothCharacteristic? _writeCharacteristic = null;
  late ScanDevice? _scanDevice = null;
  late DeviceBean? _device = null;
  bool isConnecting = false;
  ConnectManager(this._gattCallback);
  //1.扫描
  Future<void> start(String deviceName, {int timeout = ScanDevice.SCAN_TIMEOUT}) async {
    if (_scanDevice == null) {
      _scanDevice = ScanDevice(ScanCallback(
          onFind: (DeviceBean device) { //扫描到设备
            if(isConnecting) {
              _scanDevice?.stopScan();  //停止扫描
              return;
            }
            if(device.device.name == deviceName){
              this._device = device;
              _scanDevice?.stopScan();  //停止扫描
              connect(device.device); //转 - 2.连接
            }
          },
          onStop: () { //停止扫描
            if(this._device == null){
              log("没找到设备 >>>>>>");
              _gattCallback.onDeviceNotFind();  //没扫描到设备时, 回调外部
            }
          }
      ));
    }
    _scanDevice?.startScan(timeout: timeout);
    isConnecting = false;
  }
  //2.连接
  Future<void> connect(BluetoothDevice device) async {
    isConnecting = true;
    log("2.开始连接 >>>>>>name: ${device.name}");
    await device.connect(timeout: Duration(milliseconds: CON_TIMEOUT), autoConnect: false);
    log("连接成功 >>>>>>name: ${device.name}");
    _discoverServices(device);
  }
  //3.发现服务
  Future<void> _discoverServices(BluetoothDevice device) async {
    log("3.开始发现服务 >>>>>>name: ${device.name}");
    List<BluetoothService> services = await device.discoverServices();
    log("发现服务成功 >>>>>>name: ${device.name}");
    _handlerServices(device, services);  //遍历服务列表,找出指定服务
    isConnecting = false;
  }
  //3.1遍历服务列表,找出指定服务
  void _handlerServices(BluetoothDevice device, List<BluetoothService> services){
    services.forEach((sItem) {
      String sUuid = sItem.uuid.toString();
      if(sUuid == SET_MODE_SERVICE_UUID.toString()){ //找到设置模式的服务
        log("4.找到设置模式的服务 >>>>>>name: ${device.name}  serviceGuid: ${SET_MODE_SERVICE_UUID.toString()}");
        _readCharacteristics(device, sItem); //读取特征值
      } else if(sUuid == WRITE_DATA_SERVICE_UUID.toString()){ //找到写数据的服务
        log("4.找到写数据的服务 >>>>>>name: ${device.name}  serviceGuid: ${WRITE_DATA_SERVICE_UUID.toString()}");
        _readCharacteristics(device, sItem); //读取特征值
      }
    });
  }
  //4.读取特征值(读出设置模式与写数据的特征值)
  Future<void> _readCharacteristics(BluetoothDevice device, BluetoothService service) async {
    var characteristics = service.characteristics;
    for(BluetoothCharacteristic cItem in characteristics) {
      String cUuid = cItem.uuid.toString();
      if(cUuid == SET_MODE_CHARACTERISTIC_UUID.toString()){ //找到设置模式的特征值
        log("4.0.找到设置模式的特征值 >>>>>>name: ${device.name}  characteristicUUID: ${SET_MODE_CHARACTERISTIC_UUID.toString()}");
        _requestMtu(device); //设置MTU
        _setNotificationMode(device, cItem); //设置为Notification模式(设备主动给手机发数据)
      } else if(cUuid == WRITE_DATA_CHARACTERISTIC_UUID.toString()){ //找到写数据的特征值
        log("4.0.找到写数据的特征值 >>>>>>name: ${device.name}  characteristicUUID: ${WRITE_DATA_CHARACTERISTIC_UUID.toString()}");
        _writeCharacteristic = cItem; //保存写数据的征值
      }
    }
  }
  //4.1.设置MTU
  Future<void> _requestMtu(BluetoothDevice device) async {
    final mtu = await device.mtu.first;
    log("4.1.当前mtu: $mtu 请求设置mtu为512 >>>>>>name: ${device.name}");
    await device.requestMtu(512);
  }
  //4.2.设置为Notification模式(设备主动给手机发数据),Indication模式需要手机读设备的数据
  Future<void> _setNotificationMode(BluetoothDevice device, BluetoothCharacteristic cItem) async {
    log("4.2.设置为通知模式 >>>>>>name: ${device.name}");
    await cItem.setNotifyValue(true); //为指定特征的值设置通知
    cItem.value.listen((value) {
      if (value == null || value.isEmpty) return;
      log("接收数据 >>>>>>name: ${device.name}  value: $value");
      MessageData data = MessageData();
      //...省略解析设备数据的逻辑
      _gattCallback.onRead(data);  //回调外部,返回设备发送的数据
    });
    var descriptors = cItem.descriptors;
    for (BluetoothDescriptor dItem in descriptors) {
      if (dItem.uuid.toString() == SET_MODE_DESCRIPTOR_UUID.toString()) {//找到设置模式的descriptor
        log("发送Notification模式给设备 >>>>>>name: ${device.name}");
        dItem.write(ENABLE_NOTIFICATION_VALUE); //发送Notification模式给设备
        return;
      }
    }
  }
  //发送指令到设备
  Future<void> writeCommand(List<int> data) async {
    log("发送指令给设备 >>>>>>name: ${device.name}  data: $data");
    await _writeCharacteristic?.write(data);
  }
  //断开连接
  void disconnect(BluetoothDevice device) {
    log("断开连接 >>>>>>name: ${device.name}");
    device.disconnect();  //关闭连接
    _gattCallback.onDisconnect();  //连接失败回调
  }
}

(2)蓝牙连接回调接口:

typedef OnDeviceNotFind = void Function();
typedef OnConnected = void Function();
typedef OnDisconnect = void Function();
typedef OnRead = void Function(MessageData data);
class GattCallback {
  GattCallback ({required this.onDeviceNotFind, required this.onConnected, required this.onDisconnect, required this.onRead});
  OnDeviceNotFind onDeviceNotFind;
  OnConnected onConnected;
  OnDisconnect onDisconnect;
  OnRead onRead;
}

4.调用例子:文章来源地址https://www.toymoban.com/news/detail-513195.html

...//省略其他
ConnectManager connectManager = ConnectManager(GattCallback( //1.实例化连接管理类,并监听连接状态
    onDeviceNotFind: () { //没找到设备

    },
    onConnected: () { //连接成功回调

    },
    onDisconnect: () { //连接关闭回调

    },
    onRead: (MessageData data) {   //设备发过来的数据

    }
));
...//省略其他
if(!connectManager.isConnecting){
  connectManager.start("T11302002020169"); //2.开始连接蓝牙设备,T11302002020169为蓝牙设备名称
}

到了这里,关于Flutter:BLE蓝牙开发的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Flutter系列文章-Flutter 插件开发

    在本篇文章中,我们将学习如何开发 Flutter 插件,实现 Flutter 与原生平台的交互。我们将详细介绍插件的开发过程,包括如何创建插件项目、实现方法通信、处理异步任务等。最后,我们还将演示如何将插件打包并发布到 Flutter 社区。 在 Flutter 项目中,你可能需要与原生平台

    2024年02月11日
    浏览(38)
  • flutter开发实战-video_player插件播放抖音直播实现(仅限Android端)

    flutter开发实战-video_player插件播放抖音直播实现(仅限Android端) 在之前的开发过程中,遇到video_player播放视频,通过查看video_player插件描述,可以看到video_player在Android端使用exoplayer,在iOS端使用的是AVPlayer。由于iOS的AVPlayer不支持flv、m3u8格式的直播,这里video_player播放抖音直

    2024年02月05日
    浏览(47)
  • Flutter蓝牙框架-flutter_blue_plus使用及源码解析

    前段时间有朋友拜托我研究下flutter利用蓝牙与硬件交互的功能,我查阅了很多资料,目前市面上比较流行的第三方库有两个,一个是flutter_blue_plus,一个是flutter_reactive_ble,前一个比较轻量级,能满足大部分场景,后一个比较复杂,支持多个蓝牙设备同时连接。那么这一次我

    2024年02月13日
    浏览(42)
  • Flutter插件开发-(进阶篇)

    一、概述 Flutter也有自己的Dart Packages仓库。 插件的开发和复用能够提高开发效率,降低工程的耦合度 ,像网络请求(http)、用户授权(permission_handler)等客户端开发常用的功能模块,我们只需要引入对应插件就可以为项目快速集成相关能力,从而专注于具体业务功能的实现。 除

    2024年02月08日
    浏览(38)
  • 使用Flutter的image_picker插件实现设备的相册的访问和拍照

    在应用开发时,我们有很多场景要使用到更换图片的功能,即将原本的图像替换设置成其他的图像,从设备的相册或相机中选择图片或拍照的方式来更换图像。那么用Flutter要如何实现从设备的相册或相机中选择图片或拍照呢? 其实很简单一个插件就能解决,而且使用起来也

    2024年02月14日
    浏览(36)
  • Flutter 应用开发的pubspec.yaml文件说明

    pubspec.yaml是Flutter项目中的配置文件,它用于定义项目的依赖项、资源文件以及其他相关配置。 以下是pubspec.yaml文件的一些关键点: 项目名称:通过name字段指定项目的名称。 项目描述:通过description字段提供对项目的简要描述。 依赖项:使用dependencies字段定义项目所依赖的

    2024年02月05日
    浏览(40)
  • 【Flutter】Flutter 数据存储 Hive 的简要使用说明

    🎉想要精通 Flutter,掌握更多技巧和最佳实践?好消息来了!👉

    2024年02月10日
    浏览(43)
  • 物联网开发笔记(53)- 使用Micropython开发ESP32开发板之蓝牙BLE通信

    一、目的         这一节我们学习如何使用我们的ESP32开发板通过蓝牙和手机进行通信。 二、环境         ESP32 + 手机(笔者用的小米10) + Thonny IDE 三、蓝牙介绍         这个知识大家自行百度吧,这里不再赘述什么是蓝牙和蓝牙的历史,以及相关的专业知识。 四、

    2024年02月06日
    浏览(55)
  • Qt笔记---使用Qt开发低功耗蓝牙BLE(Bluetooth low energy)程序

    在Qt项目中开发BLE通信程序,即低功耗蓝牙设备通信,关于蓝牙设备的通信分为普通蓝牙设备和低功耗蓝牙设备,此文只介绍低功耗蓝牙设备的连接通信方式。 开发环境: 系统:win10 Qt:5.15.2 MSVC:2019 注:使用此版本之前使用过其他低版本的Qt和MSVC,会出现搜索不到设备以及

    2024年04月16日
    浏览(125)
  • Flutter 插件开发遇到的问题及解决方案

    本文主要对笔者flutter插件开发过程中如下问题做了解决。 一、Flutter插件android模块中的代码报红问题解决 二、Flutter Plugin 开发中引入本地 aar 包报错的问题。 三、Flutter插件项目中获取到 Activity 1、在开发Flutter插件时,打开插件的android项目,准备编写native端的代码时,发现各

    2024年02月20日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包