Flutter高级蓝牙操作插件bluetooth_advanced的使用

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

Flutter高级蓝牙操作插件bluetooth_advanced的使用

如何使用

要使用 bluetooth_advanced 插件,请遵循以下步骤:

Step1: 添加插件依赖

在你的 pubspec.yaml 文件中添加插件:

dependencies:
  bluetooth_advanced: [latest_version]

Step2: 导入插件

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

import 'package:bluetooth_advanced/bluetooth_advanced.dart';

Step3: 初始化配置详情

在这里,重要的是设置与服务器设备相似的 UUID。这些 UUID 是用于识别蓝牙设备所提供服务的独特信息。你的应用程序将通过这些标准协议连接到该设备。

final _bluetoothAdvanced = BluetoothAdvanced();
print(await _bluetoothAdvanced.getDataCharactersticUUID());
print(await _bluetoothAdvanced.getServiceCharactersticUUID());
await _bluetoothAdvanced
      .setServiceCharactersticUUID("0000baad-0000-1000-8000-00805f9b34fb");
await _bluetoothAdvanced
      .setDataCharactersticUUID("0000BEEF-0000-1000-8000-00805F9B34FB");

Step4: 初始化蓝牙

这将返回一个流,你可以持续监听它:

_bluetoothAdvanced.initBluetooth();

Step5: 扫描设备

这将返回一个流,你可以持续监听扫描状态:

状态 描述 数据类型/格式
SCANNING_STARTED 开始扫描配对设备 字符串
SCANNING_FINISHED_WITH_NO_DEVICE 未找到设备 字符串
[device_address], [device_name] 返回设备地址和名称 字符串: “01:23:45:67:89:10,MyBluetoothDevice”
_bluetoothAdvanced.scanDevices();

Step6: 连接设备

这将返回一个流,你可以持续监听连接状态:

状态 描述 数据类型/格式
DEVICE_RECOGNIZING 认识到了具有必要信息的设备 字符串
DEVICE_CONNECTING 尝试连接设备 字符串
DEVICE_CONNECTED 建立了与设备的连接 字符串
DEVICE_DISCONNECTED 连接中断 字符串
DEVICE_CONNECTING_FAILED 尝试连接失败 字符串
_bluetoothAdvanced.connectDevice().listen((event) {
  switch (event.toString()) {
    case STATE_RECOGNIZING:
      break;
    case STATE_CONNECTING:
      break;
    case STATE_CONNECTED:
      setState(() {
        isConnected = true;
      });
      break;
    case STATE_DISCONNECTED:
      setState(() {
        isConnected = false;
      });
      break;
    case STATE_CONNECTING_FAILED:
      break;
    default:
  }
});

Step7: 监听数据

这将返回一个流,你可以持续监听数据接收状态:

状态 描述 数据类型/格式
DEVICE_DATA_INITIATED 尝试与设备进行数据握手 字符串
DEVICE_DATA_CONNECTING 尝试与设备建立数据连接 字符串
DEVICE_DATA_CONNECTED 建立了与设备的数据连接 字符串
DEVICE_DATA_AVAILABLE 收到了可用的数据 字符串: “DEVICE_DATA_AVAILABLE:this is the data received”
DEVICE_DATA_DISCONNECTED 数据连接被撤销 字符串
_bluetoothAdvanced.listenData().listen((event) {
  if (event.startsWith(DEVICE_DATA_AVAILABLE)) {
    setState(() {
      isData = true;
      data = event.toString();
    });
  }
  switch (event.toString()) {
    case DEVICE_DATA_INITIATED:
      printWrapped(DEVICE_DATA_INITIATED);
      break;
    case DEVICE_DATA_CONNECTING:
      printWrapped(DEVICE_DATA_CONNECTING);
      break;
    case DEVICE_DATA_CONNECTED:
      printWrapped(DEVICE_DATA_CONNECTED);
      break;
    case DEVICE_DATA_AVAILABLE:
      printWrapped(DEVICE_DATA_AVAILABLE);
      break;
    case DEVICE_DATA_DISCONNECTED:
      setState(() {
        isData = false;
        isConnected = false;
      });
      break;
    default:
  }
});

