Flutter蓝牙通信插件flutter_reactive_ble的使用
Flutter蓝牙通信插件flutter_reactive_ble的使用
简介
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
更多关于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
插件来扫描附近的蓝牙设备,并在扫描到设备后显示设备的名称和地址。用户可以点击设备项来连接到该设备,并读取其服务和特征值。
请注意,这只是一个简单的示例,实际应用中可能需要处理更多的错误情况和边界情况,例如连接失败、设备断开连接等。此外,根据具体需求,你可能需要修改连接参数和服务、特征的读取方式。