IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Flutter BLE应用的开发-flutter_blue -> 正文阅读

[移动开发]Flutter BLE应用的开发-flutter_blue

一、写在前面的话

本文主要介绍在Flutter环境下开发BLE应用。主要包含以下内容:判断蓝牙是否开启、判断是否有位置权限、扫描设备、

连接设备、监听设备上报的数据(Notify)、向设备发送数据、监听设备的断开等。内容虽然简单,但是很详细。

二、开始

1、使用到的库

? flutter_blue: ^0.7.1+1
? permission_handler: "^3.2.0" # 权限
? 众所周知,Flutter要使用原生的能力,就需要有原生库的支持,这里我们使用了flutter_blue来开发跟BLE相关的功能,permission_handler来开发权限检测以及申请权限的功能。在使用flutter_blue开启扫描的时候,插件会弹出系统的权限申请窗口,但是点击授权以后报了一个空指针,可能是插件存在的一个BUG,所以这里我们用permission_handler插件来处理权限相关的问题。(友情提示:在Android上扫描Ble需要位置权限)

2、flutter_blue的用法

import 'package:flutter_blue/flutter_blue.dart';
FlutterBlue flutterBlue = FlutterBlue.instance;
导包和初始化。

3、判断蓝牙是否开启

@override
? void initState() {
? ? super.initState();
? ? flutterBlue.state.listen((state){
? ? ? if(state == BluetoothState.on){
? ? ? ? print('蓝牙状态为开启');
? ? ? ? isBleOn = true;
? ? ? }else if(state == BluetoothState.off){
? ? ? ? print('蓝牙状态为关闭');
? ? ? ? isBleOn = false;
? ? ? }
? ? });
? }
在路由初始化的时候开启对蓝牙状态的监听。

?if(!isBleOn){
? ? ? ToastUtils.toast(context, "手机蓝牙未打开,请打开后再扫描设备");
? ? ? return;
? ? }
在开始之前对蓝牙开启状态进行判断。

4、判断位置权限

PermissionUtils.checkPermissions(PermissionGroup.location).then((v) {
? ? ? if (v) {
? ? ? ? Navigator.pushNamed(context, "/device_page");
? ? ? } else {
? ? ? ? PermissionUtils.showDialog(context, "提示", "扫描蓝牙需要位置权限", () async {
? ? ? ? ? Navigator.pop(context);
? ? ? ? ? await PermissionHandler()
? ? ? ? ? ? ? .requestPermissions([PermissionGroup.location]);
? ? ? ? ? PermissionStatus permission = await PermissionHandler()
? ? ? ? ? ? ? .checkPermissionStatus(PermissionGroup.location);
? ? ? ? ? if (permission == PermissionStatus.granted) {
? ? ? ? ? ? Navigator.pushNamed(context, "/device_page");
? ? ? ? ? } else {
? ? ? ? ? ? print("no Permission to scan ble");
? ? ? ? ? ? ToastUtils.toast(context, "权限开启失败,请在系统设置中开启!");
? ? ? ? ? }
? ? ? ? }, () {
? ? ? ? ? Navigator.pop(context);
? ? ? ? });
? ? ? }
? ? });
?以上是对位置权限的处理,如果有,就进入扫描设备页面,没有的话申请权限,申请完之后在对其进行判断。因为本文的重点是ble,这里不对权限申请插件做过多的介绍。(PermissionUtils,dialog的源码会在文末附上)

5、扫描设备

?flutterBlue.scan().listen((scanResult) {
? ? ? // do something with scan result
? ? ? var device = scanResult.device;
? ? ? if (device.name.length > 10) {
? ? ? ? if (deviceSet.indexOf(device) == -1) {
? ? ? ? ? setState(() {
? ? ? ? ? ? deviceSet.add(device);
? ? ? ? ? });
? ? ? ? }
? ? ? ? print(
? ? ? ? ? ? '${device.name} found! rssi: ${scanResult.rssi},address:${device.id}');
? ? ? }
? ? });
? ? 使用api进行ble扫描,我对蓝牙名进行了过滤,记得要存起来哦,连接的时候要用的。

