Flutter低功耗蓝牙通信插件bluetooth_low_energy的使用

Flutter低功耗蓝牙通信插件bluetooth_low_energy的使用

简介

bluetooth_low_energy 是一个Flutter插件,用于控制低功耗蓝牙(BLE),支持中央设备(Central)和外围设备(Peripheral)角色。以下是该插件的主要功能和使用方法。

CentralManager API 支持情况

API Android iOS macOS Windows Linux
logLevel ✅ ✅ ✅ ✅ ✅
state ✅ ✅ ✅ ✅ ✅
stateChanged ✅ ✅ ✅ ✅ ✅
authorize ✅ ❌ ❌ ❌ ❌
showAppSettings ✅ ✅ ❌ ❌ ❌
discovered ✅ ✅ ✅ ✅ ✅
connectionStateChanged ✅ ✅ ✅ ✅ ✅
mtuChanged ✅ ❌ ❌ ✅ ❌
characteristicNotified ✅ ✅ ✅ ✅ ✅
startDiscovery ✅ ✅ ✅ ✅ ✅
stopDiscovery ✅ ✅ ✅ ✅ ✅
retrieveConnectedPeripherals ✅ ✅ ✅ ❌ ✅
connect ✅ ✅ ✅ ✅ ✅
disconnect ✅ ✅ ✅ ✅ ✅
requestMTU ✅ ❌ ❌ ❌ ❌
getMaximumWriteLength ✅ ✅ ✅ ✅ ✅
readRSSI ✅ ✅ ✅ ❌ ✅
readCharacteristic ✅ ✅ ✅ ✅ ✅
writeCharacteristic ✅ ✅ ✅ ✅ ✅
setCharacteristicNotifyState ✅ ✅ ✅ ✅ ✅
readDescriptor ✅ ✅ ✅ ✅ ✅
writeDescriptor ✅ ✅ ✅ ✅ ✅

PeripheralManager API 支持情况

API Android iOS macOS Windows Linux
logLevel ✅ ✅ ✅ ✅ ❌
state ✅ ✅ ✅ ✅ ❌
stateChanged ✅ ✅ ✅ ✅ ❌
authorize ✅ ❌ ❌ ❌ ❌
showAppSettings ✅ ✅ ❌ ❌ ❌
connectionStateChanged ✅ ❌ ❌ ❌ ❌
mtuChanged ✅ ❌ ❌ ✅ ❌
characteristicReadRequested ✅ ✅ ✅ ✅ ❌
characteristicWriteRequested ✅ ✅ ✅ ✅ ❌
characteristicNotifyStateChanged ✅ ✅ ✅ ✅ ❌
descriptorReadRequested ✅ ❌ ❌ ✅ ❌
descriptorWriteRequested ✅ ❌ ❌ ✅ ❌
addService ✅ ✅ ✅ ✅ ❌
removeService ✅ ✅ ✅ ✅ ❌
removeAllServices ✅ ✅ ✅ ✅ ❌
startAdvertising ✅ ✅ ✅ ✅ ❌
stopAdvertising ✅ ✅ ✅ ✅ ❌
getMaximumNotifyLength ✅ ✅ ✅ ✅ ❌
respondReadRequestWithValue ✅ ✅ ✅ ✅ ❌
respondReadRequestWithError ✅ ✅ ✅ ✅ ❌
respondWriteRequest ✅ ✅ ✅ ✅ ❌
respondWriteRequestWithError ✅ ✅ ✅ ✅ ❌
notifyCharacteristic ✅ ✅ ✅ ✅ ❌

开始使用

添加依赖

在 pubspec.yaml 文件中添加 bluetooth_low_energy 依赖:

dependencies:
  bluetooth_low_energy: ^<latest-version>

注意: 低功耗蓝牙不适用于模拟器,请使用具有蓝牙功能的物理设备进行开发。

平台特定配置

Android

确保你的 android/app/build.gradle 文件中的 minSdk 设置为21或更高。

iOS 和 macOS

根据苹果文档,你必须在iOS 13及以上版本包含 NSBluetoothAlwaysUsageDescription,在iOS 13之前包含 NSBluetoothPeripheralUsageDescription。

对于macOS,开发者需要配置应用沙盒以访问受限资源。

Windows

