Как связать устройство BLE с телефоном с помощью пакета Flutter и flutter_blue?

Я разрабатываю приложение Flutter, в котором мне нужно подключить и связать устройство Bluetooth Low Energy (BLE) с телефоном. Я использую пакет flutter_blue для подключения Bluetooth. Хотя я могу сканировать устройства и подключаться к ним, я пытаюсь справиться с процессом связывания.

Вот фрагмент моего кода для сканирования и подключения к устройствам:

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

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

  @override
  BluetoothLEManagerState createState() => BluetoothLEManagerState();
}

class BluetoothLEManagerState extends State<BluetoothLEManager> with SingleTickerProviderStateMixin {
  FlutterBlue flutterBlue = FlutterBlue.instance;
  List<BluetoothDevice> _devices = [];
  bool _isSearching = false;
  bool _scanCompleted = false;

  @override
  void initState() {
    super.initState();
    startBluetoothScan(isInitialScan: true);
  }

  @override
  void dispose() {
    flutterBlue.stopScan();
    super.dispose();
  }

  void startBluetoothScan({bool isInitialScan = false}) {
    if (_isSearching) return;

    setState(() {
      _isSearching = true;
      _scanCompleted = false;
    });

    flutterBlue.startScan(timeout: const Duration(seconds: 10)).then((_) {
      setState(() {
        _isSearching = false;
        _scanCompleted = true;
      });
    });

    flutterBlue.scanResults.listen((results) {
      setState(() {
        _devices = results.map((r) => r.device).where((device) => device.name.isNotEmpty).toList();
      });
    });

    flutterBlue.isScanning.listen((isScanning) {
      if (!isScanning) {
        print('Scanning stopped');
      }
    });
  }

  Future<void> connectToDevice(BluetoothDevice device) async {
    await device.connect();
    // further code to handle connection and service discovery
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('BLE Devices'),
      ),
      body: ListView.builder(
        itemCount: _devices.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(_devices[index].name),
            onTap: () => connectToDevice(_devices[index]),
          );
        },
      ),
    );
  }
}

Как связать устройство BLE с телефоном с помощью пакета flutter_blue и существует ли определенный метод или процесс, которому я должен следовать, чтобы убедиться, что устройство подключено перед установкой соединения?

Любые рекомендации или пример кода будут с благодарностью оценены.

(То, что я пробовал ниже)

Попытайтесь проверить состояние облигации и пару:

Я попытался проверить состояние связи устройства и инициировать сопряжение, если устройство еще не было сопряжено. Фрагмент кода, который я использовал, был:

Future<void> checkAndPairDevice(BluetoothDevice device) async {
  final BondState bondState = await device.bondState.first;

  if (bondState == BondState.bonded) {
    print('Device is already paired');
  } else {
    print('Device is not paired. Attempting to pair...');
    try {
      await device.pair();
      print('Pairing successful');
    } catch (error) {
      print('Pairing failed: $error');
      return;
    }
  }
}

К сожалению, этот подход не сработал, поскольку пакет flutter_blue не поддерживает методы BondState и Pair напрямую. Я обнаружил ошибки, указывающие на то, что эти методы не определены.

Переключение на пакет flutter_blue_plus:

Я попытался переключиться на пакет flutter_blue_plus, который имеет больше возможностей и активно поддерживается. Однако это привело к многочисленным конфликтам типов и проблемам совместимости между типами flutter_blue и flutter_blue_plus, что сделало интеграцию обоих пакетов непрактичной.

Ручное сопряжение:

Я также рассмотрел возможность вручную предложить пользователю выполнить сопряжение устройств через настройки Bluetooth системы, прежде чем инициировать соединение в приложении. Однако этот подход не обеспечивает бесперебойную работу пользователя и не гарантирует, что приложение сможет программно проверять и обрабатывать сопряжение.

Сопряжение будет выполняться автоматически ОС, как только вы попытаетесь получить доступ к характеристике, требующей шифрования. Есть ли у вашего BLE-устройства такая характеристика? Если не подключаться, достаточно

Michael Kotzjan 08.07.2024 14:53

@MichaelKotzjan Чтобы предоставить больше контекста, я пытался записать данные на устройство BLE с возможностью выбора формата (шестнадцатеричный, символьный, десятичный и т. д.) в моем приложении. Когда я пытался записать строку в характеристику, ожидающую строкового типа, она постоянно отклонялась. Сначала я думал, что проблему можно решить путем сопряжения устройства BLE с телефоном. Однако, похоже, проблема заключается не только в спаривании. Благодарю за ваш ответ. И я не знаю, выполняет ли мое устройство BLE сопряжение автоматически.

DOUINA Mouhamed 08.07.2024 15:14

Сопряжение — это просто обмен ключами шифрования и оно не нужно, если характеристика не использует никаких мер безопасности. Когда ключи обмениваются, а затем сохраняются для дальнейшего использования, мы называем это связыванием. При простом подключении сопряжение и соединение не требуются. Попробуйте использовать универсальный инструмент исследования BLE, например nRF Connect, чтобы протестировать ваше устройство BLE. Если вы не можете отправить строку через nRF Connect, проблема в вашем устройстве, а не в вашем приложении.