6、连接设备

? ? ? await device.connect(autoConnect: false, timeout: Duration(seconds: 10));
这里的连接参数可以根据需要自己进行设置,我这里设置了10秒连接超时。这里我们一般还不能认为连接成功,还需要找到对应的读写服务和特征值。

BluetoothCharacteristic mCharacteristic;
List<BluetoothService> services = await device.discoverServices();
? ? ? services.forEach((service) {
? ? ? ? if (service.uuid.toString() == GattAttributes.BLE_SPP_SERVICE_READ) {
? ? ? ? ? List<BluetoothCharacteristic> characteristics =
? ? ? ? ? ? ? service.characteristics;
? ? ? ? ? characteristics.forEach((characteristic) {
? ? ? ? ? ? if (characteristic.uuid.toString() ==
? ? ? ? ? ? ? ? GattAttributes.BLE_SPP_NOTIFY_CHARACTERISTIC) {
? ? ? ? ? ? ? mCharacteristic = characteristic;
? ? ? ? ? ? }
? ? ? ? ? });
? ? ? ? }
? ? ? ? // do something with service
? ? ? });
以上便是根据uuid在对应的读写服务中找到对应Characteristic,至此,连接过程便已经完成了,可以进行页面跳转了。

7、读取设备的心跳

if (mNotifyCharacteristic != null) {
? ? ? mNotifyCharacteristic.setNotifyValue(true);
? ? ? mNotifyCharacteristic.value
? ? ? ? ? .listen((value) => {print("device is online: " + value.toString())});
? ? }
通过第6点的方法,找到可以notify的Characteristic,开启notify,然后监听其值。这里的setNotifyValue可能会有异常,具体请

参考我的前篇文章点我点我。下图是蓝牙设备传回的心跳。

8、向设备发送数据

? Future<Null> write(List<int> value, {bool withoutResponse = false})
我先查看源码可知write方法的参数是一个int型的list,那么我们只需把我们需要发送的数据放进这个list中就行了。

? ? ? mWriteCharacteristic.write([0x00,0x01]);
同样,获取mWriteCharacteristic的方法如上第6点所示。

9、监听设备的断开

? device.state.listen((state){
? ? ? ? if(state == BluetoothDeviceState.disconnected){
? ? ? ? ? DialogUtils.showOneDialog(context, "提示", "设备已断开连接", (){
//do something
? ? ? ? ? });
? ? ? ? }
? ? ? });
10、在不用页面获取device

?await flutterBlue.connectedDevices.then((list) => {
? ? ? ? ? if (list.length == 0) {Navigator.pop(context)} else {device = list[0]}
? ? ? ? });
在不同的页面(路由)需要对设备进行读写操作,在设备的连接池中获取。

三、总结

本文归纳了flutter下使用ble对设备进行读写的详细步骤以及一些基本方法和注意事项,如果有问题的同学欢迎留言,博主会一一解答的。技术在于分享,开源的乐趣也在于此,如果本文有不够严谨的地方还望大佬支持。

附录

