Flutter蓝牙设备管理插件gk_ble_device_flutter的使用
Flutter蓝牙设备管理插件gk_ble_device_flutter的使用
本库允许用户通过低功耗蓝牙(BLE)连接到GK Concept设备,发现附近的设备,并订阅设备的报告流,以通知应用程序设备的活动。
目前,该库仅支持带有固件版本0.8.0及以上的Dropper设备。
该库使用Bloc库将业务逻辑与用户界面分离。
开始使用
在使用此库时,请务必遵循FlutterBluePlus指南,特别是有关应用程序所需权限的部分。
使用方法
所有核心功能都在BleDeviceCubit
类中实现。
完整的示例代码及其用户界面可以在这里找到。
示例演示
这是Android上示例的外观:
Dropper报告消息格式
从Dropper设备的报告流订阅中获得的消息具有以下格式:
{
"#": 27,
"date": "20-02-14",
"time": "16:05:04",
"timestamp": 1644854704,
"report": true,
"cycles": 2445,
"doses": 35,
"event": 2
}
字段说明如下:
字段 | 类型 | 描述 |
---|---|---|
timestamp | int | 报告的UTC时间戳(如果系统时间未通过WiFi设置,则仅为相对值) |
event | int | 事件代码: |
0 (POWERON) 机器启动完成 | ||
1 (DELIVERYREQ) 请求分配剂量 | ||
2 (DELIVERED) 分配成功 | ||
3 (PRIMEREQ) 请求预充 | ||
4 (PRIMED) 预充完成 | ||
5 (UPDATEREQ) 请求更新固件 | ||
6 (UPDATEOK) 更新成功 | ||
-6 (UPDATEFAIL) 更新失败 | ||
-10(NOHOMESW) 读取初始开关失败 | ||
cycles | int | 总分配次数 |
doses | int | 自上次清零以来的总分配次数 |
macOS权限设置
对于macOS,需要在Info.plist
文件中添加以下内容:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>该应用使用蓝牙来查找、连接和传输不同设备之间的数据</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>该应用使用蓝牙来查找、连接和传输不同设备之间的数据</string>
此外,还需要在DebugProfile.entitlements
和Release.entitlements
中添加以下内容:
<key>com.apple.security.device.bluetooth</key>
<true/>
示例代码
以下是完整的示例代码:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:logging/logging.dart';
import 'package:gk_ble_device_flutter/ble_device_ext.dart';
import 'package:gk_ble_device_flutter/ble_device_cubit.dart';
void main() {
FlutterBluePlus.setLogLevel(LogLevel.info);
Logger.root.level = Level.ALL;
Logger.root.onRecord.listen((record) {
// 忽略打印日志
print('${record.loggerName}: ${record.level.name}: ${record.time}: ${record.message}');
});
runApp(BlocProvider(
create: (_) => BleDeviceCubit(),
child: const MaterialApp(home: DropperDemoApp())));
}
class DropperDemoApp extends StatefulWidget {
const DropperDemoApp({super.key});
[@override](/user/override)
State<DropperDemoApp> createState() => _DropperDemoAppState();
}
// 定义状态消息映射
final Map<Type, Function(BleDeviceState state)> _stateMessages = {
BleDeviceAuthorizing: (state) => '授权蓝牙...',
BleDeviceConnecting: (state) =>
'连接到${(state as BleDeviceConnecting).device.platformName}...',
BleDeviceGettingServices: (state) =>
'从${(state as BleDeviceGettingServices).device.platformName}检索服务...',
BleDeviceGettingCharacteristics: (state) =>
'从${(state as BleDeviceGettingCharacteristics).device.platformName}检索特征...',
BleDeviceDisconnected: (state) =>
'从${(state as BleDeviceDisconnected).device.platformName}断开连接',
BleDeviceFailedToConnect: (state) =>
'无法连接到${(state as BleDeviceFailedToConnect).device.platformName}',
};
// 定义状态符号映射
final Map<Type, Function(BleDeviceState state)> _stateSymbols = {
BleDeviceAuthorizing: (state) => const CircularProgressIndicator(),
BleDeviceConnecting: (state) => const CircularProgressIndicator(),
BleDeviceGettingServices: (state) => const CircularProgressIndicator(),
BleDeviceGettingCharacteristics: (state) => const CircularProgressIndicator(),
BleDeviceDisconnected: (state) => const Icon(Icons.error),
BleDeviceFailedToConnect: (state) => const Icon(Icons.error),
};
class _DropperDemoAppState extends State<DropperDemoApp> {
List<BluetoothDevice> _devices = [];
StreamSubscription? _reportSubscription;
[@override](/user/override)
void initState() {
super.initState();
}
[@override](/user/override)
void dispose() {
_reportSubscription?.cancel();
super.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) {
return BlocConsumer<BleDeviceCubit, BleDeviceState>(
listener: _listener,
builder: (context, state) {
return Scaffold(
appBar: AppBar(
title: const Text("Dropper Demo"),
),
body: _buildScreen(context, state),
);
},
);
}
// 状态监听器
void _listener(BuildContext context, BleDeviceState state) {
final cubit = context.read<BleDeviceCubit>();
if (state is BleDeviceAuthorizing && state.status == BluetoothAdapterState.on) {
cubit.startScanning();
} else if (state is BleDeviceScanning) {
setState(() {
_devices = state.discoveredDevices;
});
} else if (state is BleDeviceDisconnected) {
if (_reportSubscription != null) {
_reportSubscription!.cancel();
}
Future.delayed(const Duration(seconds: 1), () {
cubit.startScanning();
});
} else if (state is BleDeviceConnected &&
state.characteristicStreams.containsKey(GKCharId.report)) {
if (_reportSubscription != null) {
_reportSubscription!.cancel();
}
_reportSubscription = state.characteristicStreams[GKCharId.report]!
.listen((List<int> report) {
if (context.mounted) {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('报告: ${String.fromCharCodes(report)}')));
}
});
}
}
// 构建屏幕
Widget _buildScreen(BuildContext context, BleDeviceState state) {
if (state is BleDeviceScanning) {
return _scanScreen(context, state);
}
if (state is BleDeviceConnected) {
return _connectedScreen(context, state);
}
return Center(
child: Column(
children: [
const SizedBox(height: 20),
if (_stateSymbols.containsKey(state.runtimeType))
_stateSymbols[state.runtimeType]!(state)
else
const SizedBox.shrink(),
const SizedBox(height: 20),
Text(_stateMessages.containsKey(state.runtimeType)
? _stateMessages[state.runtimeType]!(state)
: ''),
],
),
);
}
// 扫描屏幕
Widget _scanScreen(BuildContext context, BleDeviceState state) {
return Center(
child: Column(children: [
if (state is BleDeviceScanning && state.scanIsInProgress)
const Column(children: [
SizedBox(
height: 20,
),
CircularProgressIndicator(),
SizedBox(
height: 20,
),
Text('正在扫描设备...'),
]),
if (state is BleDeviceScanning && !state.scanIsInProgress)
ElevatedButton(
onPressed: () {
context.read<BleDeviceCubit>().startScanning();
},
child: const Text('扫描设备')),
if (_devices.isEmpty)
const Text('未发现设备')
else
Expanded(
child: ListView.builder(
itemCount: _devices.length,
itemBuilder: (context, index) {
return ListTile(
title: Row(children: [
BluetoothSignal(
strength: context
.read<BleDeviceCubit>()
.getRssi(_devices[index])),
const SizedBox(width: 10),
Text(_devices[index].platformName)
]),
onTap: () {
context.read<BleDeviceCubit>().connect(_devices[index]);
});
}))
]));
}
// 已连接屏幕
Widget _connectedScreen(BuildContext context, BleDeviceConnected state) {
return Center(
child: Column(children: [
const SizedBox(height: 20),
const Icon(Icons.check),
const SizedBox(height: 20),
Text('已连接到${state.device.platformName}'),
const SizedBox(height: 20),
if (state.characteristics.containsKey(GKCharId.firmwareVersion)) ...[
Text(
'固件版本: ${state.characteristics[GKCharId.firmwareVersion]!.stringValue}'),
const SizedBox(height: 20)
],
if (!state.characteristicStreams.containsKey(GKCharId.report)) ...[
const Text(
'未找到报告特征。您是否使用的是固件版本0.8.0或更高的Dropper设备?'),
const SizedBox(height: 20)
],
ElevatedButton(
onPressed: () async {
final cubit = context.read<BleDeviceCubit>();
await cubit.disconnect();
await cubit.startScanning();
},
child: const Text("断开连接"))
]));
}
}
更多关于Flutter蓝牙设备管理插件gk_ble_device_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
gk_ble_device_flutter
是一个用于在 Flutter 应用中管理蓝牙设备的插件。它可以帮助你轻松地扫描、连接、读写蓝牙设备。以下是如何使用 gk_ble_device_flutter
插件的基本步骤:
1. 添加依赖
首先,你需要在 pubspec.yaml
文件中添加 gk_ble_device_flutter
插件的依赖:
dependencies:
flutter:
sdk: flutter
gk_ble_device_flutter: ^latest_version
然后,运行 flutter pub get
来安装依赖。
2. 导入插件
在你的 Dart 文件中导入 gk_ble_device_flutter
插件:
import 'package:gk_ble_device_flutter/gk_ble_device_flutter.dart';
3. 初始化插件
在使用插件之前,你需要先初始化它:
GkBleDeviceFlutter bleDevice = GkBleDeviceFlutter();
4. 扫描蓝牙设备
你可以使用 startScan
方法来扫描附近的蓝牙设备:
bleDevice.startScan().listen((device) {
print('Found device: ${device.name}, ${device.id}');
});
5. 停止扫描
当你不再需要扫描设备时,可以调用 stopScan
方法来停止扫描:
bleDevice.stopScan();
6. 连接蓝牙设备
使用 connect
方法来连接指定的蓝牙设备:
bleDevice.connect(deviceId).then((connected) {
if (connected) {
print('Connected to device');
} else {
print('Failed to connect to device');
}
});
7. 断开连接
使用 disconnect
方法来断开与蓝牙设备的连接:
bleDevice.disconnect(deviceId).then((disconnected) {
if (disconnected) {
print('Disconnected from device');
} else {
print('Failed to disconnect from device');
}
});
8. 读取数据
使用 readCharacteristic
方法来读取蓝牙设备的特征值:
bleDevice.readCharacteristic(deviceId, serviceId, characteristicId).then((value) {
print('Read value: $value');
});
9. 写入数据
使用 writeCharacteristic
方法来向蓝牙设备的特征值写入数据:
bleDevice.writeCharacteristic(deviceId, serviceId, characteristicId, value).then((success) {
if (success) {
print('Write successful');
} else {
print('Write failed');
}
});
10. 监听通知
你可以使用 setNotification
方法来监听蓝牙设备的通知:
bleDevice.setNotification(deviceId, serviceId, characteristicId, true).listen((value) {
print('Notification received: $value');
});
11. 处理权限
在 Android 上,你需要确保应用具有访问蓝牙的权限。你可以在 AndroidManifest.xml
文件中添加以下权限:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
在 iOS 上,你需要在 Info.plist
文件中添加以下键值对:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>We need access to Bluetooth to connect to your device.</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>We need access to Bluetooth to connect to your device.</string>
12. 处理错误
在使用插件时,可能会遇到各种错误。你可以通过捕获异常来处理这些错误:
try {
await bleDevice.connect(deviceId);
} catch (e) {
print('Error: $e');
}
13. 释放资源
在应用退出或不再需要蓝牙功能时,记得释放资源:
bleDevice.dispose();