Flutter蓝牙通信插件flutter_ble_central的使用

发布于 1周前 作者 nodeper 来自 Flutter

Flutter蓝牙通信插件flutter_ble_central的使用

flutter_ble_central

一个用于在中心模式下扫描蓝牙低功耗(BLE)数据的Flutter插件。

开始使用

这个项目是一个Flutter插件包的起点,它包含针对Android和/或iOS平台的特定平台实现代码。

要开始使用Flutter,请查看我们的在线文档,其中包含教程、示例、移动开发指南以及完整的API引用。

示例代码

以下是使用flutter_ble_central插件的基本示例:

import 'dart:async';

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

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

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Map<String, ScanResult> devices = {};
  bool isScanning = false;
  int packetsFound = 0;
  int? queue = 0;

  [@override](/user/override)
  void initState() {
    super.initState();

    Timer.periodic(const Duration(seconds: 1), (timer) {
      setState(() {
        debugPrint('Packets found: $packetsFound, in queue $queue');
      });
    });

    FlutterBleCentral().onScanError?.listen((event) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text(
            '错误: ${AndroidError.values[event]}, code: $event',
          ),
        ),
      );
      debugPrint('Error: ${AndroidError.values[event]}, code: $event');
    });

    FlutterBleCentral().onScanResult.listen((event) {
      packetsFound++;
    });
  }

  Future<void> _requestPermissions() async {
    final hasPermission = await FlutterBleCentral().hasPermission();
    switch (hasPermission) {
      case BluetoothCentralState.denied:
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            backgroundColor: Colors.red,
            content: Text(
              "我们没有权限,现在请求!",
            ),
          ),
        );

        await _requestPermissions();
        break;
      default:
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            backgroundColor: Colors.green,
            content: Text(
              '状态: $hasPermission!',
            ),
          ),
        );
        break;
    }
  }

  final _messangerKey = GlobalKey<ScaffoldMessengerState>();

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      scaffoldMessengerKey: _messangerKey,
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Flutter BLE Central 示例'),
          actions: <Widget>[
            IconButton(
              onPressed: () => setState(() {
                FlutterBleCentral().stop();
              }),
              icon: const Icon(Icons.lock_reset),
            ),
            IconButton(
              onPressed: _requestPermissions,
              icon: const Icon(Icons.security),
            ),
            if (isScanning)
              IconButton(
                icon: const Icon(Icons.pause_circle_filled),
                onPressed: () => setState(() {
                  isScanning = false;
                  FlutterBleCentral().stop();
                }),
              )
            else
              IconButton(
                icon: const Icon(Icons.play_arrow),
                onPressed: () async {
                  final messenger = _messangerKey.currentState!;
                  final state = await FlutterBleCentral().start();
                  switch (state) {
                    case BluetoothCentralState.ready:
                    case BluetoothCentralState.granted:
                      setState(() {
                        isScanning = true;
                        devices.clear();
                      });
                      break;
                    case BluetoothCentralState.denied:
                      messenger.showSnackBar(
                        const SnackBar(
                          content: Text(
                            '蓝牙被拒绝,我们可以再次请求!',
                          ),
                        ),
                      );
                      break;
                    case BluetoothCentralState.permanentlyDenied:
                      messenger.showSnackBar(
                        const SnackBar(
                          content: Text(
                            '蓝牙被永久拒绝,我们不能再请求!',
                          ),
                        ),
                      );
                      break;
                    case BluetoothCentralState.restricted:
                      // TODO: 处理这种情况。
                      break;
                    case BluetoothCentralState.limited:
                      // TODO: 处理这种情况。
                      break;
                    case BluetoothCentralState.turnedOff:
                      messenger.showSnackBar(
                        const SnackBar(
                          content: Text(
                            '蓝牙已关闭。',
                          ),
                        ),
                      );
                      break;
                    case BluetoothCentralState.unsupported:
                      messenger.showSnackBar(
                        const SnackBar(
                          content: Text(
                            '设备不支持蓝牙。',
                          ),
                        ),
                      );
                      break;
                    case BluetoothCentralState.unknown:
                      messenger.showSnackBar(
                        const SnackBar(
                          content: Text(
                            '未知错误..',
                          ),
                        ),
                      );
                      break;
                  }
                },
              ),
          ],
        ),
        body: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            ElevatedButton(
              onPressed: () async {
                if (isScanning) {
                  FlutterBleCentral().stop();
                  isScanning = false;
                } else {
                  isScanning = true;
                  devices.clear();
                  FlutterBleCentral().start(
                    scanSettings: ScanSettings(
                      scanMode: ScanMode.scanModeLowLatency,
                    ),
                  );
                  await Future.delayed(
                    const Duration(
                      seconds: 30,
                    ),
                  );
                  FlutterBleCentral().stop();
                  isScanning = false;
                }
              },
              child: const Text('30秒测试'),
            ),
            ElevatedButton(
              onPressed: () => FlutterBleCentral().openBluetoothSettings(),
              child: const Text('蓝牙设置'),
            ),
            ElevatedButton(
              onPressed: () => FlutterBleCentral().openAppSettings(),
              child: const Text('应用设置'),
            ),
            Text('找到的数据包: $packetsFound, 队列中: $queue'),
            ListView.separated(
              shrinkWrap: true,
              padding: const EdgeInsets.all(8),
              itemBuilder: (BuildContext context, int index) {
                final scanResult = devices.values.elementAt(index);
                return Card(
                  child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Row(
                      children: <Widget>[
                        const Icon(Icons.bluetooth),
                        Expanded(
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: <Widget>[
                              Text('${scanResult.scanRecord?.deviceName}'),
                              Text('${scanResult.device?.address}'),
                              Text('RSSI: ${scanResult.rssi}'),
                            ],
                          ),
                        ),
                      ],
                    ),
                  ),
                );
              },
              separatorBuilder: (context, index) => const SizedBox(height: 5),
              itemCount: devices.length,
            ),
          ],
        ),
      ),
    );
  }
}

