【鸿蒙心迹】那些年,我为鸿蒙开发“熬的夜”:基于 SoftBus 的智能门锁配网全流程实战
一、前言
还记得第一次在真机上调通 HarmonyOS 分布式能力是在一个深夜,那时我的目标是让一款智能门锁在局域网内自动接入 Wi-Fi。为了实现“手机一键配网、门锁端自动上线”这一场景,我与 SoftBus、Ability、分布式数据管理等底层模块“纠缠”了整整三个深夜。本文将结合真实案例,剖析从架构设计到调试排障的全过程,并附上架构图、流程图和关键代码片段,分享那段与鸿蒙一起熬夜的温暖时刻。
二、项目背景与需求
-
场景
– 手机端扫描门锁蓝牙广播 → 建立 SoftBus 通道 → 下发 Wi-Fi 配置信息 → 门锁端连接 Wi-Fi → 回传结果。 -
关键点
– 分布式能力(SoftBus)稳定性
– 配网协议兼容性(JSON vs. Protobuf)
– 异常重连与超时处理
– 日志定位与多进程调试
三、整体架构图
+---------------+ SoftBus Channel +---------------+
| 智能家居 App | <--------------------------> | 智能门锁设备 |
| (UIAbility) | |(ServiceAbility)|
+-------+-------+ +-------+-------+
| |
| 1. 扫描广播 | 2. 建通道
v v
+-------+-------+ +-------+-------+
| Bluetooth | | Bluetooth |
| Kernel Driver | | Kernel Driver |
+---------------+ +---------------+
架构说明:
– UIAbility 负责用户交互、扫描广播;
– ServiceAbility 承载分布式通道创建、消息收发;
– 通过 SoftBus 打通手机与设备进程间通信;
四、关键流程图
[Start 配网]
↓
[Scan BLE 广播]
↓
[Connect SoftBus] ──失败▸重试3次▸超时告警
↓
[sendConfig(info)] ──包长校验──> error by JSON.parse? ──修改为 Protobuf
↓
[wait Ack (10s)]
└─ 》 成功 ──[关闭通道]──> [配网成功 ✔]
└─ 》 失败 ──[重试逻辑]──> [上报日志 & 用户提示 ❌]
五、熬夜排障:那些小细节
-
SoftBus 通道频繁断开
日志显示:E/SoftBus: Peer close channel, reason=10
原因:默认 KeepAlive 时间过短(30s),在高并发下 SoftBus 会触发断开。
调优:在 ServiceAbility 中调用:SessionAttribute attr = new SessionAttribute(); attr.setOnAutoReconnect(true); attr.setKeepAliveTime(120_000); // 延长到 2 分钟 SessionOption opt = new SessionOption(); opt.setSessionAttr(attr); adapter.openSession(pkgName, peerDev, sessionName, opt, callback);
-
JSON 解析失败异常
配网协议最初用 JSON 传输,logcat 报:java.lang.NumberFormatException: For input string: "036234..."
原因:门锁端 Wi-Fi 密码以“0”开头,JSON 里被当作八进制解析。
解决:改用 Protobuf,示例.proto
:message WifiConfig { string ssid = 1; string password = 2; int32 timeout = 3; }
并在 Ability 中加载:
import { decode, encode } from 'protobufjs/minimal'; const buf = encode(WifiConfig, configObj).finish(); remote.call('sendBytes', buf);
-
远端 Ability 死锁
第一次测试时,门锁端在收到配网成功后并未回包,ServiceAbility 一直卡在onRemoteRequest
,logcat 无任何输出。
排查:对比系统源码发现,门锁端主线程在连接 Wi-Fi 后进入阻塞等待模式,导致 Ability 的 Binder 调用无响应。
优化:将“连接 Wi-Fi”操作放入子线程,并在子线程结束后通过context.publishEvent
通知主线程回包:new Thread(() -> { boolean ok = wifiManager.connect(config); context.publishEvent("CONFIG_ACK", ok); }).start();
六、核心代码片段
- 手机端扫描 & 建通道(ArkTS + JS)
```ts
// UIAbility 扫描 BLE
import bluetooth from '@ohos.bluetooth';
bluetooth.startLeScan({
onFoundDevice: (dev) => {
if (dev.name === 'SmartLock') {
this.target = dev;
bluetooth.stopLeScan();
this.createSession(dev);
}
}
});
// 建立 SoftBus 通道
import softbus from '@ohos.softbus';
await softbus.openSession({
peerDev: this.target.deviceId,
sessionName: 'configSession',
onOpen: () => console.info('Session opened'),
onData: (data) => this.handleAck(data),
});
2. 设备端 ServiceAbility(Java)
```java
@Override
public void onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
byte[] buf = data.readByteArray();
WifiConfig config = WifiConfig.parseFrom(buf); // Protobuf 反序列化
new Thread(() -> {
boolean result = connectWifi(config.getSsid(), config.getPassword());
this.sendAck(result);
}).start();
}
private void sendAck(boolean ok) {
Optional<Session> opt = SessionManager.getInstance().getSession(getSessionName());
opt.ifPresent(s -> s.sendMessage(new AbilityParcel(AB_ACK, new byte[]{ok?1:0})));
}
七、结语:每一次“夜战”都是成长
凌晨三点,当手机界面弹出“配网成功 ✔”的瞬间,所有熬夜的疲惫都化作成就感——我们的分布式通道终于稳定可靠了。正是这些细枝末节的小问题,让我们对 HarmonyOS 底层模块有了更深的理解,也让我与鸿蒙生态的连接更加紧密。希望这篇实战能帮助更多开发者少走弯路,也欢迎在评论中分享你熬夜时最有成就的一刻!让我们继续在技术的星空里并肩前行。
更多推荐
所有评论(0)