Flutter北欧芯片固件更新插件flutter_nordic_dfu的使用

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

Flutter北欧芯片固件更新插件flutter_nordic_dfu的使用

简介

flutter-nordic-dfu 是一个用于通过Flutter应用程序对Nordic Semiconductor的nRF51或nRF52芯片进行设备固件更新(DFU)的库。它支持Android和iOS平台,可以方便地集成到你的Flutter项目中。

示例项目

要运行示例项目,请按照以下步骤操作:

  1. 添加DFU文件:将你的DFU ZIP文件添加到 example/assets/file.zip
  2. 运行示例项目:在终端中运行 flutter run 启动示例项目。
  3. 扫描设备:应用程序会自动扫描附近的蓝牙设备。
  4. 开始DFU:选择一个设备并点击“Start Dfu”按钮开始固件更新。

使用方法

startDFU

startDFU 方法用于启动固件更新过程。你可以传递绝对文件路径或资产文件路径给 FlutterNordicDfu

使用绝对文件路径
/// 你可以定义自己的ProgressListener
await FlutterNordicDfu.startDfu(
  'EB:75:AD:E3:CA:CF', '/file/to/zip/path/file.zip',
  progressListener: ProgressListenerListener(),
);

class ProgressListenerListener extends DfuProgressListenerAdapter {
  [@override](/user/override)
  void onProgressChanged(String deviceAddress, int percent, double speed, double avgSpeed, int currentPart, int partsTotal) {
    super.onProgressChanged(deviceAddress, percent, speed, avgSpeed, currentPart, partsTotal);
    print('deviceAddress: $deviceAddress, percent: $percent');
  }
}

/// 或者你可以使用DefaultDfuProgressListenerAdapter
await FlutterNordicDfu.startDfu(
  'EB:75:AD:E3:CA:CF',
  'assets/file.zip',
  fileInAsset: true,
  progressListener: DefaultDfuProgressListenerAdapter(onProgressChangedHandle: (
    deviceAddress,
    percent,
    speed,
    avgSpeed,
    currentPart,
    partsTotal,
  ) {
    print('deviceAddress: $deviceAddress, percent: $percent');
  }),
);
使用资产文件路径
/// 只需设置 [fileInAsset] 为 true
await FlutterNordicDfu.startDfu(
  'EB:75:AD:E3:CA:CF', 'assets/file.zip',
  progressListener: ProgressListenerListener(),
  fileInAsset: true,
);

class ProgressListenerListener extends DfuProgressListenerAdapter {
  [@override](/user/override)
  void onProgressChanged(String deviceAddress, int percent, double speed, double avgSpeed, int currentPart, int partsTotal) {
    super.onProgressChanged(deviceAddress, percent, speed, avgSpeed, currentPart, partsTotal);
    print('deviceAddress: $deviceAddress, percent: $percent');
  }
}

完整示例Demo

以下是一个完整的示例项目代码,展示了如何使用 flutter_nordic_dfu 插件进行固件更新。

import 'dart:async';

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

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final FlutterBlue flutterBlue = FlutterBlue.instance;
  StreamSubscription<ScanResult> scanSubscription;
  List<ScanResult> scanResults = <ScanResult>[];
  bool dfuRunning = false;
  int dfuRunningInx;

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

  Future<void> doDfu(String deviceId) async {
    stopScan();
    dfuRunning = true;
    try {
      var s = await FlutterNordicDfu.startDfu(
        deviceId,
        'assets/file.zip',
        fileInAsset: true,
        progressListener: DefaultDfuProgressListenerAdapter(onProgressChangedHandle: (
          deviceAddress,
          percent,
          speed,
          avgSpeed,
          currentPart,
          partsTotal,
        ) {
          print('deviceAddress: $deviceAddress, percent: $percent');
        }),
      );
      print(s);
      dfuRunning = false;
    } catch (e) {
      dfuRunning = false;
      print(e.toString());
    }
  }

  void startScan() async {
    scanSubscription?.cancel();
    await flutterBlue.stopScan();
    setState(() {
      scanResults.clear();
      scanSubscription = flutterBlue.scan().listen(
        (scanResult) {
          if (scanResults.firstWhere(
                  (ele) => ele.device.id == scanResult.device.id,
                  orElse: () => null) !=
              null) {
            return;
          }
          setState(() {
            /// add result to results if not added
            scanResults.add(scanResult);
          });
        },
      );
    });
  }

  void stopScan() {
    scanSubscription?.cancel();
    scanSubscription = null;
    setState(() => scanSubscription = null);
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    final isScanning = scanSubscription != null;
    final hasDevice = scanResults.length > 0;

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
          actions: <Widget>[
            isScanning
                ? IconButton(
                    icon: Icon(Icons.pause_circle_filled),
                    onPressed: dfuRunning ? null : stopScan,
                  )
                : IconButton(
                    icon: Icon(Icons.play_arrow),
                    onPressed: dfuRunning ? null : startScan,
                  )
          ],
        ),
        body: !hasDevice
            ? const Center(
                child: const Text('No device'),
              )
            : ListView.separated(
                padding: const EdgeInsets.all(8),
                itemBuilder: _deviceItemBuilder,
                separatorBuilder: (context, index) => const SizedBox(height: 5),
                itemCount: scanResults.length,
              ),
      ),
    );
  }

  Widget _deviceItemBuilder(BuildContext context, int index) {
    var result = scanResults[index];
    return DeviceItem(
      isRunningItem: (dfuRunningInx == null ? false : dfuRunningInx == index),
      scanResult: result,
      onPress: dfuRunning
          ? () async {
              await FlutterNordicDfu.abortDfu();
              setState(() {
                dfuRunningInx = null;
              });
            }
          : () async {
              setState(() {
                dfuRunningInx = index;
              });
              await this.doDfu(result.device.id.id);
              setState(() {
                dfuRunningInx = null;
              });
            },
    );
  }
}

