Flutter蓝牙通信插件flutter_blue_plus的使用

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

Flutter蓝牙通信插件flutter_blue_plus的使用

简介

FlutterBluePlus 是一个用于Flutter的Bluetooth Low Energy (BLE) 插件,它支持大多数平台上的BLE Central角色功能。本文档将详细介绍如何在Flutter项目中使用flutter_blue_plus进行蓝牙通信,并提供完整的示例代码。

目录

简介

FlutterBluePlus 是一个用于Flutter的Bluetooth Low Energy (BLE) 插件,它支持大多数平台上的BLE Central角色功能。如果你需要BLE Peripheral角色功能,可以考虑使用其他插件如FlutterBlePeripheralbluetooth_low_energy

准备工作

Android配置

  1. 更改minSdkVersion: 在android/app/build.gradle文件中设置minSdkVersion为21。

    android {
      defaultConfig {
        minSdkVersion 21
      }
    }
    
  2. 添加权限: 在android/app/src/main/AndroidManifest.xml文件中添加必要的权限。

    <uses-feature android:name="android.hardware.bluetooth_le" android:required="false" />
    <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.BLUETOOTH" android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="28" />
    
  3. Proguard规则: 在project/android/app/proguard-rules.pro文件中添加以下内容以避免发布模式下的错误。

    -keep class com.lib.flutter_blue_plus.* { *; }
    

iOS配置

ios/Runner/Info.plist文件中添加以下内容。

<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app needs Bluetooth to function</string>

基本用法

错误处理

FlutterBluePlus对错误处理非常严格,所有来自原生平台的错误都会被检查并抛出异常。

// Streams returned by FlutterBluePlus never emit any errors and never close.
var subscription = FlutterBluePlus.onScanResults.listen((results) {
    if (results.isNotEmpty) {
        ScanResult r = results.last;
        print('${r.device.remoteId}: "${r.advertisementData.advName}" found!');
    }
}, onError: (e) => print(e));

设置日志级别

FlutterBluePlus.setLogLevel(LogLevel.verbose, color: true);

蓝牙开关状态

if (await FlutterBluePlus.isSupported == false) {
    print("Bluetooth not supported by this device");
    return;
}

var subscription = FlutterBluePlus.adapterState.listen((state) {
    print(state);
    if (state == BluetoothAdapterState.on) {
        // Start scanning, connecting, etc.
    } else {
        // Show an error to the user, etc.
    }
});

if (Platform.isAndroid) {
    await FlutterBluePlus.turnOn();
}
subscription.cancel();

扫描设备

var subscription = FlutterBluePlus.onScanResults.listen((results) {
    if (results.isNotEmpty) {
        ScanResult r = results.last;
        print('${r.device.remoteId}: "${r.advertisementData.advName}" found!');
    }
}, onError: (e) => print(e));

await FlutterBluePlus.startScan(
  withServices:[Guid("180D")],
  withNames:["Bluno"],
  timeout: Duration(seconds:15));

await FlutterBluePlus.isScanning.where((val) => val == false).first;

连接设备

var subscription = device.connectionState.listen((state) async {
    if (state == BluetoothConnectionState.disconnected) {
        print("${device.disconnectReason?.code} ${device.disconnectReason?.description}");
    }
});

await device.connect();

await device.disconnect();
subscription.cancel();

自动连接

await device.connect(autoConnect: true, mtu: null);

await device.connectionState.where((val) => val == BluetoothConnectionState.connected).first;

await device.disconnect();

保存设备

final String remoteId = await File('/remoteId.txt').readAsString();
var device = BluetoothDevice.fromId(remoteId);
await device.connect(autoConnect: true);

MTU

final subscription = device.mtu.listen((int mtu) {
    print("mtu $mtu");
});

if (Platform.isAndroid) {
    await device.requestMtu(512);
}

发现服务

List<BluetoothService> services = await device.discoverServices();
services.forEach((service) {
    // Do something with service
});

读取特性

