AiFlutter 文档AiFlutter 文档
入门指南
更新日志
官网
市场
社区
低代码平台
GitHub
入门指南
更新日志
官网
市场
社区
低代码平台
GitHub
  • 入门指南

    • AiFlutter 简介
      • 产品介绍
    • 快速开始
    • 工作空间概览

      • 工作台
      • 进入工作台
      • 工作台结构
      • 账户设置
      • 订单中心
      • 项目
      • 团队
      • 资源
    • 操作界面说明

      • 操作界面简介
      • 素材管理
      • 日志管理
      • 主题设置
      • App设置
      • 小部件面板
      • 自定义组件
      • 页面管理
      • 页面编辑窗口
      • 流程图
    • 组件介绍

      • 页面布局
      • 内容展示
      • 动画图表
      • 交互行为
      • 表单元素
      • 页面导航
      • 系统工具
    • 集成硬件
    • API管理
    • 数据库
    • 自定义管理
    • iOS软件包上传TestFlight并测试
    • 实践案例

      • 老板要求两天开发一个App,半天搞定!!!
      • 一个小时搞定蓝牙调试助手!!!
      • 一个小时搞定串口调试助手!!!

一个小时搞定蓝牙调试助手!!!

项目介绍

      蓝牙调试助手是一个用于蓝牙低功耗(BLE)设备开发和调试的移动应用程序,旨在帮助开发者更高效地进行蓝牙相关项目的调试和分析。

主要功能包括:

  1. 蓝牙数据捕获:实时捕获蓝牙设备之间的通信数据,包括连接状态、传输数据等。
  2. 数据包分析:解析蓝牙数据包,显示详细信息如信号强度、设备地址、数据内容等。
  3. 设备管理:支持对蓝牙设备的扫描、连接、数据收发和断开操作。
  4. 实时监控:提供实时的蓝牙设备状态监控,帮助开发者快速定位问题。
  5. 配置管理:支持对蓝牙设备的配置参数进行调整和管理。

该工具以图形化界面呈现,操作简单,适用于需要进行蓝牙通信测试和调试的场景。

平台支持

  • Android
  • iOS

AiFlutter市场链接:蓝牙调试助手App

平台实现步骤

1. 注册登录

打开 低代码平台登录网页 ,使用微信快捷登录或者扫描二维码登录。

2. 创建项目

  1. 点击【新增项目】->【手动添加】,在平台内部创建项目
  2. 在跳出的弹窗中输入项目名称、项目描述,建议结合项目功能描述命名,便于检索
  3. 输入完成后点击确定

image-20250118152434169

3. 创建页面

(1)点击已经创建好的项目进入到操作界面,默认会存在一个HomePage页面,操作界面相关详情可查看教程 操作界面

(2)创建三个页面 AddBleDevice、SetBleName、DeviceNetWork

  1. 点击【添加页面】 -> 【创建页面】
  2. 在跳出的弹窗中输入 页面名称、页面描述
  3. 最后点击确定即可

image-20250118155246547

image-20250118155641965

(4)删除HomePage页面,在【页面管理】中右击要删除的页面,并点击【删除】

image-20250410185457201

(5)设置AddBleDevice为主页面,在【页面管理】中单击要删除的页面,并在右侧的属性编辑器中设置页面路由为/

image-20250410190123835

4. 页面设计

AddBleDevice页面设计

页面描述

  • 在页面初始化时,会依次执行以下操作
    1. 监听蓝牙扫描状态,接收到状态变化后重新构建页面
    2. 蓝牙扫描结果监听,接收到扫描结果后进行存储并重新构建页面
    3. 开始蓝牙扫描,扫描时长8秒
  • 连接设备,在设备列表中选择设备进行连接,连接成功后跳转到数据收发页面
  • 重新扫描,蓝牙扫描结束后,点击【重新扫描】开始扫描,此时会断开已连接的蓝牙设备

效果图

实现流程

(1)在【页面管理】中单击AddBleDevice页面,在右侧的属性编辑器中添加页面变量

需要定义的变量如下

变量名称变量类型是否为数组默认值变量描述
devicesMap是设备原始数据列表,用来去重
scaningBool否false蓝牙扫描状态 true 正在扫描 false 未扫描
deviceListMap是页面显示的设备列表

image-20250410191347625

操作成功如下

image-20250418182149320

(2)添加页面初始化动作,在右侧的属性编辑器中点击【动作】-> 【打开】

image-20250410193134494

在操作流程编辑器中,页面初始化 事件下点击+号添加事件,再点击+号添加动作,信息如下

  • 动作类型 --【自定义代码块】,添加customCode1自定义代码块并选择

操作成功如下

image-20250418183408977

(3)开启顶部导航栏,点击页面编辑窗口右上角的【顶部导航栏】并开启,配置顶部导航栏背景色为 #FF006FFF

