You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter中实现蓝牙Beacon(BLE)的扫描与数据传输

Flutter 实现 BLE Beacon 扫描与设备间数据传输教程

前置依赖配置

首先选用目前维护活跃的flutter_blue_plus库实现BLE相关能力:

  1. 在pubspec.yaml中添加依赖
dependencies:
  flutter_blue_plus: ^1.13.3 # 可替换为最新稳定版
  1. 平台权限配置
  • Android端:在android/app/src/main/AndroidManifest.xml中添加权限声明,适配不同系统版本:
<!-- Android 11及以下 -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" />
<!-- Android 12及以上 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
  • iOS端:在ios/Runner/Info.plist中添加权限描述:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>需要使用蓝牙进行设备连接与数据传输</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>需要位置权限扫描蓝牙设备</string>

Beacon 扫描实现

扫描前先判断蓝牙适配器状态,再开启扫描匹配目标Beacon设备:

import 'dart:convert';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';

// 初始化先检查蓝牙是否开启
Future<void> checkBluetoothState() async {
  final adapterState = await FlutterBluePlus.adapterState.first;
  if (adapterState != BluetoothAdapterState.on) {
    // 此处添加引导用户开启蓝牙的逻辑
    return;
  }
  startBeaconScan();
}

// 开启Beacon扫描
void startBeaconScan() {
  // 可指定过滤规则,仅扫描匹配预设服务UUID的Beacon,减少无效结果
  FlutterBluePlus.startScan(
    timeout: const Duration(seconds: 15),
    // withServices: [Guid("你预设的Beacon服务UUID")]
  );

  // 监听扫描结果
  final scanListener = FlutterBluePlus.scanResults.listen((scanResults) {
    for (final result in scanResults) {
      final deviceName = result.device.name.isNotEmpty ? result.device.name : "未知设备";
      final rssi = result.rssi;
      final broadcastData = result.advertisementData;

      // 解析iBeacon格式的广播数据,匹配目标设备
      if (broadcastData.manufacturerData.containsKey(0x004C)) { // 苹果iBeacon厂商ID
        final beaconPayload = broadcastData.manufacturerData[0x004C]!;
        // 可以提取major、minor字段匹配你的目标Beacon
        if (deviceName == "目标设备名") {
          FlutterBluePlus.stopScan();
          connectTargetDevice(result.device);
          break;
        }
      }
    }
  });
}

两台设备连接与数据传输

扫描到目标设备后建立连接,通过预设的BLE特征值实现双向数据传输,注意两台设备需要提前约定统一的服务UUID、读特征UUID、写特征UUID:

// 连接目标设备并开启数据传输
Future<void> connectTargetDevice(BluetoothDevice device) async {
  try {
    // 建立连接
    await device.connect(timeout: const Duration(seconds: 10));
    // 发现设备所有服务
    final services = await device.discoverServices();
    
    // 匹配预设的传输服务
    final targetService = services.firstWhere(
      (service) => service.uuid == Guid("你预设的服务UUID")
    );

    // 匹配读写特征
    final writeChar = targetService.characteristics.firstWhere(
      (char) => char.uuid == Guid("你预设的写特征UUID")
    );
    final readChar = targetService.characteristics.firstWhere(
      (char) => char.uuid == Guid("你预设的读特征UUID")
    );

    // 开启监听,接收对端设备发送的数据
    await readChar.setNotifyValue(true);
    readChar.value.listen((receivedBytes) {
      final receivedText = utf8.decode(receivedBytes);
      print("接收到数据:$receivedText");
    });

    // 向对端设备发送数据
    await writeChar.write(utf8.encode("要传输的测试数据"));

    // 单次数据超过20字节时,先协商更大的MTU
    // await device.requestMtu(512);

  } catch (e) {
    print("连接或传输失败:$e");
    // 异常时断开连接释放资源
    await device.disconnect();
  }
}

注意事项

  • 不需要使用蓝牙时,及时调用device.disconnect()断开连接、FlutterBluePlus.stopScan()停止扫描,避免资源占用
  • Beacon广播本身是无连接通信方式,如果仅需要传输极少量标识类数据,可以直接解析广播包的厂商数据字段,不需要建立连接
  • iOS端对后台蓝牙扫描限制较多,需要在Xcode中开启后台蓝牙权限才能在后台扫描设备

内容的提问来源于stack exchange,提问作者Rahul Raj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.10 04:09:00