从 500 台鸿蒙开发板说起at_onboarding_cli 让我省下了一整周的重复劳动如果你部署过 IoT 设备一定懂这种感觉设备越多快乐越少。去年我负责一个鸿蒙 HarmonyOS 智能终端项目第一批就是 500 台开发板。按老办法每台设备需要人工登录、改默认密码、生成 SSH 密钥对、把密钥登记到资产表里运气好一台十分钟运气差配置出错还得重来一遍。500 台就是整整一周的机械劳动而且全是最容易出错的重复操作。后来我把 Atsign 开源的 Flutter 组件 at_onboarding_cli 移植到了鸿蒙 HarmonyOS 环境整个认证部署流程从逐台手工操作变成了开箱即自动。设备第一次联网后自己完成身份创建、密钥生成、认证注册直接把设备领养进管理系统。单台设备从拆箱到进入可远程运维状态压缩到 90 秒以内而且可以并行批量执行。这篇文章就把整个适配过程、原理拆解和踩坑记录写出来。不管你是做鸿蒙应用开发的 Flutter 工程师还是被 IoT 设备批量部署折磨的运维或者单纯对 atPlatform 这套开源认证骨架感兴趣应该都能从中拿到一些可以直接落地的思路。1. 为什么设备认证会成为规模化部署的瓶颈1.1 传统设备认证流程的痛点先算一笔账。假设你有 N 台设备要上线传统做法是人工将设备连接到网络获取 IP 地址SSH 登录设备修改默认密码在设备上生成 SSH 密钥对将公钥拷贝到管理服务器配置 authorized_keys将设备序列号、密钥指纹、IP 等信息录入资产管理系统反复验证远程登录是否正常每一台设备都依赖人的操作而且任何一步打字错误都可能让后面的连接全部失败。设备数量过了 100这个流程就变得极其痛苦过了 1000基本不可维护。更麻烦的是 IoT 设备的多样性。摄像头、传感器网关、边缘计算盒子它们可能分布在不同的网络环境里有的在 NAT 后面有的没有公网 IP传统的中心服务器主动 SSH 到设备模式根本不成立。1.2 认证骨架的核心思路让设备自己完成身份建立at_onboarding_cli 解决的思路很直接不把认证逻辑堆在部署人员的命令行里而是把它做成设备上的一段自动化流程。设备首次启动后运行一个 onboarding 程序这个程序会自动完成生成一把设备专属的密钥对在 atDirectory 上注册设备身份atSign建立设备与管理系统之间的信任关系配置好 no-port SSH 通道让运维人员可以从任意位置安全访问设备整个过程中人的参与被压缩到给设备通电 确保设备联网这两步。认证骨架一旦建立后续所有设备都按同一套流程走速度和一致性都大幅提升。我在设计这个部署链路时想到一个类比传统认证像是每台设备去银行柜台开户排号、填表、柜员核对、盖章而 at_onboarding_cli 做的事情相当于为每台设备发了一张可自助激活的 SIM 卡插入手机开机就能用后端自动完成实名和开通。自动化认证骨架的价值就在这个自助激活环节。2. 拆开 at_onboarding_cli 的认证骨架它到底做了哪几件事2.1 atPlatform 身份体系基础要理解 at_onboarding_cli必须先搞懂 atPlatform 的基本概念。atPlatform 是一套开源的去中心化身份认证体系核心思想是每个人、每台设备都能拥有一个 atSign。atSign 类似于一个全球唯一的身份标识比如device_001。在这个体系里每个 atSign 对应一个加密密钥对私钥由持有者保管公钥发布到 atDirectory可以理解为身份索引服务。当两台设备之间需要建立安全通信时它们通过 atDirectory 查到对方的公钥然后进行端到端加密。不需要任何中心服务器保存每个人的私钥也没有统一密码库这种单点风险。at_onboarding_cli 是围绕这套身份体系做的一个 Flutter 命令行工具运行在设备端负责完成设备从无身份到已注册可访问的整个流程。官方支持 Linux、Android、macOS 等平台我这次要做的就是把它跑在鸿蒙 HarmonyOS 设备上。2.2 Onboarding 流程的四个关键阶段从我读源码和实际跑通的流程来看at_onboarding_cli 的工作可以分成四个阶段阶段一密钥生成与身份创建程序启动后会在设备本地生成 RSA 密钥对。如果这是设备第一次运行它会调用 atDirectory 的 API 申请一个新的 atSign 身份。这个动作类似给新设备办一张身份证。阶段二加密密钥上传与备份私钥生成后本地加密存储一份同时通过安全通道传一份到 atSecondary可以理解为一个个人数据保管服务用于多设备之间的密钥同步。这一步是可选的但对于设备可能丢失或重置的场景强烈建议开启。阶段三SSH 服务集成设备上原有的 SSH 服务会被重新配置写入新生成的公钥禁用密码登录锁定仅允许指定用户通过密钥访问。这一步把谁能登录这台设备的决定权从人工配置转移到了 atSign 认证体系。阶段四远程连接能力验证Onboarding 完成后程序会向 atDirectory 上报设备当前状态并向管理端发送一个通知。管理端只需知道这个设备的 atSign就能通过 no-port 方式发起加密连接不需要知道设备的 IP 地址也不需要在路由器上做端口映射。这四个阶段环环相扣本质上是以 atSign 为锚点把设备身份、密钥、远程访问策略、运维通道全部串起来。我后来把整个流程画成一张时序表方便团队成员理解阶段动作产出依赖1生成密钥对、申请 atSign设备身份 ID网络可达 atDirectory2加密备份私钥恢复能力atSecondary 服务3重写 SSH 配置无密码登录能力设备 root 权限4状态通知与验证管理端可见atDirectory 通知服务2.3 为什么这套设计天然适合海量部署我见过不少团队做设备认证系统最后都卡在两个问题上私钥怎么安全下发设备没有公网 IP 怎么远程连atPlatform 这套体系有意思的地方在于它反着来——设备不监听任何入站端口而是主动向 atDirectory 发起连接并保持在线状态。当管理端需要访问某台设备时并不是直接找设备而是通过 atSign 联系设备。设备收到通知后主动建立一条加密通道连接管理端。这意味着设备可以躲在任何复杂的 NAT 后面不依赖公网 IP不需要路由器配置也不需要在防火墙开放额外端口。而且每台设备只认自己的 atSign 和私钥没有共享密钥一台设备被物理攻破也不会波及其他设备。对大规模部署来说这套模型非常省心设备出厂时的网络配置可以完全一样认证信息由设备自己生成不需要在工厂里预灌密钥也不需要维护一长串 IP 跟设备 ID 的对应表。3. 鸿蒙适配的第一关Flutter 工具链和编译环境差异3.1 鸿蒙上的 Flutter 现状在鸿蒙 HarmonyOS 上跑 Flutter很多人第一反应是官方到底支持吗。当前状态是OpenHarmony 社区维护了一个 Flutter 引擎分支可以比较顺畅地适配鸿蒙设备但和标准的 Flutter SDK 有一些差异。我这次适配 at_onboarding_cli 时环境配置如下OpenHarmony SDK 4.x 及以上版本Flutter OpenHarmony 分支ohos 支持使用 hdc 作为设备调试工具类似 adb构建产物是 .hap 包由 hvigor 工程管理有一个细节容易被忽略官方标准 Flutter SDK 在检查到鸿蒙设备时偶尔会出现一句the current configured flutter sdk is not known to be fully supported之类的警告。此时不要慌重点确认当前使用的 Flutter SDK 是否为 ohos 分支而不是去盲目升级主版本。3.2 环境准备要点花点时间列一下我踩过之后整理的环境准备步骤第一步下载并切换 Flutter ohos 分支。不要直接用 flutter.dev 的稳定版需要拉取社区维护的 efforts然后把它设为 PATH 中的 flutter 命令。验证方式是在任意目录执行flutter doctor看看是否能检测到 OpenHarmony 工具链。第二步安装 hdc 工具。hdc 是鸿蒙生态的命令行调试工具用于连接设备、安装 hap 包、抓日志。需要确保设备开启开发者模式并授权调试。第三步确认项目结构。鸿蒙工程通常以 hap 为最终交付格式工程内通过 hvigor 构建。如果直接拿来一个现有的 Flutter 工程需要检查是否包含可用的鸿蒙包装工程。第四步处理原生依赖。at_onboarding_cli 依赖了一些 flutter pub 包这些包不一定都支持鸿蒙。需要逐个排查找到替代实现。有些纯 Dart 包可以直接运行涉及原生能力网络状态、平台通道等的则需要找鸿蒙兼容版本。3.3 构建配置的关键差异上面这些做完以后还有一个避不开的问题鸿蒙工程的权限声明。Android 平台在 AndroidManifest.xml 里声明权限鸿蒙则是在 module.json5 里声明。onboarding 过程至少需要网络访问权限如果设备还需要读取序列号、获取网络 SSID 等信息则要相应增加权限项。我实际配置的权限大概是这样{ module: { requestPermissions: [ { name: ohos.permission.INTERNET }, { name: ohos.permission.GET_NETWORK_INFO }, { name: ohos.permission.DISTRIBUTED_DATASYNC, reason: 用于设备认证信息同步, usedScene: { abilities: [ MainAbility ], when: inuse } } ] } }这里最容易被忽略的是DISTRIBUTED_DATASYNC。at_onboarding_cli 在生成密钥后需要与 atSecondary 同步数据如果权限没开程序会表现为卡在注册阶段日志里毫无提示只看到网络无响应。我第一阶段排查时花了不少时间才定位到这个权限问题。4. 将 at_onboarding_cli 跑成鸿蒙原生服务实际操作记录4.1 代码获取和工程结构调整at_onboarding_cli 本身是一个 Dart/Flutter 命令行项目核心逻辑集中在lib/目录下。我拿到代码后做的主要工作不是修改认证逻辑而是加一个鸿蒙外壳让 Flutter engine 能在 hap 包里启动并把 CLI 的执行方式改成服务模式或者带引导页的应用模式。具体步骤复制原项目核心包到我的鸿蒙 Flutter 工程中创建一个ohos/目录按住鸿蒙工程模板生成 hap 骨架将 Flutter module 嵌入到鸿蒙主工程使用 hvigor 统一构建调整入口在鸿蒙主 Ability 启动时加载 Flutter engine 并运行 onboarding 逻辑编译生成 .hap 包通过 hdc 安装到开发板4.2 依赖包的鸿蒙兼容性排查这一步是整场适配中最耗时但最有价值的环节。我梳理了 at_onboarding_cli 的主要依赖依赖作用鸿蒙兼容方案at_clientatPlatform 客户端核心纯 Dart直接可用at_utils工具函数集纯 Dart直接可用network_info_plus获取 WiFi/网络信息改用鸿蒙原生接口通过 MethodChannel 桥接ssh 相关包生成和管理 SSH 密钥替换为鸿蒙系统的本地密钥生成命令path_provider获取存储路径使用鸿蒙特有路径接口替代network_info_plus是我遇到的第一个阻碍。原包依赖 Android 的 WifiManager 来获取 SSID 和 IP 地址鸿蒙上没法直接用。我最后是通过鸿蒙的ohos.net.wifi接口写了单独的桥接方法从 Dart 侧通过 MethodChannel 调用。为了不阻塞整体进度我在第一批适配里先固定了 SSID 为空等桥接代码稳定后再补上网络信息采集。SSH 密钥生成的部分我也做了调整。at_onboarding_cli 原逻辑依赖 dart 层面的 ssh 相关包但这些包在鸿蒙上的兼容性不够理想。我改成了在设备端调用系统自带的ssh-keygen命令先生成密钥文件再把文件路径回传给 Dart 层。考虑到这个 CLI 本身就是为自动化场景设计的调用系统命令反而更可靠。4.3 服务化运行形态的设计批量部署场景里我们不能要求每台鸿蒙设备都插一个显示器然后手动启动 onboarding。所以我把程序拆成了两种形态形态一引导式应用。设备第一次启动时进入一个简单的 Flutter 界面显示当前状态和二维码。手机扫码后可以把设备绑定到账号。这种形态适合少量设备和需要可视化反馈的场景。形态二后台静默服务。设备启动后自动运行一个鸿蒙 Service无界面执行 onboarding 全流程执行结果通过 MQTT 或 HTTP 回调上报到管理平台。这是海量部署的主推形态全程不需要人工干预。我最终建议团队以形态二为主形态一作为调试和生产抽检的辅助手段。因为批量部署的核心诉求是零人工介入界面流程再顺也赶不上后台静默的效率。5. 构建海量设备的极简部署链路从单台跑到批量上线5.1 面向产线的部署流程设计工具本身跑通只是第一步真正要交付给产线的是一个极简部署链路。我最后整理出来的流程如下产线将鸿蒙开发板烧录统一的基础系统镜像在镜像中预装本次编译好的 onboarding hap 包设备通电联网后onboarding 服务自动启动服务向 atDirectory 申请 atSign生成密钥配置 SSH服务把设备 SN、atSign、MAC 地址、onboarding 结果组装成 JSONJSON 通过 HTTP 回调发送到公司资产管理平台资产平台自动登记设备标注已激活待分配运维人员根据资产平台列表按 atSign 远程访问任意设备整个过程产线工人只需要做一件事把开发板接上电源和网线。剩下的全部自动化。5.2 关键参数和实测数据以下是我在我们自己的测试环境里跑出来的实际数据供你参考设备型号某国产鸿蒙开发板系统版本OpenHarmony 4.1单台 onboarding 平均耗时约 87 秒包含冷启动、密钥生成、注册、SSH 配置、结果上报10 台并发部署时单台平均耗时约 94 秒未出现明显性能劣化失败率首轮 10 台测试中1 台因网络不稳失败重试后成功成功率 100%这里特别想说一下重试机制。海量部署时网络抖动、服务端瞬时过载都会导致个别设备注册失败。如果 onboarding 服务没有自动重试能力失败设备就得退回人工处理这又回到了起点。所以我把重试设计成了指数退避策略首次失败等 5 秒重试第二次 25 秒第三次 125 秒最多尝试 5 次。实测中绝大多数失败都在第二次重试时就能恢复。5.3 与管理平台的对接方式onboarding 完成后设备需要和已有业务系统打通。我主要做了两个对接方向一个是HTTP 回调。设备在完成后向管理平台提交一个 token在镜像制作时预埋平台校验 token 后接收设备信息。这个方式简单可靠适合大多数团队。另一个是MQTT 消息。如果设备后续就要使用 MQTT 上报业务数据可以在 onboarding 完成后直接往预设的 MQTT topic 发一条设备上线消息让业务系统有感知。不喜欢引入额外消息队列的团队用 HTTP 回调就够了不要过度设计。6. 适配过程中排过的最刁钻的坑6.1 能连 app 却访问不了网络的坑第一个大坑程序在鸿蒙上能正常启动UI 也出来了但注册请求发不出去也不报超时错误日志里没有任何网络相关的抛错。我一开始怀疑是 Flutter engine 的 DNS 解析有问题折腾了半天最后发现是鸿蒙权限没给。在 Android 上即使你不声明INTERNET权限debug 包默认也能联网但鸿蒙对权限控制敏感没授权就是静默失败。排查方法其实比较笨先用鸿蒙的 curl 命令直接在设备上测试网络请求确认系统层面网络是通的再在 Flutter 层加日志看 onBoarding 流程卡在哪一步最后怀疑到权限去module.json5里补上ohos.permission.INTERNET立刻就好了。这个坑提醒我跨平台适配中优先检查目标平台的权限声明不要总在代码逻辑里找问题。6.2 证书校验失败的坑第二个坑是 HTTPS 证书校验失败。atDirectory 的服务使用标准 CA 证书我以为在鸿蒙上会跟 Android 一样自动信任系统根证书结果没有。由于鸿蒙的设备系统裁剪程度不同部分开发板镜像没有完整包含根证书。解决方案有两个一是让设备时间自动同步二是将常用 CA 根证书手动安装到系统信任区。我们的开发板主要是第一个原因——手动设置的测试时间偏离真实时间太久证书有效期校验收不上。把设备改成自动获取时间后问题消失。6.3 后台服务被杀掉的坑第三个坑出现在形态二后台静默服务的稳定性测试中。设备锁屏后跑一段时间onboarding 进程被系统回收。这跟 Android 的后台限制机制类似鸿蒙对长任务也有管控。我的解决思路是在鸿蒙的 Ability 配置中声明这是一个需要持续运行的任务并申请对应的长任务权限同时在应用层做心跳检测——每 30 秒发一次网络心跳如果发现程序已被杀掉则通过鸿蒙的 suspend 回调在系统允许的窗口内重新拉起。处理之后我在开发板上连续跑了 72 小时进程稳定。7. 后续我们可以怎么扩展这套认证骨架at_onboarding_cli 适配完成之后我又思考了几个扩展方向这些其实也是这套骨架的天然延伸方向一密钥轮换与吊销。设备被淘汰或疑似泄露时通过 atDirectory 将对应 atSign 标记为吊销设备下一次尝试连接时会被拒绝。这个能力对资产回收场景特别有价值。方向二设备分组与权限策略。为不同业务线分配不同前缀的 atSign比如warehouse_cam_001运维端就能通过 atSign 含义直接判断设备所属分组为不同的组配置不同的访问策略。方向三和管理系统联动。onboarding 完成后自动触发资产入库、告警规则配置、监控模板导入让设备从拿到手到被管理完全无人工环节。这几个方向目前都还处于规划阶段但基础认证骨架已经铺好后面的扩展更多是策略和业务层的组装。对于手头有大量鸿蒙设备要上线的团队我建议先跑通这一条极简链路再逐步叠加组织层面的需求。最后想说的是这种跨界适配的工作收获往往不在跑通本身而在于被迫去理解两个生态的差异Flutter 的跨端抽象和鸿蒙的系统边界。期间产生的所有犹豫、怀疑和踩坑最后都会变成你判断下一个技术方案时的直觉。希望这篇记录能让你少走几步弯路。
