一、架构设计:跨平台OTA的核心逻辑
关键组件说明:
• flutter_blue_plus:支持三端BLE通信的Flutter插件
• 平台专用库:
• Android:com.nordicsemi.android:dfu
(v2.3.0+)
• iOS:iOSDFULibrary
(v4.13.0+)
• 鸿蒙:基于Hi3861的HDF驱动层改造
二、环境准备:三端差异化配置
- Flutter项目配置
dependencies:
flutter_blue_plus: ^1.8.0 # 支持Android12/鸿蒙3.0
path_provider: ^2.1.1 # DFU包存储
crypto: ^3.0.3 # 校验固件哈希
- 平台特定设置
Android (build.gradle):
dependencies {
implementation 'com.nordicsemi.android:dfu:2.3.0'
implementation 'no.nordicsemi.android:ble:2.7-alpha'
}
iOS (Podfile):
target 'Runner' do
pod 'iOSDFULibrary', '~> 4.13'
end
鸿蒙 (config.json):
{
"deviceType": ["ble"],
"abilities": [{
"name": "DfuService",
"type": "service",
"libs": ["//third_party/nordic_dfu/hdf_dfu.z.so"]
}]
}
三、核心代码实现
- DFU包预处理
Future<File> _prepareDfuPackage() async {
final zipFile = await _getDfuZipFromCloud(); // 从云端下载
_validateChecksum(zipFile); // CRC32校验
return _extractBinFile(zipFile); // 解压得到application.bin
}
bool _validateChecksum(File file) {
final expectedHash = 'a1b2c3...';
final actualHash = sha256.convert(file.readAsBytesSync()).toString();
if (actualHash != expectedHash) throw Exception('固件校验失败');
return true;
}
- 跨平台BLE连接控制
Future<void> _connectToBootloader() async {
final device = await FlutterBluePlus.scan().firstWhere((d) =>
d.localName?.contains('DfuTarg') ?? false);
await device.connect(autoConnect: false);
await device.discoverServices();
// 检查DFU服务是否存在
final dfuService = device.services?.firstWhere((s) =>
s.uuid == Guid("0000FE59-0000-1000-8000-00805F9B34FB")));
if (dfuService == null) throw Exception('非DFU模式设备');
}
- 平台通道封装
Dart侧调用:
Future<bool> _startDfu(File binFile) async {
if (Platform.isAndroid) {
return await _channel.invokeMethod('startNordicDfu', {
'file_path': binFile.path,
'device_address': device.id
});
} else if (Platform.isIOS) {
return await _channel.invokeMethod('startIosDfu', {
'file_url': binFile.uri.toString()
});
} else if (Platform.isHarmonyOS) {
return await _channel.invokeMethod('startHarmonyDfu', {
'fd': binFile.openSync().fd
});
}
}
Android侧实现 (Kotlin):
@SuppressLint("MissingPermission")
override fun onMethodCall(call: MethodCall, result: Result) {
when (call.method) {
"startNordicDfu" -> {
val starter = DfuServiceInitiator(call.argument("device_address"))
.setZip(call.argument("file_path"))
.setKeepBond(true)
starter.start(context, DfuService::class.java)
}
}
}
鸿蒙侧实现 (C++):
static napi_value StartHarmonyDfu(napi_env env, napi_callback_info info) {
int fd;
napi_get_value_int32(env, info[0], &fd);
hdf_dfu_start(fd); // 调用HDF驱动层
return nullptr;
}
四、性能优化关键点
-
传输速率对比 (nRF52840)
| 平台 | 默认速率 | 优化后速率 | 优化手段 |
|------------|----------|------------|---------|
| Android | 8KB/s | 22KB/s | 启用High Speed BLE |
| iOS | 6KB/s | 18KB/s | 调整MTU=247 |
| HarmonyOS | 5KB/s | 15KB/s | 启用DMA传输 | -
异常处理策略
enum DfuError {
connectionLost, // 连接断开
invalidFirmware, // 固件不匹配
timeout, // 超时
unsupportedDevice // 设备不支持
}
Future<void> _safeDfu() async {
try {
await _startDfu();
} on PlatformException catch (e) {
if (e.code == 'DFU_ABORTED') {
_retryWithLowerSpeed(); // 降级到1Mbps模式
}
} on DfuError catch (e) {
_showErrorDialog(e.toUserMessage());
}
}
- 进度通知统一化
// 三端统一进度回调
_channel.setMethodCallHandler((call) {
switch (call.method) {
case 'onProgress':
_updateProgress(call.arguments['percent']);
break;
case 'onCompleted':
_showSuccess();
break;
}
});
五、实战案例:智能手环OTA
特殊处理项:
- 电量检测:低于20%时禁止升级
if (device.batteryLevel < 20) { throw DfuError('电量不足'); }
- 双Bank切换:
// Nordic SDK配置 #define DFU_APP_DATA_RESERVED 0x8000
- 跨版本校验:
bool _checkVersionCompatibility() { return _newVersion > _currentVersion && _newVersion - _currentVersion < 0x10; }
六、发布与监控方案
- 灰度发布策略
- 异常监控看板
| 指标 | 预警阈值 | 监控工具 |
|---------------------|----------|------------------|
| OTA成功率 | <95% | Sentry+Firebase |
| 平均耗时 | >300s | Prometheus |
| 内存峰值 | >150MB | Android Profiler|
结语:一次编写,三端生效
“当你的Flutter代码同时在iPhone、华为Mate60和鸿蒙开发板上完成nRF5340的固件升级时,那种征服三端的快感,正是跨平台开发的终极浪漫。”