Step8: 撤销连接

这将撤销与设备的连接。如果你不调用此函数,它将在后台继续运行并持续接收数据。

_bluetoothAdvanced.dispose();

示例代码

以下是一个完整的示例代码:

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:bluetooth_advanced/bluetooth_advanced.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

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

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  List<Widget> list = [const Text('')];

  final _bluetoothAdvanced = BluetoothAdvanced();
  late StreamSubscription streamSubscription;
  late StreamBuilder streamBuilder;

  bool isConnected = false;
  String? data;
  bool isData = false;

  [@override](/user/override)
  void initState() {
    super.initState();

    initBluetoothConfig();
    listentoDeviceData();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          backgroundColor: Colors.cyan.shade900,
          title: const Text('bluetooth_advanced'),
        ),
        body: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Expanded(
                flex: 2,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.start,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    StreamBuilder<Object>(
                      stream: _bluetoothAdvanced.scanDevices(),
                      builder: (BuildContext context, AsyncSnapshot<Object> snapshot) {
                        if (snapshot.hasError) {
                          return showError(snapshot.error);
                        } else if (snapshot.hasData) {
                          if (snapshot.data.toString() == SCANNING_FINISHED_WITH_NO_DEVICE) {
                            return deviceNotFound();
                          } else {
                            List<String> device = snapshot.data.toString().split(",");
                            return deviceFound(device[0], device[1]);
                          }
                        } else {
                          return deviceScanning();
                        }
                      },
                    ),
                    StreamBuilder<String>(
                      stream: _bluetoothAdvanced.initBluetooth(),
                      builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
                        if (snapshot.hasError) {
                          return const Text("Error Occurred!");
                        } else if (snapshot.hasData) {
                          return Text("Starting Connection: ${snapshot.data}");
                        } else {
                          return const Text("Waiting for connection to start...");
                        }
                      },
                    ),
                    isConnected && isData
                        ? Text(data!)
                        : const Text('Waiting to be connected'),
                  ],
                ),
              ),
              const Spacer(),
              bottomBar()
            ],
          ),
        ),
      ),
    );
  }

  /* utilities functions */
  void printWrapped(String text) {
    final pattern = RegExp('.{1,300}');
    pattern.allMatches(text).forEach((match) => print(match.group(0)));
  }

  Future<void> initBluetoothConfig() async {
    try {
      print(await _bluetoothAdvanced
          .setServiceCharactersticUUID("0000baad-0000-1000-8000-00805f9b34fb"));
      print(await _bluetoothAdvanced
          .setDataCharactersticUUID("0000BEEF-0000-1000-8000-00805F9B34FB"));
      print(await _bluetoothAdvanced.getDataCharactersticUUID());
      print(await _bluetoothAdvanced.getServiceCharactersticUUID());
      print(await (_bluetoothAdvanced.setScanPeriod(10000)));
      await _bluetoothAdvanced.setNotificationText("new text");
      await _bluetoothAdvanced.setNotificationTitle("new title");
    } catch (e) {
      print(e.toString());
    }

    if (!mounted) return;
  }

  listentoDeviceData() {
    _bluetoothAdvanced.listenData().listen((event) {
      if (event.startsWith(DEVICE_DATA_AVAILABLE)) {
        setState(() {
          isData = true;
          data = event.toString();
        });
      }
      switch (event.toString()) {
        case DEVICE_DATA_INITIATED:
          printWrapped(DEVICE_DATA_INITIATED);
          break;
        case DEVICE_DATA_CONNECTING:
          printWrapped(DEVICE_DATA_CONNECTING);
          break;
        case DEVICE_DATA_CONNECTED:
          printWrapped(DEVICE_DATA_CONNECTED);
          break;
        case DEVICE_DATA_AVAILABLE:
          printWrapped(DEVICE_DATA_AVAILABLE);
          break;
        case DEVICE_DATA_DISCONNECTED:
          setState(() {
            isData = false;
            isConnected = false;
          });
          break;
        default:
      }
    });
  }

  /* widget function */
  showError(Object? error) {
    String errorMessage = 'Some Error Encountered';
    if (error.runtimeType == PlatformException) {
      PlatformException? platformException = error as PlatformException?;
      errorMessage = platformException!.code;
    } else {
      errorMessage = error.toString();
    }
    return Card(
        child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 20),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const Text('Error:',
                    style:
                        TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
                const SizedBox(height: 8),
                Text(errorMessage,
                    style: const TextStyle(
                        fontSize: 14, fontStyle: FontStyle.italic)),
              ],
            )));
  }

  deviceScanning() {
    return Card(
        child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 20),
            child: Row(
              children: const [
                Text("scanning devices",
                    style:
                        TextStyle(fontSize: 14, fontStyle: FontStyle.italic)),
                SizedBox(width: 12),
                SizedBox(
                    height: 22, width: 22, child: CircularProgressIndicator())
              ],
            )));
  }

  deviceNotFound() {
    return Card(
        child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 20),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const Text("No Device found, Retry",
                    style:
                        TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
                const SizedBox(height: 8),
                const Text(
                    """Troubleshoot: \n ► Try increasing the scan period.\n ► Check if the device is paired in bluetooth settings.\n ► Check if paired device has correct configurations like uuids""",
                    style:
                        TextStyle(fontSize: 14, fontStyle: FontStyle.italic)),
              ],
            )));
  }

  deviceFound(String address, String name) {
    return Card(
        child: Padding(
      padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
      child: Row(
        children: [
          isConnected
              ? const Icon(Icons.bluetooth_connected_rounded,
                  color: Colors.green)
              : const Icon(Icons.bluetooth_rounded, color: Colors.grey),
          const SizedBox(width: 10),
          Column(
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(name,
                    style: const TextStyle(
                        fontSize: 20, fontWeight: FontWeight.bold)),
                const SizedBox(height: 6),
                Text(address,
                    style: const TextStyle(
                        fontSize: 14, fontStyle: FontStyle.italic))
              ]),
          const Spacer(),
          ElevatedButton(
              style: ButtonStyle(
                backgroundColor: MaterialStateProperty.all<Color>(
                    isConnected ? Colors.green : Colors.lightBlue),
              ),
              onPressed: () {
                _bluetoothAdvanced.connectDevice().listen((event) {
                  switch (event.toString()) {
                    case STATE_RECOGNIZING:
                      break;
                    case STATE_CONNECTING:
                      break;
                    case STATE_CONNECTED:
                      setState(() {
                        isConnected = true;
                      });
                      break;
                    case STATE_DISCONNECTED:
                      setState(() {
                        isConnected = false;
                      });
                      break;
                    case STATE_CONNECTING_FAILED:
                      break;
                    default:
                  }
                });
              },
              child: Text(
                isConnected ? 'Connected' : 'Connect',
                style:
                    const TextStyle(fontSize: 14, fontStyle: FontStyle.italic),
              ))
        ],
      ),
    ));
  }

  bottomBar() {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.end,
      children: [
        Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: const [
            Icon(Icons.info_outline_rounded, color: Colors.grey),
            SizedBox(width: 10),
            Text(
              'Remember to turn on bluetooth\nand GPS first',
              style: TextStyle(
                  fontStyle: FontStyle.italic, color: Colors.blueGrey),
            ),
          ],
        ),
        const Spacer(),
        ElevatedButton(
            style: ButtonStyle(
              padding: MaterialStateProperty.all<EdgeInsetsGeometry>(
                  const EdgeInsets.symmetric(vertical: 20)),
              backgroundColor: MaterialStateProperty.all<Color>(
                  isConnected && isData ? Colors.cyan.shade900 : Colors.grey),
            ),
            onPressed: () async {
              await _bluetoothAdvanced.dispose();
            },
            child: const Icon(Icons.stop_circle)),
      ],
    );
  }
}

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