PeripheralManager#startAdvertising 不支持 name 参数。

Linux

PeripheralManager API 尚未实现,因为 bluez 不支持此功能。

示例代码

以下是一个完整的示例应用程序,展示了如何使用 bluetooth_low_energy 插件:

import 'dart:async';
import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:bluetooth_low_energy/bluetooth_low_energy.dart';

void main() {
  runZonedGuarded(onStartUp, onCrashed);
}

void onStartUp() async {
  Logger.root.onRecord.listen(onLogRecord);
  hierarchicalLoggingEnabled = true;

  // 初始化蓝牙管理器
  final centralManager = CentralManager();
  await centralManager.startDiscovery();

  runApp(const MyApp());
}

void onCrashed(Object error, StackTrace stackTrace) {
  Logger.root.shout('App crashed.', error, stackTrace);
}

void onLogRecord(LogRecord record) {
  log(
    record.message,
    time: record.time,
    sequenceNumber: record.sequenceNumber,
    level: record.level.value,
    name: record.loggerName,
    zone: record.zone,
    error: record.error,
    stackTrace: record.stackTrace,
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'BLE Example',
      theme: ThemeData.light().copyWith(
        materialTapTargetSize: MaterialTapTargetSize.padded,
      ),
      darkTheme: ThemeData.dark().copyWith(
        materialTapTargetSize: MaterialTapTargetSize.padded,
      ),
      home: const BLEHomePage(),
    );
  }
}

class BLEHomePage extends StatefulWidget {
  const BLEHomePage({super.key});

  @override
  State<BLEHomePage> createState() => _BLEHomePageState();
}

class _BLEHomePageState extends State<BLEHomePage> {
  final CentralManager _centralManager = CentralManager();
  List<DiscoveredPeripheral> _peripherals = [];

  @override
  void initState() {
    super.initState();
    _centralManager.discovered.listen((event) {
      setState(() {
        _peripherals.add(event);
      });
    });
    _centralManager.startDiscovery();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('BLE Devices'),
      ),
      body: ListView.builder(
        itemCount: _peripherals.length,
        itemBuilder: (context, index) {
          final peripheral = _peripherals[index];
          return ListTile(
            title: Text(peripheral.name ?? 'Unknown Device'),
            subtitle: Text(peripheral.identifier),
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => DeviceDetailPage(peripheral: peripheral),
                ),
              );
            },
          );
        },
      ),
    );
  }
}

class DeviceDetailPage extends StatefulWidget {
  final DiscoveredPeripheral peripheral;

  const DeviceDetailPage({super.key, required this.peripheral});

  @override
  State<DeviceDetailPage> createState() => _DeviceDetailPageState();
}

class _DeviceDetailPageState extends State<DeviceDetailPage> {
  late StreamSubscription<ConnectionState> _connectionStateSubscription;
  bool _isConnected = false;

  @override
  void initState() {
    super.initState();
    _connectToDevice();
  }

  Future<void> _connectToDevice() async {
    try {
      await widget.peripheral.connect();
      _connectionStateSubscription = widget.peripheral.connectionStateChanged.listen((state) {
        if (mounted) {
          setState(() {
            _isConnected = state == ConnectionState.connected;
          });
        }
      });
    } catch (e) {
      log('Failed to connect: $e');
    }
  }

  @override
  void dispose() {
    _connectionStateSubscription.cancel();
    widget.peripheral.disconnect();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.peripheral.name ?? 'Unknown Device'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(_isConnected ? 'Connected' : 'Disconnected'),
            ElevatedButton(
              onPressed: _isConnected ? null : () async {
                await widget.peripheral.connect();
                setState(() {
                  _isConnected = true;
                });
              },
              child: const Text('Connect'),
            ),
            ElevatedButton(
              onPressed: _isConnected ? () async {
                await widget.peripheral.disconnect();
                setState(() {
                  _isConnected = false;
                });
              } : null,
              child: const Text('Disconnect'),
            ),
          ],
        ),
      ),
    );
  }
}

这个示例展示了如何初始化蓝牙管理器、发现设备并连接到设备。你可以根据需要扩展此代码以实现更多功能,如读取和写入特征值等。