image-20250410195228700

  • 从【小部件面板】-> 【常用元素】中选择文本小部件拖入到顶部导航栏中间位置中,然后在右侧的属性编辑器中配置属性,属性信息如下:
    • 文本内容蓝牙连接
    • 文本颜色#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
    • 操作成功如下

    • image-20250418184739272

  • 再次从【小部件面板】-> 【常用元素】中选择容器小部件 拖入到页面编辑窗口内的上下布局中,然后在右侧的属性编辑器中配置属性,属性信息如下:

    • 宽 无限大 高40

    • 背景颜色#00C8C8C8

    • 从【小部件面板】-> 【基本元素】中选择 条件生成器小部件 拖入到容器小部件中,然后在右侧的属性编辑器中选择变量scaning,属性信息如下:

      • 条件 scaning = false,勾选展示此界面,从【小部件面板】-> 【常用元素】中选择按钮小部件拖入到条件生成器小部件中,然后在右侧的属性编辑器中配置属性,属性信息如下:

        • 按钮宽 120 高40
        • 按钮背景颜色#00C8C8C8
        • 按钮阴影大小0
        • 按钮动作面板中打开动作流程编辑器,单击 事件下点击+号添加事件,再点击+号添加动作,信息如下
          • 动作类型 --【自定义代码块】,添加customCode2自定义代码块并选择
        • 从【小部件面板】-> 【常用元素】中选择文本小部件拖入到按钮小部件中,然后在右侧的属性编辑器中配置属性,属性信息如下:
          • 文本内容 重新扫描

          • 字体颜色 #FF006FFF

          • 字体大小 18

          • 字体粗细 500

      • 条件 scaning = true,勾选展示此界面,从【小部件面板】-> 【常用元素】中选择文本小部件拖入到条件生成器小部件中,然后在右侧的属性编辑器中配置属性,属性信息如下:

        • 文本内容 正在扫描
        • 文本大小 18
        • 字体粗细 500
      • 操作成功如下

      • image-20250418185506985

  • 从【小部件面板】-> 【基本元素】中选择滚动条小部件拖入到页面编辑窗口内的上下布局中

  • 从【小部件面板】-> 【布局元素】中选择列表布局小部件拖入到滚动条小部件中

    • 绑定变量 deviceList

    • 宽340 高350

    • 操作成功如下

    • image-20250418190250979

      • 从【小部件面板】-> 【常用元素】中选择容器小部件拖入到列表布局小部件中,然后在右侧的属性编辑器中配置属性,属性信息如下:

        • 宽无限大 高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

        操作成功如下

        image-20250418190354569

        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));
          }

        customCode2内容如下

        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_NAMEString否${StorageUtil().read("DEVICE_NAME") ?? ''}设备名称
    serviceUUIDString否服务UUID
    readCharacteristicUUIDString否读特征UUID
    writeCharacteristicUUIDString否写特征UUID

操作成功如下

image-20250418191036518

(2)开启顶部导航栏,点击页面编辑窗口右上角的【顶部导航栏】并开启,配置顶部导航栏背景色为 #FF006FFF

  • 从【小部件面板】-> 【常用元素】中选择文本小部件拖入到顶部导航栏中间位置中,然后在右侧的属性编辑器中配置属性,属性信息如下:
    • 文本内容设置
    • 文本颜色#FFFFFFFF
    • 文本大小18

(3)页面内容设计

  • 从【小部件面板】-> 【常用元素】中选择容器小部件拖入到页面编辑窗口内的上下布局中,然后在右侧的属性编辑器中配置属性,属性信息如下:

    • 宽 无限大 高600

    • 背景颜色#00C8C8C8

    • 内边距10

    • 从【小部件面板】-> 【常用元素】中选择上下布局小部件拖入到容器小部件中

      • 从【小部件面板】-> 【常用元素】中选择上下布局小部件拖入到上下布局小部件中

        • 从【小部件面板】-> 【常用元素】中选择文本小部件拖入到上下布局小部件中,然后在右侧的属性编辑器中配置属性,属性信息如下:
          • 文本内容BLE名称
        • 从【小部件面板】-> 【常用元素】中选择容器小部件拖入到上下布局小部件中,然后在右侧的属性编辑器中配置属性,属性信息如下:
          • 宽 无限大 高50
          • 背景颜色#00C8C8C8
          • 下边框 宽度 1 颜色 #FF999999 样式 一
          • 从【小部件面板】-> 【表单元素】中选择文本输入框小部件拖入到容器小部件中,然后在右侧的属性编辑器中配置属性,属性信息如下:
            • 数据绑定变量 DEVICE_NAME
            • 光标颜色#FF006FFF
          • 操作成功如下
          • image-20250418191418691
      • 复制上述上下布局小部件及其子小部件的内容,并粘贴,修改内容如下

        • 文本内容 服务UUID 、读特征UUID 、写特征UUID
        • 绑定变量 serviceUUID 、readCharacteristicUUID 、writeCharacteristicUUID
      • 操作成功如下

      • image-20250418191318948

      • 从【小部件面板】-> 【常用元素】中选择按钮小部件拖入到上下布局小部件中,然后在右侧的属性编辑器中配置属性,属性信息如下:

        • 从【小部件面板】-> 【常用元素】中选择文本小部件拖入到按钮小部件中,然后在右侧的属性编辑器中配置属性,属性信息如下:

          • 文本内容 确认

          • 字体颜色 #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页面设计

页面描述

  • 在页面初始化时,会依次执行以下操作
    1. 蓝牙接收数据监听,接收到数据后进行存储并重新构建页面
    2. 蓝牙连接状态监听,如果蓝牙断开连接,则在400ms后回到上一个页面
  • 发送数据,用户在输入框中输入16进制数据后点击发送即可

效果图

实现流程

(1)在【页面管理】中单击DeviceNetWork页面,在右侧的属性编辑器中添加页面变量

需要定义的变量如下

变量名称变量类型是否是列表默认值变量描述
passwordMap是接收的数据内容
isConnectedBool否false连接状态
wifinameString否发送数据内容
_getDataVar否数据接收流
_connectionSubscriptionVar否连接状态流
disconnectTimerVar否断开连接定时器

(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);
}
上次更新:
上一篇
老板要求两天开发一个App,半天搞定!!!
下一篇
一个小时搞定串口调试助手!!!