代码解释

  1. 导入必要的库

    import 'dart:async';
    
    import 'package:flutter/material.dart';
    import 'package:flutter_ble_central/flutter_ble_central.dart';
    
  2. 初始化应用

    void main() {
      runApp(const MyApp());
    }
    
  3. 定义主应用状态

    class MyApp extends StatefulWidget {
      const MyApp({Key? key}) : super(key: key);
    
      [@override](/user/override)
      State<MyApp> createState() => _MyAppState();
    }
    
  4. 处理蓝牙扫描结果

    class _MyAppState extends State<MyApp> {
      Map<String, ScanResult> devices = {};
      bool isScanning = false;
      int packetsFound = 0;
      int? queue = 0;
    
      [@override](/user/override)
      void initState() {
        super.initState();
    
        Timer.periodic(const Duration(seconds: 1), (timer) {
          setState(() {
            debugPrint('Packets found: $packetsFound, in queue $queue');
          });
        });
    
        FlutterBleCentral().onScanError?.listen((event) {
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(
              content: Text(
                '错误: ${AndroidError.values[event]}, code: $event',
              ),
            ),
          );
          debugPrint('Error: ${AndroidError.values[event]}, code: $event');
        });
    
        FlutterBleCentral().onScanResult.listen((event) {
          packetsFound++;
        });
      }
    
  5. 请求权限

    Future<void> _requestPermissions() async {
      final hasPermission = await FlutterBleCentral().hasPermission();
      switch (hasPermission) {
        case BluetoothCentralState.denied:
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(
              backgroundColor: Colors.red,
              content: Text(
                "我们没有权限,现在请求!",
              ),
            ),
          );
    
          await _requestPermissions();
          break;
        default:
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(
              backgroundColor: Colors.green,
              content: Text(
                '状态: $hasPermission!',
              ),
            ),
          );
          break;
      }
    }
    
  6. 构建UI

    final _messangerKey = GlobalKey<ScaffoldMessengerState>();
    
    [@override](/user/override)
    Widget build(BuildContext context) {
      return MaterialApp(
        scaffoldMessengerKey: _messangerKey,
        home: Scaffold(
          appBar: AppBar(
            title: const Text('Flutter BLE Central 示例'),
            actions: <Widget>[
              IconButton(
                onPressed: () => setState(() {
                  FlutterBleCentral().stop();
                }),
                icon: const Icon(Icons.lock_reset),
              ),
              IconButton(
                onPressed: _requestPermissions,
                icon: const Icon(Icons.security),
              ),
              if (isScanning)
                IconButton(
                  icon: const Icon(Icons.pause_circle_filled),
                  onPressed: () => setState(() {
                    isScanning = false;
                    FlutterBleCentral().stop();
                  }),
                )
              else
                IconButton(
                  icon: const Icon(Icons.play_arrow),
                  onPressed: () async {
                    final messenger = _messangerKey.currentState!;
                    final state = await FlutterBleCentral().start();
                    switch (state) {
                      case BluetoothCentralState.ready:
                      case BluetoothCentralState.granted:
                        setState(() {
                          isScanning = true;
                          devices.clear();
                        });
                        break;
                      case BluetoothCentralState.denied:
                        messenger.showSnackBar(
                          const SnackBar(
                            content: Text(
                              '蓝牙被拒绝,我们可以再次请求!',
                            ),
                          ),
                        );
                        break;
                      case BluetoothCentralState.permanentlyDenied:
                        messenger.showSnackBar(
                          const SnackBar(
                            content: Text(
                              '蓝牙被永久拒绝,我们不能再请求!',
                            ),
                          ),
                        );
                        break;
                      case BluetoothCentralState.restricted:
                        // TODO: 处理这种情况。
                        break;
                      case BluetoothCentralState.limited:
                        // TODO: 处理这种情况。
                        break;
                      case BluetoothCentralState.turnedOff:
                        messenger.showSnackBar(
                          const SnackBar(
                            content: Text(
                              '蓝牙已关闭。',
                            ),
                          ),
                        );
                        break;
                      case BluetoothCentralState.unsupported:
                        messenger.showSnackBar(
                          const SnackBar(
                            content: Text(
                              '设备不支持蓝牙。',
                            ),
                          ),
                        );
                        break;
                      case BluetoothCentralState.unknown:
                        messenger.showSnackBar(
                          const SnackBar(
                            content: Text(
                              '未知错误..',
                            ),
                          ),
                        );
                        break;
                    }
                  },
                ),
            ],
          ),
          body: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              ElevatedButton(
                onPressed: () async {
                  if (isScanning) {
                    FlutterBleCentral().stop();
                    isScanning = false;
                  } else {
                    isScanning = true;
                    devices.clear();
                    FlutterBleCentral().start(
                      scanSettings: ScanSettings(
                        scanMode: ScanMode.scanModeLowLatency,
                      ),
                    );
                    await Future.delayed(
                      const Duration(
                        seconds: 30,
                      ),
                    );
                    FlutterBleCentral().stop();
                    isScanning = false;
                  }
                },
                child: const Text('30秒测试'),
              ),
              ElevatedButton(
                onPressed: () => FlutterBleCentral().openBluetoothSettings(),
                child: const Text('蓝牙设置'),
              ),
              ElevatedButton(
                onPressed: () => FlutterBleCentral().openAppSettings(),
                child: const Text('应用设置'),
              ),
              Text('找到的数据包: $packetsFound, 队列中: $queue'),
              ListView.separated(
                shrinkWrap: true,
                padding: const EdgeInsets.all(8),
                itemBuilder: (BuildContext context, int index) {
                  final scanResult = devices.values.elementAt(index);
                  return Card(
                    child: Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: Row(
                        children: <Widget>[
                          const Icon(Icons.bluetooth),
                          Expanded(
                            child: Column(
                              crossAxisAlignment: CrossAxisAlignment.start,
                              children: <Widget>[
                                Text('${scanResult.scanRecord?.deviceName}'),
                                Text('${scanResult.device?.address}'),
                                Text('RSSI: ${scanResult.rssi}'),
                              ],
                            ),
                          ),
                        ],
                      ),
                    ),
                  );
                },
                separatorBuilder: (context, index) => const SizedBox(height: 5),
                itemCount: devices.length,
              ),
            ],
          ),
        ),
      );
    }
    

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

