Flutter蓝牙通信插件flutter_reactive_ble的使用

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

Flutter蓝牙通信插件flutter_reactive_ble的使用

简介

Pub

flutter_reactive_ble 是一个用于处理多个设备BLE(Bluetooth Low Energy)操作的Flutter库。

功能特性

  • BLE设备发现
  • 监听主机设备BLE状态
  • 建立BLE连接
  • 维护多个BLE设备的连接状态
  • 发现服务(将隐式进行)
  • 读取/写入特征值
  • 订阅特征值变化
  • 清除GATT缓存
  • 协商MTU大小

入门指南

Android配置

AndroidManifest.xml中添加以下权限:

<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="30" />

如果使用BLUETOOTH_SCAN来确定位置,修改AndroidManfiest.xml文件以包含以下条目:

<uses-permission android:name="android.permission.BLUETOOTH_SCAN" 
                 tools:remove="android:usesPermissionFlags"
                 tools:targetApi="s" />

如果应用中使用了定位服务,则从定位权限标签中移除android:maxSdkVersion="30"

Android ProGuard规则

如果使用ProGuard,请在proguard-rules.pro文件中添加以下内容:

-keep class com.signify.hue.** { *; }

iOS配置

Info.plist文件中添加以下条目:

  • iOS13及以上版本:NSBluetoothAlwaysUsageDescription
  • iOS12及以下版本:NSBluetoothPeripheralUsageDescription

更多信息请参考博客文章

使用方法

初始化

final flutterReactiveBle = FlutterReactiveBle();

设备发现

flutterReactiveBle.scanForDevices(
  withServices: [serviceId], 
  scanMode: ScanMode.lowLatency
).listen((device) {
  // 处理发现的设备
}, onError: (error) {
  // 错误处理
});

监听主机BLE状态

_ble.statusStream.listen((status) {
  // 处理状态更新
});

建立连接

flutterReactiveBle.connectToDevice(
  id: foundDeviceId,
  servicesWithCharacteristicsToDiscover: {serviceId: [char1, char2]},
  connectionTimeout: const Duration(seconds: 2),
).listen((connectionState) {
  // 连接状态更新处理
}, onError: (error) {
  // 错误处理
});

对于不在范围内的设备,可以先扫描再连接:

flutterReactiveBle.connectToAdvertisingDevice(
  id: foundDeviceId,
  withServices: [serviceUuid],
  prescanDuration: const Duration(seconds: 5),
  servicesWithCharacteristicsToDiscover: {serviceId: [char1, char2]},
  connectionTimeout: const Duration(seconds: 2),
).listen((connectionState) {
  // 连接状态更新处理
}, onError: (error) {
  // 错误处理
});

读取/写入特征值

读取特征值

final characteristic = QualifiedCharacteristic(
  serviceId: serviceUuid, 
  characteristicId: characteristicUuid, 
  deviceId: foundDeviceId
);
final response = await flutterReactiveBle.readCharacteristic(characteristic);

写入特征值并等待响应

await flutterReactiveBle.writeCharacteristicWithResponse(
  characteristic, 
  value: [0x00]
);

写入特征值不等待响应

flutterReactiveBle.writeCharacteristicWithoutResponse(
  characteristic, 
  value: [0x00]
);

订阅特征值

flutterReactiveBle.subscribeToCharacteristic(characteristic).listen((data) {
  // 处理收到的数据
}, onError: (error) {
  // 错误处理
});

协商MTU大小

final mtu = await flutterReactiveBle.requestMtu(
  deviceId: foundDeviceId, 
  mtu: 250
);

Android特定操作

请求连接优先级

await flutterReactiveBle.requestConnectionPriority(
  deviceId: foundDeviceId, 
  priority: ConnectionPriority.highPerformance
);

清除GATT缓存

await flutterReactiveBle.clearGattCache(foundDeviceId);

FAQ

如何处理BLE不可达异常

可以在Java/Kotlin部分设置全局错误处理器:

RxJavaPlugins.setErrorHandler { throwable ->
  if (throwable is UndeliverableException && throwable.cause is BleException) {
    return@setErrorHandler // 忽略BleExceptions
  } else {
    throw throwable
  }
}

为什么BLE栈不能直接连接到我的外设

确保BLE栈初始化完成后再执行BLE操作。可以通过监听statusStream并等待BleStatus.ready

非官方示例应用

UART over BLE的实现示例:链接

完整示例Demo

下面是一个完整的示例代码,展示了如何使用flutter_reactive_ble进行基本的BLE操作:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter BLE Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: BLEHomePage(),
    );
  }
}

class BLEHomePage extends StatefulWidget {
  @override
  _BLEHomePageState createState() => _BLEHomePageState();
}

class _BLEHomePageState extends State<BLEHomePage> {
  final FlutterReactiveBle _ble = FlutterReactiveBle();

