第二百三十七回

文章目录

  • 1. 概念介绍
  • 2. 具体细节
    • 2.1 发现服务
    • 2.2 发现特征值
    • 2.3 发送数据
  • 4. 经验总结
  • 1. 概念介绍
  • 2. 主要功能
    • 2.1 扫描蓝牙设备
    • 2.2 连接蓝牙设备
  • 3. 示例代码
  • 4. 内容总结

我们在上一章回中介绍了"连接蓝牙设备的细节"相关的内容,本章回中将介绍通过蓝牙发送数据的细节.闲话休提,让我们一起Talk Flutter吧。

1. 概念介绍

我们在本章回中介绍的通过蓝牙设备发送数据仍然使用flutter_blue_plus包提供的接口,我们在第一百一十九章回中介过通过蓝牙发送数据的方法,不过还有一些
细节问题需要注意,本章回中将详细介绍通过蓝牙发送数据的细节内容。

2. 具体细节

通过蓝牙发送数据的细节主要包含发现服务(BluetoothService)和特征值(Characteristic),发送数据和接收数据。我们把这些内容分成各个小节来介绍。

2.1 发现服务

发现服务使用包中的discoverServices()方法就可以,不过蓝牙设备的服务比较多,需要进行遍历操作,在遍历过程中找到需要操作的服务,通常是通过服务的uuid
来判断服务是否是我们需要操作的某个服务。此外,蓝牙设备的服务具有读写特性,也可以依据读写特性来区分服务。

2.2 发现特征值

发现特征值不需要专门的方法,通过服务的characteristics属性就可以获取到该服务的特征值,该属性是一个列表,包含服务中的多个特征值。我们需要对特征值列表
进行遍历操作,在遍历过程中找到需要操作的特征值,通常是通过特征值的uuid来判断特征值是否是我们需要操作的某个特征值。此外,蓝牙设备的特征值类似服务,也
具有读写特性,也可以依据读写特性来区分不同的特征值。

2.3 发送数据

发送数据有两种方法:读特征值或者写特征值,读取特征值只能从蓝牙设备中读取内容,写特征值可以向蓝牙设备发送特定的内容,蓝牙设备收到具体的内容后可以做出专
门的响应,这种方法在实际项目中比较常用。包中提供了读特征值和写特征值的方法:read()和write()。注意这两个方法是特征值的方法,不是蓝牙设备的方法,在使
用这两个方法前需要判断特征值是否具有读或者写的特性,不具有读写特性的特征值无法调用这两种方法。