class ProgressListenerListener extends DfuProgressListenerAdapter {
  [@override](/user/override)
  void onProgressChanged(String deviceAddress, int percent, double speed, double avgSpeed, int currentPart, int partsTotal) {
    super.onProgressChanged(deviceAddress, percent, speed, avgSpeed, currentPart, partsTotal);
    print('deviceAddress: $deviceAddress, percent: $percent');
  }
}

class DeviceItem extends StatelessWidget {
  final ScanResult scanResult;
  final VoidCallback onPress;
  final bool isRunningItem;

  DeviceItem({this.scanResult, this.onPress, this.isRunningItem});

  [@override](/user/override)
  Widget build(BuildContext context) {
    var name = "Unknow";
    if (scanResult.device.name != null && scanResult.device.name.length > 0) {
      name = scanResult.device.name;
    }
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Row(
          children: <Widget>[
            Icon(Icons.bluetooth),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Text(name),
                  Text(scanResult.device.id.id),
                  Text("RSSI: ${scanResult.rssi}"),
                ],
              ),
            ),
            TextButton(
                onPressed: onPress,
                child: isRunningItem ? Text("Abort Dfu") : Text("Start Dfu"))
          ],
        ),
      ),
    );
  }
}

更多关于Flutter北欧芯片固件更新插件flutter_nordic_dfu的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter北欧芯片固件更新插件flutter_nordic_dfu的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用 flutter_nordic_dfu 插件来更新北欧芯片(Nordic Semiconductor)固件的 Flutter 示例代码。这个插件通常用于与 nRF 设备进行固件更新(DFU)。

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

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

然后运行 flutter pub get 来获取依赖。

示例代码

以下是一个基本的 Flutter 应用示例,它演示了如何使用 flutter_nordic_dfu 插件进行固件更新。

主应用文件(main.dart

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Nordic DFU Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: DfuScreen(),
    );
  }
}

class DfuScreen extends StatefulWidget {
  @override
  _DfuScreenState createState() => _DfuScreenState();
}

class _DfuScreenState extends State<DfuScreen> {
  String _status = "Not started";

  void _startDfu(String deviceAddress, String firmwareUrl) async {
    setState(() {
      _status = "Starting DFU...";
    });

    try {
      // 初始化DFU控制器
      final dfuController = DfuController();

      // 发起DFU更新
      await dfuController.startDfu(
        deviceAddress: deviceAddress,
        firmwareUrl: firmwareUrl,
        initPackets: 1,
        packetReceiptNotificationsEnabled: true,
        secureDfuEnabled: false, // 根据需要启用安全DFU
      );

      setState(() {
        _status = "DFU successful!";
      });
    } catch (e) {
      setState(() {
        _status = "DFU failed: ${e.message}";
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Nordic DFU Example'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('DFU Status:', style: TextStyle(fontSize: 18)),
            Text(_status, style: TextStyle(fontSize: 16)),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                // 替换为实际的设备地址和固件URL
                final deviceAddress = "XX:XX:XX:XX:XX:XX";
                final firmwareUrl = "https://example.com/firmware.zip";
                _startDfu(deviceAddress, firmwareUrl);
              },
              child: Text('Start DFU'),
            ),
          ],
        ),
      ),
    );
  }
}

注意事项

  1. 设备地址:替换 XX:XX:XX:XX:XX:XX 为你的实际设备蓝牙地址。
  2. 固件URL:替换 https://example.com/firmware.zip 为你的实际固件文件URL。
  3. 权限:确保你的应用具有访问蓝牙设备的权限,并在 AndroidManifest.xml 中声明必要的权限。
  4. 错误处理:示例代码中的错误处理相对简单,实际使用中可能需要更详细的错误处理逻辑。

Android 配置

AndroidManifest.xml 中添加蓝牙权限:

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

iOS 配置

Info.plist 中添加蓝牙使用描述:

<key>NSBluetoothAlwaysUsageDescription</key>
<string>App needs bluetooth access to update device firmware.</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>App needs bluetooth access to update device firmware.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>App needs location access to scan for bluetooth devices.</string>

通过以上步骤,你应该能够使用 flutter_nordic_dfu 插件来更新北欧芯片的固件。如果你遇到任何问题,建议查看插件的官方文档或 GitHub 仓库以获取更多信息和帮助。

回到顶部