  StreamSubscription<DiscoveredDevice>? _scanSubscription;
  List<DiscoveredDevice> _devices = [];

  void _startScan() {
    _scanSubscription?.cancel();
    _scanSubscription = _ble.scanForDevices(withServices: []).listen(
      (device) {
        setState(() {
          _devices.add(device);
        });
      },
    );
  }

  void _stopScan() {
    _scanSubscription?.cancel();
  }

  void _connectToDevice(String deviceId) async {
    try {
      await _ble.connectToDevice(id: deviceId).listen((event) {
        print("Connection state: ${event.connectionState}");
      }).asFuture();
    } catch (e) {
      print("Failed to connect: $e");
    }
  }

  @override
  void dispose() {
    _scanSubscription?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter BLE Demo'),
      ),
      body: Column(
        children: [
          ElevatedButton(
            onPressed: _startScan,
            child: Text('Start Scan'),
          ),
          ElevatedButton(
            onPressed: _stopScan,
            child: Text('Stop Scan'),
          ),
          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.id),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

这个示例展示了如何启动和停止BLE设备扫描,并在列表中显示发现的设备。点击设备项时会尝试建立连接。可以根据需要扩展此示例来实现更多功能,如读取、写入或订阅特征值等。


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

1 回复

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


当然,下面是一个使用Flutter蓝牙通信插件flutter_reactive_ble的示例代码。这个示例展示了如何扫描附近的蓝牙设备、连接到设备以及读取设备的服务、特征和值。

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

dependencies:
  flutter:
    sdk: flutter
  flutter_reactive_ble: ^x.y.z  # 请替换为最新版本号

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

接下来是示例代码:

import 'package:flutter/material.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'dart:async';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Reactive BLE Example',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Reactive BLE Example'),
        ),
        body: BleScreen(),
      ),
    );
  }
}

class BleScreen extends StatefulWidget {
  @override
  _BleScreenState createState() => _BleScreenState();
}

class _BleScreenState extends State<BleScreen> {
  final FlutterReactiveBle _flutterReactiveBle = FlutterReactiveBle();
  List<ScannedDevice> _scannedDevices = [];
  String _connectedDeviceId = '';
  StreamSubscription<ScanResult> _scanSubscription;

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

  @override
  void dispose() {
    _scanSubscription?.cancel();
    super.dispose();
  }

  void startScanning() {
    _scanSubscription = _flutterReactiveBle.scan().listen((scanResult) {
      setState(() {
        _scannedDevices = _scannedDevices.filter((device) {
          return device.id.address != scanResult.device.id.address;
        }).toList()..add(scanResult.device);
      });
    });
  }

  void connectToDevice(String deviceId) async {
    setState(() {
      _connectedDeviceId = deviceId;
    });

    final device = _scannedDevices.firstWhere((device) => device.id.address == deviceId, key: (device) => device.id.address);
    await _flutterReactiveBle.connectToDevice(
      deviceId: device.id,
      connectionParameters: ConnectionParameters(
        interval: 7.5 * 1000, // connection interval (1.25ms to 4s)
        slaveLatency: 0,
        supervisionTimeout: 5000, // supervision timeout (10ms to 32s)
      ),
    );

    // Discover services
    final services = await _flutterReactiveBle.discoverServices(deviceId: device.id);
    services.forEach((service) {
      print('Service UUID: ${service.uuid}');
      // Discover characteristics
      _flutterReactiveBle.discoverCharacteristics(deviceId: device.id, serviceUuid: service.uuid).then((characteristics) {
        characteristics.forEach((characteristic) {
          print('  Characteristic UUID: ${characteristic.uuid}');
          // Read characteristic value
          _flutterReactiveBle.readCharacteristic(deviceId: device.id, characteristicUuid: characteristic.uuid).then((value) {
            print('    Value: ${value}');
          });
        });
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Text('Scanned Devices:', style: TextStyle(fontSize: 20)),
          SizedBox(height: 16),
          Expanded(
            child: ListView.builder(
              itemCount: _scannedDevices.length,
              itemBuilder: (context, index) {
                final device = _scannedDevices[index];
                return ListTile(
                  title: Text(device.name ?? 'Unknown Device'),
                  subtitle: Text(device.id.address.toString()),
                  trailing: IconButton(
                    icon: Icon(Icons.connect_without_contact),
                    onPressed: () => connectToDevice(device.id.address.toString()),
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

这个示例代码展示了一个基本的Flutter应用,它使用flutter_reactive_ble插件来扫描附近的蓝牙设备,并在扫描到设备后显示设备的名称和地址。用户可以点击设备项来连接到该设备,并读取其服务和特征值。

请注意,这只是一个简单的示例,实际应用中可能需要处理更多的错误情况和边界情况,例如连接失败、设备断开连接等。此外,根据具体需求,你可能需要修改连接参数和服务、特征的读取方式。

回到顶部