更多关于Flutter低功耗蓝牙通信插件bluetooth_low_energy的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter低功耗蓝牙通信插件bluetooth_low_energy的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter应用中使用bluetooth_low_energy插件进行低功耗蓝牙通信的示例代码。这个示例包括扫描设备、连接到设备、读取和写入特征值的基本操作。

首先,确保你的Flutter项目中已经添加了bluetooth_low_energy插件。你可以在你的pubspec.yaml文件中添加以下依赖:

dependencies:
  flutter:
    sdk: flutter
  bluetooth_low_energy: ^0.10.0  # 请确保使用最新版本

然后运行flutter pub get来安装依赖。

接下来是示例代码:

import 'package:flutter/material.dart';
import 'package:bluetooth_low_energy/bluetooth_low_energy.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: BluetoothScreen(),
    );
  }
}

class BluetoothScreen extends StatefulWidget {
  @override
  _BluetoothScreenState createState() => _BluetoothScreenState();
}

class _BluetoothScreenState extends State<BluetoothScreen> {
  final BleManager bleManager = BleManager();
  List<DiscoveredDevice> devices = [];
  ConnectedDevice? connectedDevice;

  @override
  void initState() {
    super.initState();
    initBluetooth();
  }

  Future<void> initBluetooth() async {
    await bleManager.initialize();
    startScanning();
  }

  Future<void> startScanning() async {
    bleManager.startScanning().listen((scanResult) {
      setState(() {
        devices = devices.filter((device) => device.id != scanResult.device.id).toList();
        devices.add(scanResult.device);
      });
    }).onDone(() {
      print("Scanning stopped.");
    });
  }

  Future<void> connectToDevice(DiscoveredDevice device) async {
    connectedDevice = await device.connect();
    print("Connected to ${connectedDevice!.id}");
    await readCharacteristic(connectedDevice!);
  }

  Future<void> readCharacteristic(ConnectedDevice device) async {
    final service = await device.discoverServices();
    final characteristic = service.characteristics.firstOrNull;
    if (characteristic != null) {
      final value = await characteristic.read();
      print("Characteristic value: ${value.toHex()}");
    }
  }

  Future<void> writeCharacteristic(ConnectedDevice device, Uint8List data) async {
    final service = await device.discoverServices();
    final characteristic = service.characteristics.firstOrNull;
    if (characteristic != null) {
      await characteristic.write(data);
      print("Characteristic written: ${data.toHex()}");
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Bluetooth Low Energy Example'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            Text('Discovered Devices:'),
            Expanded(
              child: ListView.builder(
                itemCount: devices.length,
                itemBuilder: (context, index) {
                  final device = devices[index];
                  return ListTile(
                    title: Text(device.name ?? 'Unknown'),
                    subtitle: Text(device.id),
                    onTap: () => connectToDevice(device),
                  );
                },
              ),
            ),
            if (connectedDevice != null) {
              Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text('Connected Device:'),
                  Text(connectedDevice!.id),
                  ElevatedButton(
                    onPressed: () async {
                      final data = Uint8List.fromList([0x01, 0x02, 0x03]);
                      await writeCharacteristic(connectedDevice!, data);
                    },
                    child: Text('Write Characteristic'),
                  ),
                ],
              )
            }
          ],
        ),
      ),
    );
  }
}

说明

  1. 初始化蓝牙:在initState方法中调用bleManager.initialize()来初始化蓝牙。
  2. 扫描设备:调用bleManager.startScanning()开始扫描附近的蓝牙设备,并将扫描到的设备添加到devices列表中。
  3. 连接设备:点击列表中的设备项时,调用connectToDevice方法连接到该设备。
  4. 读取特征值:连接成功后,调用readCharacteristic方法读取第一个特征值(示例中假设只有一个特征值)。
  5. 写入特征值:提供一个按钮,点击后调用writeCharacteristic方法向特征值写入数据。

注意事项

  • 确保在AndroidManifest.xml和Info.plist中添加了必要的蓝牙权限。
  • 在实际使用中,可能需要处理更多的错误情况和边缘情况,例如设备连接失败、特征值读取/写入失败等。
  • bluetooth_low_energy插件的API可能会随着版本更新而变化,请参考最新的官方文档。

希望这个示例代码能帮助你理解如何在Flutter中使用bluetooth_low_energy插件进行低功耗蓝牙通信。

回到顶部