var characteristics = service.characteristics;
for(BluetoothCharacteristic c in characteristics) {
    if (c.properties.read) {
        List<int> value = await c.read();
        print(value);
    }
}

写入特性

await c.write([0x12, 0x34]);

订阅特性

final subscription = characteristic.onValueReceived.listen((value) {
    // Handle value received
});

await characteristic.setNotifyValue(true);

读取和写入描述符

var descriptors = characteristic.descriptors;
for(BluetoothDescriptor d in descriptors) {
    List<int> value = await d.read();
    print(value);
}

await d.write([0x12, 0x34]);

获取已连接设备

List<BluetoothDevice> devs = FlutterBluePlus.connectedDevices;
for (var d in devs) {
    print(d);
}

获取系统设备

List<Guid> withServices = [Guid("180F")];
List<BluetoothDevice> devs = await FlutterBluePlus.systemDevices(withServices);
for (var d in devs) {
    await d.connect();
    await d.discoverServices();
}

创建绑定(仅限Android)

final bsSubscription = device.bondState.listen((value) {
    print("$value prev:{$device.prevBondState}");
});

await device.createBond();

await device.removeBond();

事件API

FlutterBluePlus.events.onConnectionStateChanged.listen((event)) {
    print('${event.device} ${event.connectionState}');
}

示例代码

以下是flutter_blue_plus的完整示例代码:

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

void main() {
  FlutterBluePlus.setLogLevel(LogLevel.verbose, color: true);
  runApp(const FlutterBlueApp());
}

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

  @override
  State<FlutterBlueApp> createState() => _FlutterBlueAppState();
}

class _FlutterBlueAppState extends State<FlutterBlueApp> {
  BluetoothAdapterState _adapterState = BluetoothAdapterState.unknown;
  late StreamSubscription<BluetoothAdapterState> _adapterStateStateSubscription;

  @override
  void initState() {
    super.initState();
    _adapterStateStateSubscription = FlutterBluePlus.adapterState.listen((state) {
      _adapterState = state;
      if (mounted) {
        setState(() {});
      }
    });
  }

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

  @override
  Widget build(BuildContext context) {
    Widget screen = _adapterState == BluetoothAdapterState.on
        ? const ScanScreen()
        : BluetoothOffScreen(adapterState: _adapterState);

    return MaterialApp(
      color: Colors.lightBlue,
      home: screen,
      navigatorObservers: [BluetoothAdapterStateObserver()],
    );
  }
}

class BluetoothAdapterStateObserver extends NavigatorObserver {
  StreamSubscription<BluetoothAdapterState>? _adapterStateSubscription;

  @override
  void didPush(Route route, Route? previousRoute) {
    super.didPush(route, previousRoute);
    if (route.settings.name == '/DeviceScreen') {
      _adapterStateSubscription ??= FlutterBluePlus.adapterState.listen((state) {
        if (state != BluetoothAdapterState.on) {
          navigator?.pop();
        }
      });
    }
  }

  @override
  void didPop(Route route, Route? previousRoute) {
    super.didPop(route, previousRoute);
    _adapterStateSubscription?.cancel();
    _adapterStateSubscription = null;
  }
}

通过上述代码和说明,你应该能够顺利地在Flutter项目中使用flutter_blue_plus进行蓝牙通信。如果有任何问题或需要进一步的帮助,请参考官方文档或社区资源。


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

1 回复

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


当然,以下是一个关于如何使用 flutter_blue_plus 插件进行蓝牙通信的示例代码。这个插件是对 flutter_blue 的增强,提供了更多的功能和更好的性能。请确保你已经在 pubspec.yaml 文件中添加了 flutter_blue_plus 依赖,并且已经运行了 flutter pub get

1. 添加依赖

首先,在你的 pubspec.yaml 文件中添加以下依赖:

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

2. 导入插件并初始化

在你的 Dart 文件中导入 flutter_blue_plus 插件:

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

3. 扫描和连接设备

以下是一个简单的示例,展示如何扫描蓝牙设备并连接到其中一个设备:

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: BluetoothScreen(),
    );
  }
}

