资讯动态

Android 实战:将 Nordic nRF Connect Device Manager 集成到自己的 App

发布时间:2026/10/30 4:08:31 来源:尧图企业网站定制
github 旧链接https://github.com/JuulLabs-OSS/mcumgr-androidgithub 新链接https://github.com/NordicSemiconductor/Android-nRF-Connect-Device-ManagerAndroid 实战将 Nordic nRF Connect Device Manager 集成到自己的 App本文介绍如何将 Nordic Semiconductor 的 Android-nRF-Connect-Device-Manager 集成到自己的 Android 应用实现 BLE 设备连接、MCU Manager 命令调用和 OTA 固件升级。开发语言Kotlin开发平台Android Studio通信方式Bluetooth Low EnergyBLE管理协议SMPSimple Management Protocol设备端支持 MCU Manager / SMP 的 Zephyr 或 nRF Connect SDK 设备官方项目Android-nRF-Connect-Device-Manager一、为什么要使用 Device Manager在开发 BLE 嵌入式产品时Android App 经常需要实现以下功能连接设备并读取设备信息。查询设备运行状态和统计数据。读取设备日志。修改设备配置。执行设备复位等管理操作。通过 BLE 对设备进行 OTA 固件升级。如果所有功能都从零开发Android 端不仅需要实现 BLE 连接、GATT 特征读写和数据收发还需要实现管理协议的数据编码、响应解析、超时处理、固件分包上传和升级状态管理。Nordic 提供的Android-nRF-Connect-Device-Manager就是为这类场景准备的开源库。官方项目地址https://github.com/NordicSemiconductor/Android-nRF-Connect-Device-Manager该库兼容 nRF Connect SDK、Zephyr 和 Apache Mynewt 中的 MCU Manager 管理子系统提供协议实现和 BLE 传输实现。它不仅能用于固件升级还能用于设备统计、日志、配置、文件系统及 Shell 操作。官方文档GitHub READMENordic Device Manager 官方文档API Reference本文的目标不是重新实现整个协议而是学习如何把现有库集成到自己的 Android App 中并在此基础上开发业务界面。二、先理解整体架构在集成代码之前需要先弄清楚 Android App、Device Manager 和嵌入式设备之间的关系。┌───────────────────────────────────────┐ │ 自己开发的 Android App │ │ │ │ 设备列表 / 设备详情 / OTA / 日志 / 配置 │ └───────────────────┬───────────────────┘ │ ▼ ┌───────────────────────────────────────┐ │ Android-nRF-Connect-Device-Manager │ │ │ DefaultManager / ImageManager │ │ StatsManager / LogManager / 其他接口 │ └───────────────────┬───────────────────┘ │ ▼ ┌───────────────────────────────────────┐ │ McuMgrTransport │ │ │ │ McuMgrBleTransport │ └───────────────────┬───────────────────┘ │ ▼ ┌───────────────────────────────────────┐ │ BLE GATT │ │ │ │ SMP 数据传输 │ └───────────────────┬───────────────────┘ │ ▼ ┌───────────────────────────────────────┐ │ 设备端 MCU Manager / SMP │ │ │ │ 处理命令、读取状态、上传固件镜像 │ └───────────────────┬───────────────────┘ │ ▼ ┌───────────────────────────────────────┐ │ 应用程序 / Bootloader / Flash │ │ │ │ 固件升级、镜像验证和启动 │ └───────────────────────────────────────┘整个过程可以分成三层。2.1 Android 业务层这是开发者自己维护的代码负责设备列表、用户操作、固件文件选择、升级进度展示和错误提示。这一层不应该直接处理 SMP 数据包的编码与解析。2.2 Device Manager 协议层这一层负责封装 MCU Manager 命令。例如读取设备统计信息、管理固件镜像、执行复位等操作都可以通过对应的 Manager 类完成。官方库已经提供了多种 Manager开发者不需要为每个管理命令单独实现一套协议。2.3 设备端设备端必须支持相应的 SMP 管理服务。如果设备只支持普通 BLE GATT 通信没有实现 SMP那么即使 Android App 成功连接设备也不能直接使用 Device Manager 完成管理操作。对于固件升级设备端还必须具备与升级方案相匹配的镜像管理和 Bootloader 配置。三、选择正确的依赖版本这是集成过程中非常重要的一步。官方项目的版本演进中存在 API 和包名变化因此不能随意复制旧版本教程中的代码。官方 README 明确说明从 3.0.0 开始包名从io.runtime.mcumgr变更为no.nordicsemi.android.mcumgr。2.x 版本应参考相应的版本分支或标签。mcumgr-ble是传统 BLE 传输实现。新版仓库还提供了基于 Kotlin BLE Library 的mcumgr-ble2但其 API 与传统实现不同且官方将其标注为实验性模块。参考[官方 README - Importing](https://github.com/NordicSemiconductor/Android-nRF-Connect-Device-Manager# importing)为避免混用不同版本的 API本文先使用传统的mcumgr-ble方案进行讲解。3.1 添加 Gradle 依赖打开 Android 项目的模块级app/build.gradle.kts添加dependencies{implementation(no.nordicsemi.android:mcumgr-ble:3.4.1)}这里使用3.4.1作为示例版本。该版本可在官方 Releases 页面查到。官方发布页https://github.com/NordicSemiconductor/Android-nRF-Connect-Device-Manager/releases实际项目中建议先确认仓库当前最新稳定版本并固定一个经过验证的版本号。不要在未经测试的情况下直接升级生产项目依赖。添加依赖后在 Android Studio 中执行 Gradle Sync。如果依赖无法下载先检查项目是否配置了 Maven Central 仓库以及网络环境是否允许访问依赖源。3.2 为什么选择 mcumgr-blemcumgr-ble已包含核心协议模块以及基于 Nordic Android BLE Library 的 BLE 传输实现。因此大多数只需要 BLE 设备管理功能的 Android 项目可以直接从这个依赖开始。如果项目已经使用 Nordic Kotlin BLE Library并且希望统一管理 BLE 连接也可以研究新版mcumgr-ble2。但它不能与mcumgr-ble同时加入同一个 App因为两个模块定义了相同包名下的相关类API 也不同。本文后续代码以mcumgr-ble为基础不混用mcumgr-ble2的接口。四、配置 Android BLE 权限Android BLE 扫描和连接需要正确配置权限。打开app/src/main/AndroidManifest.xml。以下是常见权限配置示例manifestxmlns:androidhttp://schemas.android.com/apk/res/android!-- Android 11 及更低版本常用的 BLE 权限 --uses-permissionandroid:nameandroid.permission.BLUETOOTHandroid:maxSdkVersion30/uses-permissionandroid:nameandroid.permission.BLUETOOTH_ADMINandroid:maxSdkVersion30/!-- Android 11 及更低版本扫描 BLE 时可能需要位置权限 --uses-permissionandroid:nameandroid.permission.ACCESS_FINE_LOCATIONandroid:maxSdkVersion30/!-- Android 12 及以上版本 --uses-permissionandroid:nameandroid.permission.BLUETOOTH_SCANandroid:usesPermissionFlagsneverForLocation/uses-permissionandroid:nameandroid.permission.BLUETOOTH_CONNECT/applicationandroid:allowBackuptrueandroid:labelMy Device Managerandroid:supportsRtltrue!-- Activity 配置 --/application/manifest以上配置是常见的 BLE 权限方案具体仍需根据 App 的minSdk、targetSdk和扫描用途调整。注意以下几点Android 12API 31及以上版本需要按系统版本申请BLUETOOTH_SCAN和BLUETOOTH_CONNECT等运行时权限。Android 11 及更低版本的 BLE 扫描可能需要位置权限部分设备还要求开启系统定位服务。neverForLocation仅适用于 App 不将 BLE 扫描结果用于推断位置的情况。使用该标志还可能影响某些 Beacon 的扫描结果。Manifest 中声明权限并不代表运行时权限已经获得。扫描和连接之前需要检查并请求相应权限。如果 App 需要在后台持续连接或扫描还应单独评估 Android 后台执行和前台服务限制。Android 官方权限文档https://developer.android.com/develop/connectivity/bluetooth/bt-permissions五、先完成 BLE 扫描和连接Device Manager 的 BLE 传输层需要一个已经选定的 AndroidBluetoothDevice对象。因此业务层通常先完成设备扫描和连接再把设备交给 Device Manager。需要特别区分两个概念Android 系统层面的 BLE 连接。SMP 管理协议层面的请求和响应。BLE 连接成功只是第一步后续还需要验证设备端是否提供了 SMP 服务。5.1 获取 BluetoothDevice假设你的 App 已经完成扫描并且用户从设备列表中选择了目标设备。可以在扫描结果中取得valbluetoothDevicescanResult.device这里的scanResult是 Android BLE 扫描得到的ScanResult。如果你使用的是自己的 BLE 管理框架也可以把它提供的BluetoothDevice对象传给 Device Manager。不要在设备管理模块内部重复实现一套扫描逻辑除非你明确希望该模块独立负责设备发现。5.2 BLE 扫描的基本结构如果还没有扫描代码可以使用 Android 原生BluetoothLeScanner。以下示例只展示扫描的核心结构运行前必须先获得对应的运行时权限。privatevalbluetoothAdapter:BluetoothAdapterbylazy{valmanagergetSystemService(BluetoothManager::class.java)requireNotNull(manager.adapter)}privatevalscanner:BluetoothLeScannerget()requireNotNull(bluetoothAdapter.bluetoothLeScanner)privatevalscanCallbackobject:ScanCallback(){overridefunonScanResult(callbackType:Int,result:ScanResult){valdeviceresult.device// 将 device 添加到 UI 设备列表。// 建议根据 address 去重。android.util.Log.d(BLE,Found device:${device.address}, RSSI${result.rssi})}overridefunonScanFailed(errorCode:Int){android.util.Log.e(BLE,Scan failed:$errorCode)}}SuppressLint(MissingPermission)funstartBleScan(){scanner.startScan(scanCallback)}SuppressLint(MissingPermission)funstopBleScan(){scanner.stopScan(scanCallback)}注意SuppressLint(MissingPermission)只用于告诉静态检查器调用位置已经处理权限不能替代真实的运行时权限检查。实际项目应在扫描开始前检查蓝牙是否开启。应在适当的生命周期节点停止扫描避免不必要的功耗。应在 UI 中区分扫描中、扫描结束、连接中和已连接状态。这个示例没有包含完整的权限申请和 UI 代码适合作为扫描模块的起点。六、创建 McuMgrBleTransport现在进入 Device Manager 的核心部分。官方 README 提供了以下 Java 风格的创建方式McuMgrTransporttransportnewMcuMgrBleTransport(context,bluetoothDevice);对应的 Kotlin 写法可以是importandroid.bluetooth.BluetoothDeviceimportandroid.content.Contextimportno.nordicsemi.android.mcumgr.McuMgrTransportimportno.nordicsemi.android.mcumgr.ble.McuMgrBleTransportfuncreateTransport(context:Context,device:BluetoothDevice):McuMgrTransport{returnMcuMgrBleTransport(context.applicationContext,device)}这段代码展示的是传统mcumgr-ble模块的传输对象创建方式。McuMgrTransport表示管理协议使用的传输接口McuMgrBleTransport则提供基于 BLE 的实现。后续创建各类 Manager 时就可以把这个传输对象传进去。版本核对提示如果实际工程中的包路径或构造函数与上述示例不一致应优先检查所安装依赖对应的 API Reference 和官方 Sample不要把mcumgr-ble2的构造方式混入本示例。另外创建McuMgrBleTransport并不等于已经完成 SMP 请求。真正的命令调用仍需由对应的 Manager 发起。七、调用 Manager 实现设备管理功能官方库把不同类型的管理命令组织成多个 Manager。常见的管理类如下Manager主要用途DefaultManager设备复位、系统相关命令和统计信息ImageManager镜像管理与固件上传StatsManager读取设备统计信息SettingsManager读取和修改设备设置LogManager读取设备日志FsManager设备文件系统的上传与下载ShellManager执行设备端 Shell 命令BasicManager支持的设备存储擦除等操作这些类并不意味着每台设备都支持全部功能。具体能力取决于设备端启用的管理命令组和固件配置。7.1 创建管理对象例如需要读取设备统计信息时可以创建StatsManager。importno.nordicsemi.android.mcumgr.McuMgrTransportimportno.nordicsemi.android.mcumgr.managers.StatsManagerfuncreateStatsManager(transport:McuMgrTransport):StatsManager{returnStatsManager(transport)}这段代码展示管理对象与传输对象之间的关系。实际发起统计信息请求时应继续参考当前版本的StatsManager方法签名并按其要求处理回调、异常和响应对象。不同 Manager 的调用方式并不完全相同因此不应假设所有管理命令都使用同一个方法。7.2 建议先验证 Echo 或简单管理命令首次集成时不建议直接从 OTA 开始。更稳妥的顺序是确认设备可以被扫描到。确认 BLE 连接正常。创建McuMgrBleTransport。使用设备端支持的简单管理命令验证请求和响应。再尝试读取统计信息或执行复位。最后集成固件升级。Echo 一类的简单请求适合验证通信链路但具体命令接口应以当前版本的 API Reference 为准。如果命令超时应检查设备端 SMP 服务、GATT 传输配置和日志而不是仅凭 BLE 已连接就认定通信正常。八、设计自己的设备管理封装层直接在 Activity 中创建各种 Manager 虽然能快速验证功能但不适合长期维护。建议在业务层与第三方库之间增加一个自己的封装类。例如app/ ├── ui/ │ ├── DeviceListActivity.kt │ ├── DeviceDetailActivity.kt │ └── FirmwareUpdateActivity.kt │ ├── device/ │ ├── DeviceConnectionManager.kt │ └── DeviceManagerRepository.kt │ └── firmware/ └── FirmwareUpdateRepository.kt可以按以下职责划分DeviceConnectionManager负责 BLE 连接生命周期和连接状态。DeviceManagerRepository负责创建传输对象、管理对象和执行管理命令。FirmwareUpdateRepository负责固件文件准备、升级启动、进度和结果。UI 层只负责展示状态和响应用户操作。这里的类名是建议的项目结构并非 Nordic 官方规定的类名。这种封装方式的优势在于未来如果更换 BLE 连接实现或升级库版本业务 UI 不需要跟着大范围修改。同时应明确传输对象的所有权连接断开时要按实际使用的传输实现和 BLE 库的生命周期规则释放或重建资源避免重复创建连接或继续向已经失效的传输对象发送请求。九、集成 OTA 固件升级如果 App 的核心需求是固件升级就需要使用FirmwareUpgradeManager。官方 README 给出的典型升级流程包括上传固件镜像。测试新镜像或确认新镜像。复位设备。在相应模式下确认升级结果。该流程由FirmwareUpgradeManager负责组织并通过FirmwareUpgradeCallback报告升级状态。官方示例https://github.com/NordicSemiconductor/Android-nRF-Connect-Device-Manager#firmware-upgrade9.1 创建 FirmwareUpgradeManager官方 README 的基本结构如下McuMgrTransporttransportnewMcuMgrBleTransport(context,bluetoothDevice);FirmwareUpgradeManagerdfuManagernewFirmwareUpgradeManager(transport,dfuCallback);对应的 Kotlin 结构如下importandroid.bluetooth.BluetoothDeviceimportandroid.content.Contextimportno.nordicsemi.android.mcumgr.McuMgrTransportimportno.nordicsemi.android.mcumgr.ble.McuMgrBleTransportimportno.nordicsemi.android.mcumgr.dfu.FirmwareUpgradeManagerimportno.nordicsemi.android.mcumgr.dfu.FirmwareUpgradeCallbackfuncreateFirmwareUpgradeManager(context:Context,device:BluetoothDevice,callback:FirmwareUpgradeCallback):FirmwareUpgradeManager{valtransport:McuMgrTransportMcuMgrBleTransport(context.applicationContext,device)returnFirmwareUpgradeManager(transport,callback)}这段代码演示升级管理对象的创建方式。实际开发时还需要根据当前依赖版本实现FirmwareUpgradeCallback所要求的回调方法并将升级状态转换为 UI 可以观察的状态。9.2 配置升级模式官方库支持不同的升级模式。模式流程概述适用情况TEST_AND_CONFIRM上传、测试、复位、确认设备端支持可回滚的测试升级CONFIRM_ONLY上传、确认、复位不支持回滚的设备等场景TEST_ONLY上传、测试、复位希望由应用或测试流程稍后确认NONE上传、复位例如符合条件的 Direct-XIP 无回滚配置模式必须与设备端 Bootloader 和镜像管理机制匹配。特别是多核设备不能简单套用单核设备的升级配置。官方 README 指出nRF5340 等多核设备在相应实现中存在升级模式限制。9.3 启动升级官方 README 的核心调用形式为dfuManager.setMode(mode);dfuManager.start(image,advancedSettings);其中image是符合设备端升级要求的固件镜像数据。advancedSettings是升级参数配置。mode决定镜像上传之后如何执行测试、确认和复位。为了避免在不同库版本之间误用 API建议直接从官方 Sample 中找到当前版本的完整升级实现并重点阅读以下内容固件文件如何读取。固件镜像是否需要从 ZIP 包中解压。FirmwareUpgradeManager.Settings如何构建。FirmwareUpgradeCallback如何接收状态变化。升级失败时如何显示错误。设备重启后如何重新连接。不要直接把任意二进制文件传入start()就认为 OTA 一定可以工作。固件镜像格式、签名、分区布局、Bootloader 配置和升级模式必须与设备端匹配。9.4 如何处理升级进度升级界面通常至少需要显示以下状态未开始 │ ▼ 验证固件 │ ▼ 上传镜像 │ ▼ 等待测试 / 确认 │ ▼ 设备复位 │ ▼ 重新连接并验证版本 │ ▼ 升级完成这是业务层的状态展示示例不代表库的回调枚举一定与这些名称完全一致。实际开发中应把FirmwareUpgradeCallback提供的状态转换为自己的 UI 状态并区分“镜像上传成功”和“设备升级完成”。特别需要注意设备重启后 BLE 连接可能中断。App 应能够识别预期的断开、重新扫描设备并在重新连接后验证固件版本或设备状态。十、几个容易忽略的工程问题10.1 不要混用不同版本的包名旧版代码可能使用importio.runtime.mcumgr.*3.x 版本则使用importno.nordicsemi.android.mcumgr.*如果项目编译时报找不到类首先检查依赖版本与导入路径是否一致。10.2 不要同时引入 mcumgr-ble 和 mcumgr-ble2这两个模块的传输实现不同不能当成可随意替换的同一套 API。如果你当前使用的是implementation(no.nordicsemi.android:mcumgr-ble:3.4.1)就先按照传统McuMgrBleTransport(context, bluetoothDevice)的方式集成。如果决定改用mcumgr-ble2则应按照其对应版本的文档使用CentralManager、Peripheral等接口并检查连接管理逻辑。10.3 不要把 BLE 连接成功等同于 SMP 可用如果手机已经连接设备但管理命令始终超时应检查设备端 SMP Server 是否启用。BLE GATT 的 SMP 服务和特征是否正确配置。Android 端与设备端是否采用兼容的协议实现。请求是否真正发送到设备。设备端是否返回响应。是否存在 MTU、分包或连接中断问题。可以使用 Android 日志、设备串口日志和 BLE 抓包工具共同定位问题。10.4 固件升级必须考虑失败恢复OTA 不只是文件传输。量产项目还需要考虑固件签名和镜像验证。升级过程中断电或断连。Bootloader 回滚机制。新固件启动失败后的恢复。设备版本兼容性。升级完成后的版本确认。这些能力主要取决于设备端固件和 Bootloader 设计不能单靠 Android 库保证。10.5 管理命令需要权限控制某些命令可能修改关键配置、擦除应用数据、执行 Shell 操作或触发复位。正式产品应根据用户角色和设备状态限制这些操作避免把调试功能无条件暴露给所有用户。十一、建议的集成顺序为了降低集成风险可以按照以下顺序推进。阶段工作内容验收目标1添加 Gradle 依赖项目成功编译2配置 Android BLE 权限可以正常扫描设备3实现设备选择和连接可以连接目标设备4创建McuMgrBleTransport传输对象初始化成功5调用简单管理命令能够收到设备响应6接入统计信息或设备复位管理功能正常7集成FirmwareUpgradeManager能够执行完整升级流程8增加错误处理和重连能处理断连与升级异常建议先以官方 Sample 作为参照确保基础链路跑通再逐步替换成自己的 UI 和业务架构。十二、总结Nordic 的 Android-nRF-Connect-Device-Manager 为 Android App 提供了现成的 MCU Manager 协议实现和 BLE 传输能力。对于 Android 开发者集成的关键并不是重新实现 BLE 通信协议而是正确处理以下几个方面选择匹配的库版本。正确配置 Android BLE 权限。完成设备扫描与连接。创建McuMgrBleTransport。使用相应的 Manager 执行设备管理操作。通过FirmwareUpgradeManager集成固件升级。处理异步状态、断连、重试和错误恢复。只要设备端已经实现兼容的 SMP 服务Android 端就可以在现有库的基础上快速构建设备管理功能。对于需要 OTA 的产品建议先使用官方 Sample 验证设备端升级链路再把传输层、管理层和 UI 层拆分封装逐步集成到自己的 Android App 中。参考资料Android-nRF-Connect-Device-Manager 官方 GitHub 仓库官方 API ReferenceNordic nRF Connect Device Manager 文档Android BLE 权限文档Zephyr SMP Server 示例MCUboot 官方项目

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