import 'package:flutter/cupertino.dart';
?
class DialogUtils{
? static showDialog(BuildContext cxt, String title, String content,
? ? ? ok(), cancel()) {
? ? showCupertinoDialog<int>(
? ? ? ? context: cxt,
? ? ? ? builder: (cxt) {
? ? ? ? ? return CupertinoAlertDialog(
? ? ? ? ? ? title: Text(title),
? ? ? ? ? ? content: Text(content),
? ? ? ? ? ? actions: <Widget>[
? ? ? ? ? ? ? CupertinoDialogAction(
? ? ? ? ? ? ? ? child: Text("确定"),
? ? ? ? ? ? ? ? onPressed: () {
? ? ? ? ? ? ? ? ? ok();
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ),
? ? ? ? ? ? ? CupertinoDialogAction(
? ? ? ? ? ? ? ? child: Text("取消"),
? ? ? ? ? ? ? ? onPressed: () {
? ? ? ? ? ? ? ? ? cancel();
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? )
? ? ? ? ? ? ],
? ? ? ? ? );
? ? ? ? });
? }
? static showOneDialog(BuildContext cxt, String title, String content,
? ? ? ok()) {
? ? showCupertinoDialog<int>(
? ? ? ? context: cxt,
? ? ? ? builder: (cxt) {
? ? ? ? ? return CupertinoAlertDialog(
? ? ? ? ? ? title: Text(title),
? ? ? ? ? ? content: Text(content),
? ? ? ? ? ? actions: <Widget>[
? ? ? ? ? ? ? CupertinoDialogAction(
? ? ? ? ? ? ? ? child: Text("确定"),
? ? ? ? ? ? ? ? onPressed: () {
? ? ? ? ? ? ? ? ? ok();
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? )
? ? ? ? ? ? ],
? ? ? ? ? );
? ? ? ? });
? }
}
import 'package:flutter/cupertino.dart';
import 'package:permission_handler/permission_handler.dart';
?
/// 权限管理工具类
class PermissionUtils {
? /// 检测相关权限是否已经打开(根据已有状态值)
? static bool checkPermissionsByStatus(List<PermissionStatus> lists) {
? ? bool result = true;
?
? ? for (PermissionStatus permissionStatus in lists) {
? ? ? if (permissionStatus != PermissionStatus.granted) {
? ? ? ? result = false;
? ? ? ? break;
? ? ? }
? ? }
?
? ? return result;
? }
?
? /// 检测相关权限是否已经打开(根据已有权限名称)
? static Future<bool> checkPermissionsByGroup(
? ? ? List<PermissionGroup> lists) async {
? ? bool result = true;
?
? ? for (PermissionGroup permissionGroup in lists) {
? ? ? PermissionStatus checkPermissionStatus =
? ? ? await PermissionHandler().checkPermissionStatus(permissionGroup);
?
? ? ? if (checkPermissionStatus != PermissionStatus.granted) {
? ? ? ? result = false;
? ? ? ? break;
? ? ? }
? ? }
?
? ? return result;
? }
? static Future<bool> checkPermissions(PermissionGroup permissionGroup) async{
? ? bool result = true;
?
? ? PermissionStatus checkPermissionStatus =
? ? await PermissionHandler().checkPermissionStatus(permissionGroup);
?
? ? if (checkPermissionStatus != PermissionStatus.granted) {
? ? ? result = false;
?
? ? }
? ? return result;
?
? }
?
? /// 权限提示对话款
? static showDialog(BuildContext cxt, String title, String content,
? ? ? ?ok(), cancel()) {
? ? showCupertinoDialog<int>(
? ? ? ? context: cxt,
? ? ? ? builder: (cxt) {
? ? ? ? ? return CupertinoAlertDialog(
? ? ? ? ? ? title: Text(title),
? ? ? ? ? ? content: Text(content),
? ? ? ? ? ? actions: <Widget>[
? ? ? ? ? ? ? CupertinoDialogAction(
? ? ? ? ? ? ? ? child: Text("去开启"),
? ? ? ? ? ? ? ? onPressed: () {
? ? ? ? ? ? ? ? ? ok();
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ),
? ? ? ? ? ? ? CupertinoDialogAction(
? ? ? ? ? ? ? ? child: Text("取消"),
? ? ? ? ? ? ? ? onPressed: () {
? ? ? ? ? ? ? ? ? cancel();
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? )
? ? ? ? ? ? ],
? ? ? ? ? );
? ? ? ? });
? }
}

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-08-19 12:09:56  更:2021-08-19 12:11:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 10:19:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码