1 回复

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


当然,以下是如何在Flutter应用中使用bluetooth_advanced插件进行高级蓝牙操作的示例代码。这个插件提供了更全面的蓝牙功能,包括扫描设备、连接设备、读写蓝牙特征值等。

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

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

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

示例代码

以下是一个基本的Flutter应用示例,它展示了如何使用bluetooth_advanced插件进行蓝牙扫描和连接操作。

main.dart

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

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  BluetoothAdvanced _bluetoothAdvanced = BluetoothAdvanced();
  List<BluetoothDevice> _devices = [];
  BluetoothDevice? _connectedDevice;

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

  Future<void> initBluetooth() async {
    bool isBluetoothEnabled = await _bluetoothAdvanced.isBluetoothEnabled();
    if (!isBluetoothEnabled) {
      // Handle Bluetooth not enabled case
      return;
    }

    // Request location permission (required for Bluetooth scanning on Android)
    bool hasLocationPermission = await _bluetoothAdvanced.requestLocationPermission();
    if (!hasLocationPermission) {
      // Handle permission denied case
      return;
    }

    // Start scanning for devices
    _bluetoothAdvanced.startDeviceScan(allowDuplicates: false).listen((devices) {
      setState(() {
        _devices = devices;
      });
    }, onError: (error) {
      // Handle scan error
      print('Scan error: $error');
    }, onDone: () {
      // Handle scan done (e.g., when stopDeviceScan is called)
      print('Scan done');
    });
  }

  Future<void> connectToDevice(BluetoothDevice device) async {
    bool isConnected = await _bluetoothAdvanced.connectToDevice(device);
    if (isConnected) {
      setState(() {
        _connectedDevice = device;
      });
      // Optionally, start discovering services, characteristics, etc.
      discoverServices();
    } else {
      // Handle connection failure
      print('Failed to connect to device: ${device.address}');
    }
  }

  Future<void> discoverServices() async {
    if (_connectedDevice != null) {
      List<BluetoothService> services = await _bluetoothAdvanced.discoverServices(_connectedDevice!);
      // Process discovered services
      print('Discovered services: $services');
      
      // Example: Get characteristics for the first service
      if (services.isNotEmpty) {
        List<BluetoothCharacteristic> characteristics = await _bluetoothAdvanced.getCharacteristics(services.first);
        // Process characteristics
        print('Characteristics: $characteristics');
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Bluetooth Advanced Example'),
        ),
        body: Column(
          children: [
            Expanded(
              child: ListView.builder(
                itemCount: _devices.length,
                itemBuilder: (context, index) {
                  BluetoothDevice device = _devices[index];
                  return ListTile(
                    title: Text(device.name ?? 'Unknown Device'),
                    subtitle: Text(device.address),
                    onTap: () => connectToDevice(device),
                  );
                },
              ),
            ),
            if (_connectedDevice != null)
              Text('Connected Device: ${_connectedDevice!.name ?? _connectedDevice!.address}'),
          ],
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            // Stop scanning when FAB is pressed
            _bluetoothAdvanced.stopDeviceScan();
          },
          tooltip: 'Stop Scanning',
          child: Icon(Icons.stop),
        ),
      ),
    );
  }
}

注意事项

  1. 权限处理:在Android上,你需要处理位置权限请求,因为蓝牙扫描需要位置权限。在iOS上,蓝牙权限通常是自动处理的,但确保在Info.plist中添加了适当的蓝牙使用描述。

  2. 错误处理:在实际应用中,你应该添加更多的错误处理逻辑,以确保应用的健壮性。

  3. 平台特定代码:某些蓝牙操作可能需要在iOS和Android上分别处理,因此可能需要使用平台通道(Platform Channels)来编写特定于平台的代码。

  4. 依赖更新:由于插件和Flutter框架可能会更新,请确保你使用的是最新版本的bluetooth_advanced插件,并查看其文档以获取最新的API信息和最佳实践。

这个示例代码提供了一个基本的框架,你可以在此基础上扩展以实现更复杂的功能,如读写蓝牙特征值、订阅特征值通知等。

回到顶部