Flutter北欧芯片固件更新插件flutter_nordic_dfu的使用
Flutter北欧芯片固件更新插件flutter_nordic_dfu的使用
简介
flutter-nordic-dfu
是一个用于通过Flutter应用程序对Nordic Semiconductor的nRF51或nRF52芯片进行设备固件更新(DFU)的库。它支持Android和iOS平台,可以方便地集成到你的Flutter项目中。
示例项目
要运行示例项目,请按照以下步骤操作:
- 添加DFU文件:将你的DFU ZIP文件添加到
example/assets/file.zip
。 - 运行示例项目:在终端中运行
flutter run
启动示例项目。 - 扫描设备:应用程序会自动扫描附近的蓝牙设备。
- 开始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
更多关于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'),
),
],
),
),
);
}
}
注意事项
- 设备地址:替换
XX:XX:XX:XX:XX:XX
为你的实际设备蓝牙地址。 - 固件URL:替换
https://example.com/firmware.zip
为你的实际固件文件URL。 - 权限:确保你的应用具有访问蓝牙设备的权限,并在 AndroidManifest.xml 中声明必要的权限。
- 错误处理:示例代码中的错误处理相对简单,实际使用中可能需要更详细的错误处理逻辑。
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 仓库以获取更多信息和帮助。