一个小时搞定蓝牙调试助手!!!
项目介绍
蓝牙调试助手是一个用于蓝牙低功耗(BLE)设备开发和调试的移动应用程序,旨在帮助开发者更高效地进行蓝牙相关项目的调试和分析。
主要功能包括:
- 蓝牙数据捕获:实时捕获蓝牙设备之间的通信数据,包括连接状态、传输数据等。
- 数据包分析:解析蓝牙数据包,显示详细信息如信号强度、设备地址、数据内容等。
- 设备管理:支持对蓝牙设备的扫描、连接、数据收发和断开操作。
- 实时监控:提供实时的蓝牙设备状态监控,帮助开发者快速定位问题。
- 配置管理:支持对蓝牙设备的配置参数进行调整和管理。
该工具以图形化界面呈现,操作简单,适用于需要进行蓝牙通信测试和调试的场景。
平台支持
- Android
- iOS
AiFlutter市场链接:蓝牙调试助手App
平台实现步骤
1. 注册登录
打开 低代码平台登录网页 ,使用微信快捷登录或者扫描二维码登录。
2. 创建项目
- 点击【新增项目】->【手动添加】,在平台内部创建项目
- 在跳出的弹窗中输入项目名称、项目描述,建议结合项目功能描述命名,便于检索
- 输入完成后点击确定
3. 创建页面
(1)点击已经创建好的项目进入到操作界面,默认会存在一个HomePage
页面,操作界面相关详情可查看教程 操作界面
(2)创建三个页面 AddBleDevice
、SetBleName
、DeviceNetWork
- 点击【添加页面】 -> 【创建页面】
- 在跳出的弹窗中输入 页面名称、页面描述
- 最后点击确定即可
(4)删除HomePage
页面,在【页面管理】中右击要删除的页面,并点击【删除】
(5)设置AddBleDevice
为主页面,在【页面管理】中单击要删除的页面,并在右侧的属性编辑器中设置页面路由为/
4. 页面设计
AddBleDevice页面设计
页面描述
- 在页面初始化时,会依次执行以下操作
- 监听蓝牙扫描状态,接收到状态变化后重新构建页面
- 蓝牙扫描结果监听,接收到扫描结果后进行存储并重新构建页面
- 开始蓝牙扫描,扫描时长8秒
- 连接设备,在设备列表中选择设备进行连接,连接成功后跳转到数据收发页面
- 重新扫描,蓝牙扫描结束后,点击【重新扫描】开始扫描,此时会断开已连接的蓝牙设备
效果图