上面小节中介绍的实现方法比较抽象,接下来我们通过具体的代码来演示如何通过蓝牙设备读写数据;

  Future<List<BluetoothService>> discoverServices(BluetoothDevice device) async {///获取服务List<BluetoothService> services = await device.discoverServices();List<BluetoothCharacteristic> characteristics;Stream<List<int>> readValueChanged;Stream<List<int>> writeValueChanged;///查找具有读写特性的特征值同时监听Strem来获取蓝牙设备返回的数值for (var element in services) {// log.i("service: ${element.toString()}");characteristics = element.characteristics;for(var char in characteristics) {if(char.properties.read) {///激活监听char.setNotifyValue(true);readValueChanged = char.onValueReceived;readValueChanged.listen((event) {log.i('read chara feedback: ${event.toHes()}');});readCharacteristics(char);}if(char.properties.write) {///激活监听char.setNotifyValue(true);writeValueChanged = char.onValueReceived;writeValueChanged.listen((event) {log.i('write chara feedback: ${event.toHex()}');},onError:(e){log.i('write chara error: ${e.toString()}');},onDone: () => log.i('write chara done'),);writeCharacteristics(char);}}}return services;}///依据指定的UUID读取特征值void readCharacteristics (BluetoothCharacteristic characteristic) async{if(PrivateKey.searchServiceUuid != characteristic.characteristicUuid.toString()) {return null;}List<int> value =  await characteristic.read();log.w('read characteristic:  ${value.toString()}');}///依据指定的UUID写入特征值void writeCharacteristics (BluetoothCharacteristic characteristic) async{if(PrivateKey.writeCharacteristicUuid != characteristic.characteristicUuid.toString()) {return null;}List<int> value = [12,13,14];await characteristic.write(value,withoutResponse: false);log.w('write characteristic:  ${value.toString()}');}

上面的代码中把读写特征值的操作封装成了独立的方法,这样方便调用。我们可以依据特征值的读写属性来区分特征值,也可以依据特征值的uuid来区分特征值,不过需
要与蓝牙设备的开发工程师获取特征值的uuid.发起读写操作后,可以在Stream中的Listen()方法中获取到蓝牙设备返回的数据。我们在代码的关键位置都添加了注释,
这样方便大家理解代码。注意:读写操作需要进行异步操作,不然无法接收到数据。

4. 经验总结

最后,我们对本章回的内容做一个全面的总结:

  • Service,Characteristic和Descriptor都是蓝牙设备的属性,而且每个蓝牙都有这些属性;
  • Service,Characteristic和Descriptor环环相扣:获取到Service后才能获取Characteristic,获取到Characteristic后才能获取Descriptor;
  • 一个蓝牙设备可能会有多个service,我们可以通过它的uuid来区分不同的service;
  • 一个serice可能会有多个characteristic,我们可以通过它的uuid来区分不同的characteristic;
  • 一个characteristic可以具备读写属性中的任意一种,或者二种属性都具备;
  • Service和Characteristic都具有读写属性,可以通过读写特征来区分,或者通过uuid来区分;
  • 读写数据前需要激活特征值的监听功能,读写操作完成后,可以通过特征值的Stream接收蓝牙设备回复的数据;
  • 读写数据的操作需要通过异步方法来实现,否则无法接收到蓝牙设备回复的数据;
    看官们,与"通过蓝牙发送数据的细节"相关的内容就介绍到这里,欢迎大家在评论区交流与讨论!

第一百九十七回 蓝牙综合使用示例一
我们在上一章回中介绍了"通过蓝牙发送数据的细节相关的内容,本章回中将介绍蓝牙综合使用示例.闲话休提,让我们一起Talk Flutter吧。

1. 概念介绍

本章回中的蓝牙综合示例是在前面两个章回中的基础上实现的,主要包含蓝牙的扫描和连接功能。建议大家先阅读博客中关于蓝牙基础知识的介绍,然后是前面两个章回中
的细节内容,这样有助于大家理解内容。此外,示例中仍然使用使用flutter_blue_plus包提供的接口.

2. 主要功能

2.1 扫描蓝牙设备

扫描蓝牙功能直接使用FlutterBluePlus.startScan()方法就可以,不过扫描前需要申请蓝牙权限,有了蓝牙权限以后才可以进行扫描。此外,还需要进行初始化操
作,这个初始化主要是监听Stream: FlutterBluePlus.scanResults.当扫描到蓝牙设备的话,就可以直接从该Stream中获取蓝牙设备列表。此外,扫描前还需
要打开手机上的蓝牙开关,这个内容比较多,我们将在后面章回中介绍这方面的内容。

2.2 连接蓝牙设备

连接蓝牙设备使用包中提供的connect()方法就可以,该方法返回的是Future,我们可以通过Future处理连接完成和连接失败的相关操作。注意一下,该方法是异步方
法,因此需要使用async/await关键字来实现异步操作。

3. 示例代码

介绍完主要的功能后,我们通过具体的示例代码来演示如何实现这些功能,下面是示例代码,请大家参考:

void checkPermission() async {var status = await Permission.bluetooth.status;if (status.isDenied) {requestPermission();}
}///这里的蓝牙权限只包含两个,大家可以依据平台版本来请求不同的权限
void requestPermission() async {Map<Permission, PermissionStatus> permissionMap = await [// Permission.locationAlways,Permission.bluetoothScan,Permission.bluetoothConnect,].request();
}///初始化操作,主要是监听Stream来获取扫描到的蓝牙设备列表
void initBLE() {subscription = FlutterBluePlus.scanResults.listen((result) {scanDeviceList = result;filterDeviceList = scanDeviceList?.where((element) => element.device.localName.isNotEmpty).toList();filterDeviceList?.forEach((element) {_deviceViewModel.setDeviceModel(element.device.localName, "Disconnected");});},onError: (e) => debugPrint('onError ${e.toString()}'),onDone: () => debugPrint('onDone'),);
}///扫描蓝牙设备
void startScan() {debugPrint('start scan');FlutterBluePlus.startScan(// withServices: [Guid(PrivateKey.uuid)],timeout: Duration(seconds: scanTimeout),);
}///连接设备
void connectDevice(BluetoothDevice device) async {if (device != null) {await device.connect().onError((error, stackTrace) =>log.e('connect device: ${error.toString()}')).whenComplete(() => log.i('connect finished'));}
}

我们在上面的示例代码中依据不同的功能把相关的操作封装成了方法,并且添加了相关的注释以方便大家理解代码。程序需要运行在真机上才可以扫描蓝牙,建议大家自己
动手去实践,这样可以看到扫描到的蓝牙设备。代码中没有涉及页面,大家可以把相关的功能添加到按钮的onPress属性上,这样就可以在点击按钮时完成相关的功能,
蓝牙设备列表也可以显示到页面上,或者通过log打印出来。我在这里就不实现这些内容了,只是给大家提一个实现的方向和思路。

4. 内容总结

最后,我们对本章回中的内容做一个全面的总结:

  • 蓝牙扫描功能直接使用包中的方法就可以;
  • 蓝牙扫描前需要获取蓝牙操作权限并且监听扫描设备列表;
  • 连接蓝牙设备直接使用包中的方法就可以,不过需要进行异步处理;
  • 蓝牙操作的相关功能建议和按钮的onPress属性关联,这样可以在点击按钮时实现相关功能;
    看官们,与"蓝牙综合使用示例"相关的内容就介绍到这里,欢迎大家在评论区交流与讨论!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/586257.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据库系统概论】第7章-数据库设计

文章目录 7.1 数据库设计概述7.2 需求分析7.2.1 需求分析的任务7.2.2 需求分析的难点7.2.2 需求分析的方法7.2.3 数据字典 7.3 概念结构设计7.3.1 概念模型7.3.2 E-R模型7.3.3 概念结构设计 7.4 逻辑结构设计7.4.1 E-R图向关系模型的转换7.4.2 数据模型的优化7.4.3 设计用户子模…

【教程】标注工具Labelimg的安装与使用

图片标注主要是为了建立自己的数据集&#xff0c;便于进行更深度的学习训练。本篇文章将对一款十分好用的图片标注工具labelimg进行介绍&#xff0c;重点介绍其安装以及使用的过程。 - 什么是labelimg labelimg 是一个可视化的图像标定工具。它是用Python编写的&#xff0c;并…

HDFS客户端UnknownHostException事故解析

文章目录 前言事故现场问题分析是否是整个域名解析服务当时都出问题了是否是出问题的pods本身的域名解析有问题 异常发生的全部过程域名的解析是什么时候发生的&#xff0c;怎么发生的域名解析的详细流程 重试发生在什么地方为什么重试会无效 Bugfix代码详解关于StandardHostRe…

特殊权限(suid sticky acl mask)

1.suid 1. 普通用户可不可以修改密码&#xff1f; 答&#xff1a;是可以的&#xff0c;可以修改自己的密码 2. /etc/shadow 文件的作用是什么&#xff1f; 答&#xff1a;存储用户密码的文件 3. 普通用户是否可以修改/etc/shadow 文件&#xff1f; 答&#xff1a;不可以&…

STM32+Codesys工业软件PLC解决方案

工业控制系统在现代制造和自动化领域扮演着关键角色, 基于IEC 61131-3 标准的控制器编程开发软件平台CODESYS&#xff0c;适用于多种行业的控制系统的开发,使用户方便快捷地对自动化工程进行编程和配置&#xff0c;完成项目开发、软件测试和应用调试。 本次STM32联合合作伙伴C…

Docker logs 命令——查看docker容器日志

请直接看原文: 原文链接:Docker logs 命令——查看docker容器日志-CSDN博客 --------------------------------------------------------------------------------------------------------------------------------- 用法&#xff1a; docker logs [OPTIONS] CONTAINER …

2023年全国职业院校技能大赛网络系统管理网络模块 网络构建答题卡(600)(还原截图锐捷)

网络构建答题卡(600) 要求:使用下面指令查看其运行状态,并使用FSCapture截图软件进行截图,将输入结果的截图插入到文档中。 职业素养(25) 截图文档整洁规范,根据题目要求进行截图。 整理赛位,工具、设备归位,保持赛后整洁有序。 遵守赛项记录,听从裁判安排。 基础…

FC UxROM (Mapper 2) 操作

UxROM 概览 mapper号2卡带名UxROMPRG ROM容量256K / 4096KPRG ROM窗口16K 16K fixedPRG RAM容量无PRG RAM窗口无CHR ROM容量无CHR ROM窗口n/a扩展声音无IRQ无 寄存器 Bank 选择 ( 8000 − 8000- 8000−FFFE) 7 bit 0 ---- ---- xxxx pPPP||||- 为 CPU $8000-$BFFF 选择…

服务器运行状况监控工具

服务器运行状况监视提供了每个服务器状态和性能的广泛概述&#xff0c;通过监控服务器指标&#xff0c;如 CPU 使用率、内存消耗、I/O、磁盘使用率、进程等&#xff0c;服务器运行状况监控可以避免服务器停机。 服务器性能监控指标 服务器是网络中最重要的组件之一&#xff0…

计算机网络复习6

应用层 文章目录 应用层网络应用模型域名系统DNS文件传输协议FTP电子邮件万维网 网络应用模型 客户/服务器模型 客户/服务器&#xff08;Client/Server&#xff0c;C/S)模型中&#xff0c;有一个总是打开的主机称为服务器&#xff0c;它服务于许多来自其他称为客户机的主机请求…

Python线程池实现的进阶知识

1.参数 max_workers 的设定 接前文 《Python多线程和线程池的下载实战用法 》中案例,继续分析 concurrent.futures.ThreadPoolExecutor() 是 Python 中的一个线程池实现,用于执行并发的任务。它可以通过参数 max_workers 来设置线程池的最大工作线程数。 在你提供的代码中,…

SLAM学习入门--编程语言

文章目录 编程语言一、C/C++C 与 C++ 的区别(面向对象的特点)C++ 与 Python的区别判断struct的字节数static 作用Const 作用extern "C"的作用多态如何实现多态?虚函数虚函数怎么实现的?析构函数虚析构函数的作用virtual函数能不能用在构造函数中&#

Java集合/泛型篇----第一篇

系列文章目录 文章目录 系列文章目录前言一、ArrayList和linkedList的区别二、HashMap和HashTable的区别三、Collection包结构,与Collections的区别四、泛型常用特点前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站…

Spring系列学习四、Spring数据访问

Spring数据访问 一、Spring中的JDBC模板介绍1、新建SpringBoot应用2、引入依赖&#xff1a;3、配置数据库连接&#xff0c;注入dbcTemplate对象&#xff0c;执行查询&#xff1a;4&#xff0c;测试验证&#xff1a; 二、整合MyBatis Plus1&#xff0c;在你的项目中添加MyBatis …

Java 实现自动获取法定节假日

一、背景 在实现业务需求的过程中&#xff0c;遇到了需要计算 x 个工作日后的日期需求。由于工作日是每年国务院发布的&#xff0c;调休和休假都没有规律&#xff0c;所以无法使用算法进行计算。 一般的实现方案是自己维护一个工作日和调休的表&#xff0c;或者去爬取国务院发…

AutoSAR(基础入门篇)4.4-Autosar_BSW的Memory功能

Memory功能 一、Autosar_BSW的Memory 1、Memory 组件图 2、架构与术语解释 3、片内存储 4、片外存储

游戏加速器LSP/DLL导致WSL.EXE无法打开问题修复!

解决办法&#xff1a; https://github.com/microsoft/WSL/issues/4177#issuecomment-597736482 方法一&#xff1a;&#xff08;管理员身份&#xff09; netsh winsock reset 方法二&#xff1a; WSCSetApplicationCategory 函数设置LSP加载权限 bool NoLsp(const wchar_t* …

从零开始:使用 BIND 构建和管理您的 DNS 服务器

1 前言 在这篇文章中&#xff0c;我将详细介绍如何使用 BIND&#xff08;Berkeley Internet Name Domain&#xff09;软件包中的 named 程序来配置和管理一个基本的 DNS 服务器。 从安装 BIND 开始&#xff0c;到设置 DNS 区域文件&#xff0c;再到运行和测试您的服务器&#x…

Oracle 19c OCP 1z0 082考场真题解析第17题

考试科目&#xff1a;1Z0-082 考试题量&#xff1a;90 通过分数&#xff1a;60% 考试时间&#xff1a;150min 本文为云贝教育郭一军guoyJoe原创&#xff0c;请尊重知识产权&#xff0c;转发请注明出处&#xff0c;不接受任何抄袭、演绎和未经注明出处的转载。 17. Which three …

通过数字证书对PDF电子文件进行数字签名/盖章

以下代码详细说明如何使用数字证书对PDF电子文件进行数字签名/盖章。PDF文件签署主要传递PDF文件&#xff0c;数字证书信息&#xff0c;签章图片3个信息。代码中需要的文件、数字证书、签章图片可访问开放签电子签章开源系统详细了解系统的实现与效果。也可通过gitee开源社区下…