class BluetoothScreen extends StatefulWidget {
  @override
  _BluetoothScreenState createState() => _BluetoothScreenState();
}

class _BluetoothScreenState extends State<BluetoothScreen> {
  FlutterBluePlus flutterBluePlus = FlutterBluePlus.instance;
  List<BluetoothDevice> devices = [];
  BluetoothDevice? selectedDevice;

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

  Future<void> scanForDevices() async {
    bool isScanning = true;
    flutterBluePlus.startScan(allowDuplicates: false).listen((scanResult) {
      setState(() {
        devices.add(scanResult.device);
      });
    }).onDone(() {
      if (isScanning) setState(() {}); // trigger a UI update when scanning is stopped
    });

    // Stop scanning after 10 seconds
    Future.delayed(Duration(seconds: 10), () {
      isScanning = false;
      flutterBluePlus.stopScan();
    });
  }

  Future<void> connectToDevice(BluetoothDevice device) async {
    setState(() {
      selectedDevice = device;
    });

    try {
      await device.connect();
      print('Connected to ${device.name}');
      // Here you can discover services, characteristics, etc.
    } catch (e) {
      print('Failed to connect: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Bluetooth Example'),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Expanded(
            child: ListView.builder(
              itemCount: devices.length,
              itemBuilder: (context, index) {
                final device = devices[index];
                return ListTile(
                  title: Text(device.name ?? 'Unknown device'),
                  subtitle: Text(device.id.toString()),
                  trailing: Icon(Icons.arrow_forward),
                  onTap: () => connectToDevice(device),
                );
              },
            ),
          ),
          if (selectedDevice != null)
            Text('Connected to: ${selectedDevice?.name ?? 'No Device'}'),
        ],
      ),
    );
  }
}

4. 发现和交互服务与特征值

一旦连接到设备,你可以发现和交互服务与特征值。以下是一个简单的示例,展示如何读取和写入特征值:

Future<void> interactWithServices(BluetoothDevice device) async {
  // Discover services
  List<BluetoothService> services = await device.discoverServices();

  // Find a specific service (you need to know the UUID of the service you want)
  BluetoothService? service = services.firstWhere(
    (s) => s.uuid.toString().contains('your-service-uuid'),
    orElse: () => null,
  );

  if (service == null) {
    print('Service not found');
    return;
  }

  // Discover characteristics of the service
  List<BluetoothCharacteristic> characteristics = await service.characteristics();

  // Find a specific characteristic (you need to know the UUID of the characteristic)
  BluetoothCharacteristic? characteristic = characteristics.firstWhere(
    (c) => c.uuid.toString().contains('your-characteristic-uuid'),
    orElse: () => null,
  );

  if (characteristic == null) {
    print('Characteristic not found');
    return;
  }

  // Read value from characteristic
  List<int> value = await characteristic.read();
  print('Value read: ${bytesToHex(value)}');

  // Write value to characteristic
  List<int> newValue = hexToBytes('new-value-in-hex');
  await characteristic.write(newValue);
  print('Value written');
}

// Helper function to convert bytes to hex string
String bytesToHex(List<int> bytes) {
  return bytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join();
}

// Helper function to convert hex string to bytes
List<int> hexToBytes(String hexString) {
  return hexString.replaceAll(" ", "")
      .split("")
      .map((hex) => int.parse(hex + hex, radix: 16))
      .toList();
}

5. 使用交互函数

你可以在 connectToDevice 函数中调用 interactWithServices 函数:

Future<void> connectToDevice(BluetoothDevice device) async {
  setState(() {
    selectedDevice = device;
  });

  try {
    await device.connect();
    print('Connected to ${device.name}');
    await interactWithServices(device);
  } catch (e) {
    print('Failed to connect: $e');
  }
}

这个示例代码展示了如何使用 flutter_blue_plus 插件扫描蓝牙设备、连接到设备,并与设备上的服务和特征值进行交互。请注意,你需要替换 'your-service-uuid''your-characteristic-uuid' 为实际设备的 UUID。

回到顶部