1 回复

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


当然,以下是一个关于如何使用 flutter_ble_central 插件进行蓝牙通信的示例代码。这个示例展示了如何扫描设备、连接到设备以及读写蓝牙特征值。

首先,确保你已经在 pubspec.yaml 文件中添加了 flutter_ble_central 依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_ble_central: ^2.0.0 # 请根据需要检查最新版本

然后,运行 flutter pub get 来获取依赖。

接下来是主要的 Dart 代码示例:

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

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  FlutterBleCentral _flutterBleCentral = FlutterBleCentral();
  List<DiscoveredDevice> _devices = [];
  ConnectedDevice? _connectedDevice;
  Characteristic? _characteristic;

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

  Future<void> initBle() async {
    // 初始化 Bluetooth 适配器
    bool isBluetoothAvailable = await _flutterBleCentral.isBluetoothAvailable();
    if (!isBluetoothAvailable) {
      // 处理蓝牙不可用的情况
      return;
    }

    bool isBluetoothEnabled = await _flutterBleCentral.isBluetoothEnabled();
    if (!isBluetoothEnabled) {
      // 请求用户开启蓝牙
      bool result = await _flutterBleCentral.requestBluetoothEnable();
      if (!result) {
        // 用户拒绝开启蓝牙
        return;
      }
    }

    // 开始扫描设备
    _flutterBleCentral.scanForDevices(timeout: Duration(seconds: 5)).listen(
      (List<DiscoveredDevice> result) {
        setState(() {
          _devices = result;
        });
      },
      onError: (dynamic error) {
        print('Scan error: $error');
      },
      onDone: () {
        print('Scan done.');
      },
    );
  }

  Future<void> connectToDevice(DiscoveredDevice device) async {
    _connectedDevice = await _flutterBleCentral.connectToDevice(device.id);
    if (_connectedDevice != null) {
      // 获取服务
      List<BluetoothService> services = await _connectedDevice!.discoverServices();
      services.forEach((service) {
        // 获取特征值
        service.characteristics.forEach((characteristic) {
          setState(() {
            _characteristic = characteristic;
          });
          // 可以在这里根据 UUID 筛选需要的特征值
        });
      });
    }
  }

  Future<void> readCharacteristic() async {
    if (_characteristic != null && _connectedDevice != null) {
      List<int> value = await _connectedDevice!.readCharacteristic(_characteristic!.uuid);
      print('Characteristic value: ${bytesToHex(value)}');
    }
  }

  Future<void> writeCharacteristic(List<int> value) async {
    if (_characteristic != null && _connectedDevice != null) {
      await _connectedDevice!.writeCharacteristic(_characteristic!.uuid, value);
      print('Characteristic written.');
    }
  }

  String bytesToHex(List<int> bytes) {
    return bytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter BLE Example'),
        ),
        body: Column(
          children: [
            Expanded(
              child: ListView.builder(
                itemCount: _devices.length,
                itemBuilder: (context, index) {
                  return ListTile(
                    title: Text(_devices[index].name ?? 'Unknown Device'),
                    subtitle: Text(_devices[index].id),
                    onTap: () {
                      connectToDevice(_devices[index]);
                    },
                  );
                },
              ),
            ),
            ElevatedButton(
              onPressed: _connectedDevice != null ? () => readCharacteristic() : null,
              child: Text('Read Characteristic'),
            ),
            ElevatedButton(
              onPressed: _connectedDevice != null ? () => writeCharacteristic([0x01, 0x02, 0x03]) : null,
              child: Text('Write Characteristic'),
            ),
          ],
        ),
      ),
    );
  }
}

解释

  1. 依赖初始化:在 pubspec.yaml 中添加 flutter_ble_central 依赖,并运行 flutter pub get

  2. Bluetooth 初始化:在 initBle 方法中检查蓝牙是否可用和已启用,并在必要时请求用户开启蓝牙。

  3. 扫描设备:使用 _flutterBleCentral.scanForDevices 方法开始扫描设备,并将扫描到的设备存储在 _devices 列表中。

  4. 连接设备:在 connectToDevice 方法中,根据设备 ID 连接到设备,并发现服务及其特征值。

  5. 读写特征值:在 readCharacteristicwriteCharacteristic 方法中,分别读取和写入特征值。

  6. UI:在 build 方法中构建一个简单的 UI,显示扫描到的设备列表,并提供按钮来读取和写入特征值。

这个示例展示了基本的蓝牙通信流程,你可以根据具体需求进一步扩展和修改代码。

回到顶部