Michael Kotzjan 08.07.2024 15:30

@MichaelKotzjan Я считаю, что основная проблема заключается в том, что подключение к устройству BLE не устанавливает автоматически связь между устройством BLE и телефоном. Я проверил это с помощью nRF Connect и BLE Scanner, и соединение не произошло автоматически. Даже попытки вручную связать не увенчались успехом. Похоже, что устройство BLE имеет какую-то функцию безопасности, которая вообще предотвращает соединение.

DOUINA Mouhamed 08.07.2024 16:38

Но действительно ли вам нужна связь? Разве подключения недостаточно для чтения/записи необходимых характеристик?

Michael Kotzjan 09.07.2024 07:15

Я пытался записать данные на устройство BLE, чтобы изменить яркость света. При этом чтение и подписка на характеристики работает нормально, запись - нет. Это похоже на меру безопасности. Рассматриваемая характеристика: Имя характеристики: uuid_bonding UUID: 18E446F6-B870-07DD-021A-08123A051401 Свойства: Read / WriteNoResp / Write / Notify / Indicate Значение: [225] (байты) Эта характеристика должна возвращать [1], если она связана и [0], если он не подключен, но я постоянно получаю [255] (ff) при каждой попытке подключения.

DOUINA Mouhamed 09.07.2024 08:07

Обновление: соединение действительно было необходимо для записи данных на устройство. Я успешно установил соединение и теперь могу выполнять операции записи. Спасибо вам за вашу помощь; это было очень оценено.

DOUINA Mouhamed 09.07.2024 08:34

Рад слышать! Не стесняйтесь ответить на свой вопрос и пометить его как решенный, чтобы другие могли быстрее найти решение :)

Michael Kotzjan 09.07.2024 09:32

Я выложу более чистое решение, как только доработаю его, поскольку текущая реализация довольно жестко запрограммирована. :) Кстати ваша помощь была ценна и полезна.

DOUINA Mouhamed 09.07.2024 09:55
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
75
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Использование flutter_blue устарело из-за нерегулярных обновлений. Вместо этого мы можем использовать flutter_blue_plus, который является ответвлением flutter_blue с более регулярными обновлениями и минимальными необходимыми изменениями. Вот как мы можем попытаться подключиться к устройству Bluetooth с помощью flutter_blue_plus:

import 'dart:io';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:device_info/device_info.dart';

Future<void> attemptBonding(BluetoothDevice device) async {
  // get the device UUID
  DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
  String deviceUUID;

  try {
    if (Platform.isAndroid) {
      AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
      deviceUUID = androidInfo.id;
    } else if (Platform.isIOS) {
      IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
      deviceUUID = iosInfo.identifierForVendor ?? '';
    } else {
      print('Unsupported platform');
      return;
    }
  } catch (e) {
    print('Error getting device UUID: $e');
    return;
  }

  // convert the UUID to a byte array
  List<int> uuidBytes = deviceUUID.codeUnits;

  // function to match the UUID ignoring the first four characters (device name)
  bool matchUUID(String characteristicUUID, String targetUUID) {
    return characteristicUUID.substring(4).toLowerCase() == targetUUID.substring(4).toLowerCase();
  }

  // discover services and characteristics
  List<BluetoothService> services;
  try {
    services = await device.discoverServices();
  } catch (e) {
    print('Error discovering services: $e');
    return;
  }

  // find the bonding characteristic
  BluetoothCharacteristic? bondingCharacteristic;
  for (var service in services) {
    bondingCharacteristic = service.characteristics.firstWhereOrNull(
      (c) => matchUUID(c.uuid.toString(), 'UUID of your device that returns bonding characteristic')
    );
    if (bondingCharacteristic != null) break;
  }

  if (bondingCharacteristic != null) {
    try {
      print('Attempting to write to bonding characteristic...');
      await bondingCharacteristic.write(uuidBytes, withoutResponse: true);
      print('Written UUID to bonding characteristic.');
    } catch (e) {
      print('Error writing to bonding characteristic: $e');
      return;
    }
  } else {
    print('Bonding characteristic not found');
    return;
  }

  // check bonding status
  BluetoothCharacteristic? bondingStatusCharacteristic;
  for (var service in services) {
    bondingStatusCharacteristic = service.characteristics.firstWhereOrNull(
      (c) => matchUUID(c.uuid.toString(), 'UUID of your device that returns bonding status characteristic')
    );
    if (bondingStatusCharacteristic != null) break;
  }

  if (bondingStatusCharacteristic != null) {
    try {
      await Future.delayed(Duration(seconds: 1)); // add a delay to ensure the bonding is processed
      List<int> bondingStatus = await bondingStatusCharacteristic.read();
      print('Bonding status value: $bondingStatus');
      if (bondingStatus.isNotEmpty && bondingStatus[0] == 1) {
        print('Bonding successful.');
      } else {
        print('Bonding failed or not recognized by the device.');
      }
    } catch (e) {
      print('Error reading bonding status: $e');
    }
  } else {
    print('Bonding status characteristic not found');
  }
}

Такой подход обеспечивает лучшую совместимость и регулярные обновления за счет использования flutter_blue_plus, что делает процесс соединения Bluetooth более надежным.

Другие вопросы по теме