说明:
使用flutter_blue_plus插件实现低功耗蓝牙开发。
一、添加蓝牙权限:
1.Android网络权限(工程/android/app/src/main/AndroidManifest.xml):
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
2.iOS蓝牙权限(工程/ios/Runner/Info.plist):
<dict>
...
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Need BLE permission</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>Need BLE permission</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Need Location permission</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Need Location permission</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Need Location permission</string>
</dict>
二、实现扫描/连接/接收BLE设备数据:
1.添加flutter_blue_plus插件依赖,在pubspec.yaml中:
dependencies:
flutter_blue_plus: ^1.3.1 #蓝牙插件
2.实现BLE蓝牙设备扫描:
(1)蓝牙扫描类:
class ScanDevice {
static const int SCAN_TIMEOUT = 10000;
final String NAME_PREFIX = "T";
final String NAME_PREFIX_2 = "HLW";
final FlutterBluePlus _flutterBlue = FlutterBluePlus.instance; //蓝牙API
final ScanCallback _callback; //回调接口
var _isScanning = false;
late Timer? _timer = null;
ScanDevice(this._callback);
//开始扫描
void startScan({int timeout = SCAN_TIMEOUT}) {
log("1.开始扫描设备 >>>>>>");
if (_isScanning) return;
_isScanning = true;
_flutterBlue.scanResults.listen((results) {
for (ScanResult item in results) {
_handlerScanResult(item);
}
});
_flutterBlue?.startScan(timeout: Duration(seconds: timeout));
startTimer();
}
//N秒后停止扫描, 并回调通知外部
void startTimer(){
cancelTimer();
_timer = Timer(Duration(milliseconds: SCAN_TIMEOUT), () {
stopScan(); //停止扫描
_callback.onStop(); //回调通知外部
});
}
void cancelTimer(){
_timer?.cancel();
_timer = null;
}
//是否扫描中
bool isScan() {
return _isScanning;
}
//停止扫描
void stopScan() {
log("停止扫描设备 >>>>>>");
cancelTimer();
if (!_isScanning) return;
_isScanning = false;
_flutterBlue.stopScan();
}
//处理扫描结果
void _handlerScanResult(ScanResult result) {
if (!result.device.name.startsWith(NAME_PREFIX) && !result.device.name.startsWith(NAME_PREFIX_2)) return; //过滤掉非本公司的蓝牙设备
log('扫到设备, name: ${result.device.name}');
if (result.device.name.startsWith(NAME_PREFIX_2)) { //针对定制过的蓝牙设备,需要从广播中获取真正的设备名称
var realName = getRealName(result); //从广播中获取真实的设备名称
if (realName != null && realName.startsWith("T")){
//...
}
_callback.onFind(DeviceBean(result.device)); //回调到外部
return;
}
_callback.onFind(DeviceBean(result.device)); //回调到外部
}
}
(2)蓝牙扫描回调接口:
typedef OnFind = void Function(DeviceBean device);
typedef OnStop = void Function();
class ScanCallback {
ScanCallback ({required this.onFind, required this.onStop});
OnFind onFind;
OnStop onStop;
}
(3)自定义实体类:
class DeviceBean {
BluetoothDevice device; //设备
DeviceBean(this.device);
}
3.实现连接设备/接收数据:
(1)连接设备/接收数据管理类:
class ConnectManager {
final Guid SET_MODE_SERVICE_UUID = Guid("0000180f-0000-1000-8000-00805f9b34fb"); //设置模式-服务UUID
final Guid SET_MODE_CHARACTERISTIC_UUID = Guid("00002a19-0000-1000-8000-00805f9b34fb"); //设置模式-特征值UUID
final Guid SET_MODE_DESCRIPTOR_UUID = Guid("00002902-0000-1000-8000-00805f9b34fb"); //设置模式-特征值描述UUID(固定不变)
final Guid WRITE_DATA_SERVICE_UUID = Guid("01ff0100-ba5e-f4ee-5ca1-eb1e5e4b1ce1"); //写数据-服务UUID
final Guid WRITE_DATA_CHARACTERISTIC_UUID = Guid("01ff0101-ba5e-f4ee-5ca1-eb1e5e4b1ce1"); //写数据-特征值UUID
final List<int> ENABLE_NOTIFICATION_VALUE = [0x01, 0x00]; //启用Notification模式
final List<int> DISABLE_NOTIFICATION_VALUE = [0x00, 0x00]; //停用Notification模式
final List<int> ENABLE_INDICATION_VALUE = [0x02, 0x00]; //启用Indication模式
static const int CON_TIMEOUT = 10000;
final GattCallback _gattCallback;
late BluetoothCharacteristic? _writeCharacteristic = null;
late ScanDevice? _scanDevice = null;
late DeviceBean? _device = null;
bool isConnecting = false;
ConnectManager(this._gattCallback);
//1.扫描
Future<void> start(String deviceName, {int timeout = ScanDevice.SCAN_TIMEOUT}) async {
if (_scanDevice == null) {
_scanDevice = ScanDevice(ScanCallback(
onFind: (DeviceBean device) { //扫描到设备
if(isConnecting) {
_scanDevice?.stopScan(); //停止扫描
return;
}
if(device.device.name == deviceName){
this._device = device;
_scanDevice?.stopScan(); //停止扫描
connect(device.device); //转 - 2.连接
}
},
onStop: () { //停止扫描
if(this._device == null){
log("没找到设备 >>>>>>");
_gattCallback.onDeviceNotFind(); //没扫描到设备时, 回调外部
}
}
));
}
_scanDevice?.startScan(timeout: timeout);
isConnecting = false;
}
//2.连接
Future<void> connect(BluetoothDevice device) async {
isConnecting = true;
log("2.开始连接 >>>>>>name: ${device.name}");
await device.connect(timeout: Duration(milliseconds: CON_TIMEOUT), autoConnect: false);
log("连接成功 >>>>>>name: ${device.name}");
_discoverServices(device);
}
//3.发现服务
Future<void> _discoverServices(BluetoothDevice device) async {
log("3.开始发现服务 >>>>>>name: ${device.name}");
List<BluetoothService> services = await device.discoverServices();
log("发现服务成功 >>>>>>name: ${device.name}");
_handlerServices(device, services); //遍历服务列表,找出指定服务
isConnecting = false;
}
//3.1遍历服务列表,找出指定服务
void _handlerServices(BluetoothDevice device, List<BluetoothService> services){
services.forEach((sItem) {
String sUuid = sItem.uuid.toString();
if(sUuid == SET_MODE_SERVICE_UUID.toString()){ //找到设置模式的服务
log("4.找到设置模式的服务 >>>>>>name: ${device.name} serviceGuid: ${SET_MODE_SERVICE_UUID.toString()}");
_readCharacteristics(device, sItem); //读取特征值
} else if(sUuid == WRITE_DATA_SERVICE_UUID.toString()){ //找到写数据的服务
log("4.找到写数据的服务 >>>>>>name: ${device.name} serviceGuid: ${WRITE_DATA_SERVICE_UUID.toString()}");
_readCharacteristics(device, sItem); //读取特征值
}
});
}
//4.读取特征值(读出设置模式与写数据的特征值)
Future<void> _readCharacteristics(BluetoothDevice device, BluetoothService service) async {
var characteristics = service.characteristics;
for(BluetoothCharacteristic cItem in characteristics) {
String cUuid = cItem.uuid.toString();
if(cUuid == SET_MODE_CHARACTERISTIC_UUID.toString()){ //找到设置模式的特征值
log("4.0.找到设置模式的特征值 >>>>>>name: ${device.name} characteristicUUID: ${SET_MODE_CHARACTERISTIC_UUID.toString()}");
_requestMtu(device); //设置MTU
_setNotificationMode(device, cItem); //设置为Notification模式(设备主动给手机发数据)
} else if(cUuid == WRITE_DATA_CHARACTERISTIC_UUID.toString()){ //找到写数据的特征值
log("4.0.找到写数据的特征值 >>>>>>name: ${device.name} characteristicUUID: ${WRITE_DATA_CHARACTERISTIC_UUID.toString()}");
_writeCharacteristic = cItem; //保存写数据的征值
}
}
}
//4.1.设置MTU
Future<void> _requestMtu(BluetoothDevice device) async {
final mtu = await device.mtu.first;
log("4.1.当前mtu: $mtu 请求设置mtu为512 >>>>>>name: ${device.name}");
await device.requestMtu(512);
}
//4.2.设置为Notification模式(设备主动给手机发数据),Indication模式需要手机读设备的数据
Future<void> _setNotificationMode(BluetoothDevice device, BluetoothCharacteristic cItem) async {
log("4.2.设置为通知模式 >>>>>>name: ${device.name}");
await cItem.setNotifyValue(true); //为指定特征的值设置通知
cItem.value.listen((value) {
if (value == null || value.isEmpty) return;
log("接收数据 >>>>>>name: ${device.name} value: $value");
MessageData data = MessageData();
//...省略解析设备数据的逻辑
_gattCallback.onRead(data); //回调外部,返回设备发送的数据
});
var descriptors = cItem.descriptors;
for (BluetoothDescriptor dItem in descriptors) {
if (dItem.uuid.toString() == SET_MODE_DESCRIPTOR_UUID.toString()) {//找到设置模式的descriptor
log("发送Notification模式给设备 >>>>>>name: ${device.name}");
dItem.write(ENABLE_NOTIFICATION_VALUE); //发送Notification模式给设备
return;
}
}
}
//发送指令到设备
Future<void> writeCommand(List<int> data) async {
log("发送指令给设备 >>>>>>name: ${device.name} data: $data");
await _writeCharacteristic?.write(data);
}
//断开连接
void disconnect(BluetoothDevice device) {
log("断开连接 >>>>>>name: ${device.name}");
device.disconnect(); //关闭连接
_gattCallback.onDisconnect(); //连接失败回调
}
}
(2)蓝牙连接回调接口:文章来源:https://www.toymoban.com/news/detail-513195.html
typedef OnDeviceNotFind = void Function();
typedef OnConnected = void Function();
typedef OnDisconnect = void Function();
typedef OnRead = void Function(MessageData data);
class GattCallback {
GattCallback ({required this.onDeviceNotFind, required this.onConnected, required this.onDisconnect, required this.onRead});
OnDeviceNotFind onDeviceNotFind;
OnConnected onConnected;
OnDisconnect onDisconnect;
OnRead onRead;
}
4.调用例子:文章来源地址https://www.toymoban.com/news/detail-513195.html
...//省略其他
ConnectManager connectManager = ConnectManager(GattCallback( //1.实例化连接管理类,并监听连接状态
onDeviceNotFind: () { //没找到设备
},
onConnected: () { //连接成功回调
},
onDisconnect: () { //连接关闭回调
},
onRead: (MessageData data) { //设备发过来的数据
}
));
...//省略其他
if(!connectManager.isConnecting){
connectManager.start("T11302002020169"); //2.开始连接蓝牙设备,T11302002020169为蓝牙设备名称
}
到了这里,关于Flutter:BLE蓝牙开发的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!