第二百三十七回

2023-12-30 23:36
文章标签 三十七 第二百

本文主要是介绍第二百三十七回,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 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.chinasem.cn/article/554336

相关文章

优雅编程之项目开发中的22点编码小建议(三十七)

http://blog.csdn.net/huangwenyi1010/article/details/53890837

Java程序员从笨鸟到菜鸟(三十七)redhat7安装及部署web项目

一、软件下载 虚拟机 VmwareWorkStation 12操作系统 RedHatEnterpriseLinux [RHEL]7.0 软件下载传送门:https://www.linuxprobe.com/tools 二、安装软件 安装教程传送门:https://www.linuxprobe.com/chapter-01.html 三、网络设置 1.虚拟机网络选择 1.选择net模

尚品汇-购物车列表、临时用户购物车与登录用户购物车合并实现(三十七)

目录: (1)功能—展示购物车列表 (2)在web-all添加前端实现 (3)功能--合并购物车 (1)功能—展示购物车列表 购物车列表接口:CartService /*** 通过用户Id 查询购物车列表* @param userId* @param userTempId* @return*/List<CartInfo> getCartList(String userId,

第二百零九节 Java格式 - Java数字格式类

Java格式 - Java数字格式类 以下两个类可用于格式化和解析数字: java.text.NumberFormatjava.text.DecimalFormat NumberFormat 类可以格式化一个数字特定地区的预定义格式。 DecimalFormat 类可以格式化数字以特定区域设置的自定义格式。 NumberFormat类的 getXXXInstance()方法返回格式化

第二百零四节 Java正则表达式教程 - Java正则表达式量词

Java正则表达式教程 - Java正则表达式量词 我们可以指定正则表达式中的字符的次数可以匹配字符序列。 为了使用正则表达式表达一个数字或更多的模式,我们可以使用量词。 下表列出了量词及其含义。 量词含义*零次或更多次+一次或多次?一次或根本不{m}正好m次{m,}至少m次{m,n}至少m,但不超过n次 量词必须遵循字符或字符类。 例子 import java.util.reg

POSTMAN从入门到精通系列(三十七):脚本简介二

请求前脚本是与收集请求关联的代码段,这些代码段在发送请求之前已执行。这非常适合用例,例如在请求标头中包含时间戳或在URL参数中发送随机字母数字字符串。 例如,要在请求标头中包含时间戳,可以使用从函数返回的值设置环境变量。 然后,您可以 通过键入在标题数据编辑器中访问  timestampHeader变量{{timestampHeader}}。发送请求后,将执行您的请求前脚本,并发送time

FFmpeg开发笔记(三十七)分析SRS对HLS协议里TS包的插帧操作

《FFmpeg开发实战:从零基础到短视频上线》一书的“2.1.2  音视频文件的封装格式”介绍了视频流的PS格式和TS格式。由于TS包的长度固定,从TS流的任一片段开始都能独立解码,因此可以把TS当成音视频文件的封装格式。 鉴于TS包的独立解码特性,HLS协议引入了TS格式作为传输单元。HLS协议的实现原理是对一个大的媒体分片,并将分片后的文件路径记录于m3u8文件,客户端依据该m3u8文件即可获

算法数据结构(三十七)----状态压缩技巧

题目一 链接:https://leetcode-cn.com/problems/can-i-win 在 "100 game" 这个游戏中,两名玩家轮流选择从 1 到 10 的任意整数,累计整数和,先使得累计整数和达到或超过 100 的玩家,即为胜者。 如果我们将游戏规则改为 “玩家不能重复使用整数” 呢? 例如,两个玩家可以轮流从公共整数池中抽取从 1 到 15 的整数(不放回),直到累计整

三十七、openlayers官网示例Earthquakes Heatmap解析——在地图上加载热力图

官网demo地址: Earthquakes Heatmap  这篇主要介绍了热力图HeatmapLayer HeatmapLayer 是一个用于在地图上显示热力图的图层类型,通常用于表示地理数据中的密度或强度。例如,它可以用来显示地震、人口密度或其他空间数据的热点区域。在这个示例中,HeatmapLayer 被用来显示从 KML 文件中提取的地震数据。  const vecto

(三十七)第 6 章 树和二叉树(二叉树的二叉链表存储表示实现)

1. 背景说明 2. 示例代码   1) errorRecord.h   // 记录错误宏定义头文件#ifndef ERROR_RECORD_H#define ERROR_RECORD_H#include <stdio.h>#include <string.h>#include <stdint.h>// 从文件路径中提取文件名#define FILE_NAME(X) s