Flutter蓝牙通信插件flutter_esp_ble_prov的使用

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

Flutter蓝牙通信插件 flutter_esp_ble_prov 的使用

flutter_esp_ble_prov 是一个用于通过 BLE(蓝牙低功耗)配置 ESP32 设备的 Flutter 插件。该库使用 Espressif 提供的协议库来实现此功能。

要求

iOS

  • iOS 13.0+

Info.plist 文件中添加蓝牙权限:

<key>NSBluetoothAlwaysUsageDescription</key>
<string>Our app uses bluetooth to find, connect and transfer data between different devices</string>

Android

确保 android/app/build.gradle 中的 minSdkVersion 至少为 23。

android/build.gradle 中添加以下仓库到 repositories 部分:

allprojects {
    repositories {
        google()
        mavenCentral()
        maven { url ("https://jitpack.io/") }
    }
}

对于 Android S (API 级别 31) 及以上版本,需要在 AndroidManifest.xml 中进行一些权限设置。具体可以参考 官方文档

示例 Demo

下面是一个完整的示例代码,展示了如何使用 flutter_esp_ble_prov 插件扫描 BLE 设备、Wi-Fi 网络并配置 Wi-Fi。

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

import 'package:flutter_esp_ble_prov/flutter_esp_ble_prov.dart';

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

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _flutterEspBleProvPlugin = FlutterEspBleProv();

  final defaultPadding = 12.0;
  final defaultDevicePrefix = 'PROV';

  List<String> devices = [];
  List<String> networks = [];

  String selectedDeviceName = '';
  String selectedSsid = '';
  String feedbackMessage = '';

  final prefixController = TextEditingController(text: 'PROV_');
  final proofOfPossessionController = TextEditingController(text: 'abcd1234');
  final passphraseController = TextEditingController();

  Future scanBleDevices() async {
    final prefix = prefixController.text;
    final scannedDevices = await _flutterEspBleProvPlugin.scanBleDevices(prefix);
    setState(() {
      devices = scannedDevices;
    });
    pushFeedback('Success: scanned BLE devices');
  }

  Future scanWifiNetworks() async {
    final proofOfPossession = proofOfPossessionController.text;
    final scannedNetworks = await _flutterEspBleProvPlugin.scanWifiNetworks(
        selectedDeviceName, proofOfPossession);
    setState(() {
      networks = scannedNetworks;
    });
    pushFeedback('Success: scanned WiFi on $selectedDeviceName');
  }

  Future provisionWifi() async {
    final proofOfPossession = proofOfPossessionController.text;
    final passphrase = passphraseController.text;
    await _flutterEspBleProvPlugin.provisionWifi(
        selectedDeviceName, proofOfPossession, selectedSsid, passphrase);
    pushFeedback('Success: provisioned WiFi $selectedDeviceName on $selectedSsid');
  }

  pushFeedback(String msg) {
    setState(() {
      feedbackMessage = '$feedbackMessage\n$msg';
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('ESP BLE Provisioning Example'),
          actions: [
            IconButton(
                icon: const Icon(Icons.bluetooth),
                onPressed: () async {
                  await scanBleDevices();
                }),
          ],
        ),
        bottomSheet: SafeArea(
          child: Container(
            width: double.infinity,
            color: Colors.black87,
            padding: EdgeInsets.all(defaultPadding),
            child: Text(
              feedbackMessage,
              style: TextStyle(
                  fontWeight: FontWeight.bold, color: Colors.green.shade600),
            ),
          ),
        ),
        body: SafeArea(
          child: Container(
            padding: EdgeInsets.all(defaultPadding),
            child: Column(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                Flexible(
                  child: Container(
                    padding: EdgeInsets.all(defaultPadding),
                    child: Row(
                      mainAxisSize: MainAxisSize.max,
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        const Flexible(
                          child: Text('Device Prefix'),
                        ),
                        Expanded(
                          child: TextField(
                            controller: prefixController,
                            decoration: const InputDecoration(
                                hintText: 'enter device prefix'),
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
                Flexible(
                  child: Container(
                    padding: EdgeInsets.all(defaultPadding),
                    child: const Text('BLE devices'),
                  ),
                ),
                Expanded(
                  child: ListView.builder(
                    itemCount: devices.length,
                    itemBuilder: (context, i) {
                      return ListTile(
                        title: Text(
                          devices[i],
                          style: TextStyle(
                            color: Colors.blue.shade700,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                        onTap: () async {
                          selectedDeviceName = devices[i];
                          await scanWifiNetworks();
                        },
                      );
                    },
                  ),
                ),
                Flexible(
                  child: Container(
                    padding: EdgeInsets.all(defaultPadding),
                    child: Row(
                      mainAxisSize: MainAxisSize.max,
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        const Flexible(
                          child: Text('Proof of possession'),
                        ),
                        Expanded(
                          child: TextField(
                            controller: proofOfPossessionController,
                            decoration: const InputDecoration(
                                hintText: 'enter proof of possession string'),
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
                Flexible(
                  child: Container(
                    padding: EdgeInsets.all(defaultPadding),
                    child: const Text('WiFi networks'),
                  ),
                ),
                Expanded(
                  child: ListView.builder(
                    itemCount: networks.length,
                    itemBuilder: (context, i) {
                      return ListTile(
                        title: Text(
                          networks[i],
                          style: TextStyle(
                            color: Colors.green.shade700,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                        onTap: () async {
                          selectedSsid = networks[i];
                          await provisionWifi();
                        },
                      );
                    },
                  ),
                ),
                Flexible(
                  child: Container(
                    padding: EdgeInsets.all(defaultPadding),
                    child: Row(
                      mainAxisSize: MainAxisSize.max,
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        const Flexible(
                          child: Text('WiFi Passphrase'),
                        ),
                        Expanded(
                          child: TextField(
                            controller: passphraseController,
                            decoration: const InputDecoration(
                                hintText: 'enter passphrase'),
                            obscureText: true,
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

这个示例展示了如何使用 flutter_esp_ble_prov 插件进行设备的 BLE 扫描、Wi-Fi 网络扫描以及 Wi-Fi 配置。希望对你有所帮助!


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

1 回复

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


当然,以下是如何在Flutter项目中使用flutter_esp_ble_prov插件进行蓝牙通信的示例代码。这个插件主要用于与ESP32设备上的BLE(蓝牙低功耗)进行通信,尤其是那些使用ESP-IDF(Espressif IoT Development Framework)的设备。

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

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

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

初始化插件

在你的Flutter应用中,你需要初始化flutter_esp_ble_prov插件。这通常在MainActivity.kt(对于Android)或AppDelegate.swift(对于iOS)以及你的Dart代码中完成。但主要是Dart代码部分。

Dart代码示例

以下是一个简单的示例,展示如何初始化插件、扫描设备、连接设备并进行数据读写。

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

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

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

class _MyAppState extends State<MyApp> {
  late FlutterEspBleProv flutterEspBleProv;
  late List<BleDevice> devices = [];
  BleDevice? connectedDevice;

  @override
  void initState() {
    super.initState();
    flutterEspBleProv = FlutterEspBleProv();

    // 初始化插件
    flutterEspBleProv.initialize().then((_) {
      print("FlutterEspBleProv initialized");
      // 开始扫描设备
      startScanning();
    }).catchError((error) {
      print("Initialization failed: $error");
    });
  }

  void startScanning() async {
    flutterEspBleProv.startDeviceScan().listen((event) {
      if (event.devices.isNotEmpty) {
        setState(() {
          devices = event.devices;
        });
      }
    });
  }

  void connectToDevice(BleDevice device) async {
    connectedDevice = device;
    try {
      await flutterEspBleProv.connectToDevice(device.address!);
      print("Connected to ${device.name}");
      // 在这里可以进行读写操作
      // readData();
      // writeData();
    } catch (e) {
      print("Connection failed: $e");
    }
  }

  void readData() async {
    if (connectedDevice != null) {
      try {
        Uint8List data = await flutterEspBleProv.readCharacteristic(
          connectedDevice!.address!,
          "your_service_uuid",
          "your_characteristic_uuid"
        );
        print("Read data: ${data.map((byte) => byte.toRadixString(16).padStart(2, '0')).join('')}");
      } catch (e) {
        print("Read failed: $e");
      }
    }
  }

  void writeData(List<int> data) async {
    if (connectedDevice != null) {
      try {
        await flutterEspBleProv.writeCharacteristic(
          connectedDevice!.address!,
          "your_service_uuid",
          "your_characteristic_uuid",
          Uint8List.fromList(data)
        );
        print("Data written");
      } catch (e) {
        print("Write failed: $e");
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter ESP BLE Prov Example'),
        ),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            children: [
              Text('Scanned Devices:'),
              Expanded(
                child: ListView.builder(
                  itemCount: devices.length,
                  itemBuilder: (context, index) {
                    BleDevice device = devices[index];
                    return ListTile(
                      title: Text(device.name ?? 'Unknown'),
                      subtitle: Text(device.address ?? 'Unknown'),
                      onTap: () => connectToDevice(device),
                    );
                  },
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

注意事项

  1. UUID:在读写数据时,需要替换"your_service_uuid""your_characteristic_uuid"为你的ESP32设备实际使用的UUID。
  2. 错误处理:实际应用中需要更完善的错误处理机制。
  3. 依赖项:确保你的Android和iOS项目配置正确,以支持蓝牙通信。
  4. 权限:在Android上,你需要在AndroidManifest.xml中请求蓝牙权限。在iOS上,你需要在Info.plist中添加相应的蓝牙使用描述。

这个示例只是一个基本框架,你可能需要根据具体需求进行扩展和修改。

回到顶部