实现流程
(1)在【页面管理】中单击AddBleDevice
页面,在右侧的属性编辑器中添加页面变量
需要定义的变量如下
变量名称 | 变量类型 | 是否为数组 | 默认值 | 变量描述 |
---|---|---|---|---|
devices | Map | 是 | 设备原始数据列表,用来去重 | |
scaning | Bool | 否 | false | 蓝牙扫描状态 true 正在扫描 false 未扫描 |
deviceList | Map | 是 | 页面显示的设备列表 |
操作成功如下
(2)添加页面初始化动作,在右侧的属性编辑器中点击【动作】-> 【打开】
在操作流程编辑器中,页面初始化
事件下点击+
号添加事件,再点击+
号添加动作,信息如下
- 动作类型 --【自定义代码块】,添加customCode1自定义代码块并选择
操作成功如下
(3)开启顶部导航栏,点击页面编辑窗口右上角的【顶部导航栏】并开启,配置顶部导航栏背景色为 #FF006FFF
- 从【小部件面板】-> 【常用元素】中选择
文本小部件
拖入到顶部导航栏中间位置中,然后在右侧的属性编辑器中配置属性,属性信息如下:- 文本内容
蓝牙连接
- 文本颜色
#FFFFFFFF
- 文本大小
18
- 文本内容
- 从【小部件面板】-> 【常用元素】中选择
按钮小部件
拖入到顶部导航栏右侧位置中,然后在右侧的属性编辑器中配置属性,属性信息如下:- 按钮宽
40
高40
- 按钮背景颜色
#00C8C8C8
- 按钮阴影大小
0
- 按钮打开动作流程编辑器,
单击
事件下点击+
号添加事件,再点击+
号添加动作,信息如下- 动作类型 --【导航】,设置导航到
SetBleName
页面
- 动作类型 --【导航】,设置导航到
- 从【小部件面板】-> 【基本元素】中选择
图标小部件
拖入到按钮小部件
中,然后在右侧的属性编辑器中配置属性,属性信息如下:- 图标选择
setting
- 图标大小
24
- 图标颜色
#FFFFFFFF
- 图标选择
- 按钮宽
(4)页面内容设计
从【小部件面板】-> 【常用元素】中选择
容器小部件
拖入到页面编辑窗口内的上下布局中,然后在右侧的属性编辑器中配置属性,属性信息如下:宽
80
高20
背景颜色
#00C8C8C8
从【小部件面板】-> 【基本元素】中选择
雷达小部件
拖入到页面编辑窗口内的上下布局中,然后在右侧的属性编辑器中配置属性,属性信息如下:绑定变量
deviceList
宽
320
高320
雷达指针
- 开启
true
- 指针颜色
#FF00478D
- 开启
背景渐变
- 开启
true
- 渐变类型
放射性渐变
- 过渡点
颜色:#7740FAB0, 过渡点:0
颜色:#FFFFFFFF, 过渡点:1
- 渐变中心
0,0
- 渐变半径
0.5
- 开启
水波纹属性
- 水波纹个数
3
- 水波纹颜色
#1CE6ECEC
- 是否填充
true
- 水波纹个数
扫描目标属性
- 点的大小
15
- 点的颜色
#FF3B35B7
- 点的大小
操作成功如下
再次从【小部件面板】-> 【常用元素】中选择
容器小部件
拖入到页面编辑窗口内的上下布局中,然后在右侧的属性编辑器中配置属性,属性信息如下:宽
无限大
高40
背景颜色
#00C8C8C8
从【小部件面板】-> 【基本元素】中选择
条件生成器小部件
拖入到容器小部件中,然后在右侧的属性编辑器中选择变量scaning
,属性信息如下:条件
scaning = false
,勾选展示此界面
,从【小部件面板】-> 【常用元素】中选择按钮小部件
拖入到条件生成器小部件
中,然后在右侧的属性编辑器中配置属性,属性信息如下:- 按钮宽
120
高40
- 按钮背景颜色
#00C8C8C8
- 按钮阴影大小
0
- 按钮动作面板中打开动作流程编辑器,
单击
事件下点击+
号添加事件,再点击+
号添加动作,信息如下- 动作类型 --【自定义代码块】,添加customCode2自定义代码块并选择
- 从【小部件面板】-> 【常用元素】中选择
文本小部件
拖入到按钮小部件
中,然后在右侧的属性编辑器中配置属性,属性信息如下:文本内容
重新扫描
字体颜色
#FF006FFF
字体大小
18
字体粗细
500
- 按钮宽
条件
scaning = true
,勾选展示此界面
,从【小部件面板】-> 【常用元素】中选择文本小部件
拖入到条件生成器小部件
中,然后在右侧的属性编辑器中配置属性,属性信息如下:- 文本内容
正在扫描
- 文本大小
18
- 字体粗细
500
- 文本内容
操作成功如下
从【小部件面板】-> 【基本元素】中选择
滚动条小部件
拖入到页面编辑窗口内的上下布局中从【小部件面板】-> 【布局元素】中选择
列表布局小部件
拖入到滚动条小部件
中绑定变量
deviceList
宽
340
高350
操作成功如下
从【小部件面板】-> 【常用元素】中选择
容器小部件
拖入到列表布局小部件
中,然后在右侧的属性编辑器中配置属性,属性信息如下:宽
无限大
高80
背景颜色
#FFFFFFFF
圆角
10
内边距
10
外边距
上:10 下:10
从【小部件面板】-> 【常用元素】中选择
左右布局小部件
拖入到容器小部件
中从【小部件面板】-> 【常用元素】中选择
上下布局小部件
拖入到左右布局小部件
中- 拖入
容器+文本
到上下布局小部件
中,并设置- 文本内容
${deviceList[index]["name"] == '' ? '未知' : deviceList[index]["name"]}
- 字体大小
16
- 字体粗细
700
- 容器宽
120
高20
- 容器背景颜色
#00C8C8C8
- 文本内容
- 拖入
容器+文本
到上下布局小部件
中,并设置- 文本内容
Mac: ${deviceList[index]['mac']} RSSI: ${deviceList[index]["rssi"]}
- 字体颜色
#FF999999
- 字体大小
14
- 字体粗细
500
- 容器宽
260
高20
- 容器背景颜色
#00C8C8C8
- 文本内容
- 拖入
从【小部件面板】-> 【常用元素】中选择
按钮小部件
拖入到左右布局小部件
中,然后在右侧的属性编辑器中配置属性,属性信息如下:- 宽
60
高40
- 背景颜色
#00C8C8C8
阴影大小
0
按钮动作面板中打开动作流程编辑器,
单击
事件下点击+
号添加事件,再点击+
号添加动作,信息如下动作类型 --【自定义代码块】,添加customCode3自定义代码块并选择
从【小部件面板】-> 【常用元素】中选择
文本小部件
拖入到按钮小部件
中,然后在右侧的属性编辑器中配置属性,属性信息如下:文本内容
连接
字体颜色
#FF006FFF
字体大小
14
字体粗细
500
- 宽
customCode1
内容如下void function() { // 控制雷达扫描的动画 waterRippleController = AnimationController( vsync: this, duration: const Duration(seconds: 2), ); radarViewController = AnimationController( vsync: this, duration: const Duration(seconds: 5), ); // 蓝牙扫描结果处理 ble.onScanResults(callbackLast: (event) { String name = event.advertisementData.advName; // 设备名称过滤 String DEVICE_NAME = StorageUtil().read('DEVICE_NAME') ?? ''; if ((DEVICE_NAME.isNotEmpty && (name == '' || !name.contains(DEVICE_NAME))) || devices.contains(event)) { return; } // 去重操作,防止重复设备添加 devices.add(event); if (mounted) { setState(() { // 添加至设备列表 deviceList.add({ "name": event.device.platformName, "rssi": event.rssi, "mac": "mac", "raw": event }); }); } }); // 扫描状态处理 ble.isScaning((event) { if (mounted) { setState(() { scaning = event; }); if (event) { waterRippleController?.repeat(); radarViewController?.repeat(); } else { waterRippleController?.stop(); radarViewController?.stop(); } } }); // 开始扫描 ble.status(timeout: const Duration(seconds: 8)); }
function() async { EasyLoading.dismiss(); if (mounted) { // 断开蓝牙 await ble.disconnect(); setState(() { // 清空设备列表 devices.clear(); }); // 重新扫描设备 ble.status(timeout: const Duration(seconds: 8)); } }
customCode3
内容如下void function(index) { if (scaning) { ble.stopScan(); } EasyLoading.show(); // 连接蓝牙 ble.connect(deviceList[index]['raw'].device, serviceUUID: StorageUtil().read("serviceUUID") ?? '', readCharacteristicUUID: StorageUtil().read("readCharacteristicUUID") ?? '', writeCharacteristicUUID: StorageUtil().read("writeCharacteristicUUID") ?? '', notifyCallBcak: () async { Map<String, dynamic> json = { "name": deviceList[index]['name'], "id": deviceList[index]['mac'] }; await Get.toNamed('/DeviceNetWork', arguments: json); EasyLoading.dismiss(); }); }
SetBleName页面设计
页面描述
- 蓝牙名称过滤,设置BLE名称后蓝牙只搜索该名称的设备
- 读写UUID,如果不设置蓝牙的读写UUID,则默认向所有的读写UUID发送数据和接收数据
效果图

实现流程
(1)在【页面管理】中单击SetBleName
页面,在右侧的属性编辑器中添加页面变量
需要定义的变量如下
变量名称 变量类型 是否为数组 默认值 变量描述 DEVICE_NAME String 否 ${StorageUtil().read("DEVICE_NAME") ?? ''} 设备名称 serviceUUID String 否 服务UUID readCharacteristicUUID String 否 读特征UUID writeCharacteristicUUID String 否 写特征UUID
操作成功如下
(2)开启顶部导航栏,点击页面编辑窗口右上角的【顶部导航栏】并开启,配置顶部导航栏背景色为 #FF006FFF
- 从【小部件面板】-> 【常用元素】中选择
文本小部件
拖入到顶部导航栏中间位置中,然后在右侧的属性编辑器中配置属性,属性信息如下:- 文本内容
设置
- 文本颜色
#FFFFFFFF
- 文本大小
18
- 文本内容
(3)页面内容设计
从【小部件面板】-> 【常用元素】中选择
容器小部件
拖入到页面编辑窗口内的上下布局中,然后在右侧的属性编辑器中配置属性,属性信息如下:宽
无限大
高600
背景颜色
#00C8C8C8
内边距
10
从【小部件面板】-> 【常用元素】中选择
上下布局小部件
拖入到容器小部件
中从【小部件面板】-> 【常用元素】中选择
上下布局小部件
拖入到上下布局小部件
中- 从【小部件面板】-> 【常用元素】中选择
文本小部件
拖入到上下布局小部件
中,然后在右侧的属性编辑器中配置属性,属性信息如下:- 文本内容
BLE名称
- 文本内容
- 从【小部件面板】-> 【常用元素】中选择
容器小部件
拖入到上下布局小部件
中,然后在右侧的属性编辑器中配置属性,属性信息如下:- 宽
无限大
高50
- 背景颜色
#00C8C8C8
- 下边框 宽度
1
颜色#FF999999
样式一
- 从【小部件面板】-> 【表单元素】中选择
文本输入框小部件
拖入到容器小部件
中,然后在右侧的属性编辑器中配置属性,属性信息如下:- 数据绑定变量
DEVICE_NAME
- 光标颜色
#FF006FFF
- 数据绑定变量
- 操作成功如下
- 宽
- 从【小部件面板】-> 【常用元素】中选择
复制上述上下布局小部件及其子小部件的内容,并粘贴,修改内容如下
- 文本内容
服务UUID
、读特征UUID
、写特征UUID
- 绑定变量
serviceUUID
、readCharacteristicUUID
、writeCharacteristicUUID
- 文本内容
操作成功如下
从【小部件面板】-> 【常用元素】中选择
按钮小部件
拖入到上下布局小部件
中,然后在右侧的属性编辑器中配置属性,属性信息如下:从【小部件面板】-> 【常用元素】中选择
文本小部件
拖入到按钮小部件
中,然后在右侧的属性编辑器中配置属性,属性信息如下:文本内容
确认
字体颜色
#FFFFFFFF
字体大小
14
字体粗细
500
宽
无限大
高40
背景颜色
#FF006FFF
阴影大小
4
圆角大小
10
按钮动作面板中打开动作流程编辑器,
单击
事件下点击+
号添加事件,再点击+
号添加动作,信息如下- 动作类型 --【自定义代码块】,添加
customCode1
自定义代码块并选择
- 动作类型 --【自定义代码块】,添加
customCode1
内容如下
void function(){
StorageUtil().write("DEVICE_NAME", DEVICE_NAME);
StorageUtil().write("serviceUUID", serviceUUID);
StorageUtil().write("readCharacteristicUUID", readCharacteristicUUID);
StorageUtil().write("writeCharacteristicUUID", writeCharacteristicUUID);
EasyLoading.showSuccess("设置成功");
Get.back();
}
DeviceNetWork页面设计
页面描述
- 在页面初始化时,会依次执行以下操作
- 蓝牙接收数据监听,接收到数据后进行存储并重新构建页面
- 蓝牙连接状态监听,如果蓝牙断开连接,则在400ms后回到上一个页面
- 发送数据,用户在输入框中输入16进制数据后点击发送即可
效果图

实现流程
(1)在【页面管理】中单击DeviceNetWork
页面,在右侧的属性编辑器中添加页面变量
需要定义的变量如下
变量名称 | 变量类型 | 是否是列表 | 默认值 | 变量描述 |
---|---|---|---|---|
password | Map | 是 | 接收的数据内容 | |
isConnected | Bool | 否 | false | 连接状态 |
wifiname | String | 否 | 发送数据内容 | |
_getData | Var | 否 | 数据接收流 | |
_connectionSubscription | Var | 否 | 连接状态流 | |
disconnectTimer | Var | 否 | 断开连接定时器 |
(2)添加页面初始化动作,在右侧的属性编辑器中点击【动作】-> 【打开】
在操作流程编辑器中,页面初始化
事件下点击+
号添加事件,再点击+
号添加动作,信息如下
- 动作类型 --【自定义代码块】,添加
customCode1
自定义代码块并选择
customCode1
内容如下
void function(){
_connectionSubscription?.cancel();
_connectionSubscription = ble.connectController.stream.listen((event) {
if (event is BluetoothConnectionState) {
if (mounted) {
setState(() {
switch (event) {
case BluetoothConnectionState.connected:
isConnected = true;
break;
case BluetoothConnectionState.disconnected:
disconnectTimer?.cancel();
disconnectTimer = Timer(const Duration(milliseconds: 400), () {
if (connectStatus == BluetoothConnectionState.disconnected) {
//400毫秒后还是未连接才代表断开了连接,回到以前的界面
print("400毫秒后还是未连接才代表断开了连接,回到以前的界面");
EasyLoading.showError("设备断开了连接");
Get.offNamed('/');
}
});
break;
default:
}
});
}
}
});
_getData?.cancel();
_getData = ble.getBleDateController.stream.listen((event) {
if (event is List<int> && event.length != 0) {
List<int> newArr = event;
print("蓝牙发送过来的数据_netWork:$newArr");
List<String> dataArr = [];
for (var i = 0; i < newArr.length; i++) {
var element = newArr[i];
String str = '';
str = element.toRadixString(16);
str = str.length == 1 ? "0$str" : str;
dataArr.add(str);
}
password.add({
"type": "接收",
"data": dataArr.join(),
"time": DateFormat("HH:mm:ss").format(DateTime.now()),
});
setState(() {});
}
});
}
(3)开启顶部导航栏,点击页面编辑窗口右上角的【顶部导航栏】并开启,配置顶部导航栏背景色为 #FF006FFF
- 从【小部件面板】-> 【常用元素】中选择
文本小部件
拖入到顶部导航栏中间位置中,然后在右侧的属性编辑器中配置属性,属性信息如下:- 文本内容
数据收发
- 文本颜色
#FFFFFFFF
- 文本大小
18
- 文本内容
(4)页面内容设计
从【小部件面板】-> 【常用元素】中选择
容器小部件
拖入到页面编辑窗口内的上下布局中,然后在右侧的属性编辑器中配置属性,属性信息如下:宽
无限大
高700
背景颜色
#C8C8C800
内边距
10
从【小部件面板】-> 【常用元素】中选择
上下布局小部件
拖入到容器小部件
中拖入
容器+文本
到上下布局小部件
中,并设置- 文本内容
连接状态: ${isConnected?'已连接': '未连接' }
- 宽
无限大
高30
- 背景颜色
#00C8C8C8
- 文本内容
拖入
容器+文本
到上下布局小部件
中,并设置- 文本内容
数据收发内容
- 宽
无限大
高40
- 背景颜色
#00C8C8C8
- 文本内容
从【小部件面板】-> 【常用元素】中选择
容器小部件
拖入到上下布局小部件
中,然后在右侧的属性编辑器中配置属性,属性信息如下:- 宽
无限大
高300
- 背景颜色
#00C8C8C8
- 从【小部件面板】-> 【布局元素】中选择
列表布局小部件
拖入到容器小部件
中,然后在右侧的属性编辑器中配置属性,属性信息如下:- 数据变量绑定
password
- 从【小部件面板】-> 【常用元素】中选择
文本小部件
拖入到列表布局小部件
中,然后在右侧的属性编辑器中配置属性,属性信息如下:- 文本内容
${password[index]['type']}: ${password[index]['data']}
- 文本内容
- 数据变量绑定
- 宽
拖入
容器+文本
到上下布局小部件
中,并设置- 文本内容
发送数据内容
- 宽
无限大
高40
- 背景颜色
#00C8C8C8
- 文本内容
从【小部件面板】-> 【常用元素】中选择
容器小部件
拖入到上下布局小部件
中,然后在右侧的属性编辑器中配置属性,属性信息如下:- 宽
无限大
高50
- 背景颜色
#00C8C8C8
- 下边框 颜色
#FF999999
宽度1
样式一
- 从【小部件面板】-> 【表单元素】中选择
文本输入框小部件
拖入到容器小部件
中,然后在右侧的属性编辑器中配置属性,属性信息如下:- 输入框数据变量绑定
wifiname
- 输入框光标颜色
#006FFFFF
- 输入框数据变量绑定
- 宽
从【小部件面板】-> 【常用元素】中选择
按钮小部件
拖入到上下布局小部件
中,然后在右侧的属性编辑器中配置属性,属性信息如下:- 从【小部件面板】-> 【常用元素】中选择
文本小部件
拖入到按钮小部件
中,然后在右侧的属性编辑器中配置属性,属性信息如下:文本内容
发送数据
字体颜色
#FFFFFFFF
- 宽
200
高40
- 背景颜色
#FF006FFF
- 圆角
10
- 按钮动作面板中打开动作流程编辑器,
单击
事件下点击+
号添加事件,再点击+
号添加动作,信息如下- 动作类型 --【自定义代码块】,添加
customCode2
自定义代码块并选择
- 动作类型 --【自定义代码块】,添加
- 从【小部件面板】-> 【常用元素】中选择
customCode2
内容如下
void function() async {
if (wifiname == null) {
EasyLoading.showError("请输入数据".tr);
return;
}
List<int> intArray = [];
for (int i = 0; i < wifiname.length; i += 2) {
String hexPair = wifiname.substring(i, i + 2);
intArray.add(int.parse(hexPair, radix: 16));
}
password.add({"type": "发送", "data": wifiname});
setState(() {});
await ble.writeWithOut(intArray);
}