HarmonyOS技术精讲-Connectivity Kit(短距通信服务):初识统一短距通信框架

开篇
HarmonyOS NEXT 开发中,短距通信能力一直是个需要重点关注的地方。Wi-Fi 扫描、蓝牙配对、NFC 标签读取、星闪连接,每个能力分散在不同的模块里,接口风格也各不相同。很多人在集成多个通信能力时,会发现代码里堆满了各模块的 import,状态同步逻辑重复,设备发现和连接管理很难统一维护。
Connectivity Kit 的出现就是为了解决这个问题。它把这些短距通信能力聚合到一个统一框架下,通过分布式软总线提供设备发现、连接管理和数据传输的标准化接口。这篇文章不准备大段翻译文档,而是直接说明白这个 Kit 是什么、能做什么、怎么用,以及实际开发中容易踩的坑。
Connectivity Kit 解决的核心问题
在没有 Connectivity Kit 之前,调用短距通信能力的典型做法是:分别 import @kit.ConnectivityKit.d.ts 下的 Wi-Fi、蓝牙、NFC、星闪各模块,自己管理设备搜索、配对、连接、数据收发。问题是:
- 接口风格不统一:Wi-Fi 用 startScan、蓝牙用 startBLEScan,回调参数结构不同
- 设备管理分散:每个模块有各自的发现回调、状态监听
- 跨设备协同困难:需要自己实现设备台账,做不到统一的连接管理
Connectivity Kit 的核心思路是:通过分布式软总线层抽象设备通信能力。应用层不需要关心底层是 Wi-Fi 还是蓝牙,只需要向框架注册"发现设备"、"建立连接"、"发送数据"等请求,框架自动选择最优链路。
| 对比项 | 传统方式 | Connectivity Kit |
|---|---|---|
| 设备发现 | 各模块独立实现 | DeviceDiscoveryManager 统一管理 |
| 连接管理 | 手动维护连接状态 | ConnectionManager 统一生命周期 |
| 数据通道 | 按协议各自实现 | 自动选择最优链路 |
| 跨设备协同 | 需自建协议 | 分布式软总线原生支持 |
简单说,如果你的需求只涉及单一通信协议(比如只做蓝牙体脂秤数据读取),直接用对应模块 API 更直接。但如果需要多设备协同、多协议切换、统一设备管理,Connectivity Kit 的框架更合适。
环境说明
text
DevEco Studio 版本:DevEco Studio 6.1.0 及以上
HarmonyOS SDK 版本:HarmonyOS 6.1.0(23) 及以上
目标设备:手机 / 平板(支持 Wi-Fi、蓝牙、NFC 功能
核心实现:快速上手 Connectivity Kit
这一节的目标不是写完整的通信逻辑,而是演示如何初始化框架并查询设备能力。让读者先对框架有个实际操作感觉。
1. 引入模块
connectivityKit 的入口模块统一从 @kit.ConnectivityKit 引入。官方推荐使用 * 导入方式,但实际开发中发现这种方式会影响 IDE 的类型推断,建议显式导入需要的子模块。
typescript
// 推荐方式:显式导入需要的子模块
import { deviceManager } from '@kit.ConnectivityKit';
import { wifiManager } from '@kit.ConnectivityKit';
import { bluetoothManager } from '@kit.ConnectivityKit';
如果只用到部分能力,只导入对应模块即可。全部用 * 导入会增加包体积。
2. 查询设备短距通信能力
很多场景下需要先判断设备是否支持某种通信能力,或者判断当前信道的质量。connectivityKit 提供了 deviceManager 模块来查询设备能力。
下面这段代码演示如何查询当前设备支持的短距通信类型,以及当前 Wi-Fi 信号强度。
typescript
import { deviceManager } from '@kit.ConnectivityKit';
import { wifiManager } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct ConnectivityDemo {
@State deviceInfo: string = '查询中...';
@State signalLevel: number = 0;
aboutToAppear() {
this.queryConnectivity();
}
queryConnectivity() {
// 获取设备信息实例
let deviceInfo = deviceManager.getDeviceInfo();
if (deviceInfo) {
this.deviceInfo = JSON.stringify({
deviceName: deviceInfo.deviceName,
deviceType: deviceInfo.deviceType,
networkId: deviceInfo.networkId
});
} else {
this.deviceInfo = '无法获取设备信息';
}
// 查询 Wi-Fi 信号强度
wifiManager.getLinkedInfo().then((wifiInfo) => {
this.signalLevel = wifiInfo.rssi;
}).catch((err: BusinessError) => {
console.error(`Wi-Fi 信息获取失败: ${err.message}`);
});
}
build() {
Column() {
Text('设备信息').fontSize(20).fontWeight(FontWeight.Bold);
Text(this.deviceInfo).fontSize(14).margin({ top: 8 });
Divider().margin({ top: 16, bottom: 16 });
Text('Wi-Fi 信号强度').fontSize(20).fontWeight(FontWeight.Bold);
Text(this.signalLevel === 0 ? '未连接或查询失败' : `${this.signalLevel} dBm`)
.fontSize(14)
.margin({ top: 8 });
}
.padding(16)
.width('100%')
.height('100%')
}
}
关键说明:
deviceManager.getDeviceInfo()返回的是当前设备的基本信息,不包含网络状态。这个接口在 API 12 之后才稳定,低版本设备可能返回 nullwifiManager.getLinkedInfo()需要在已连接 Wi-Fi 的情况下才能获取到 RSSI 值。如果设备没连 Wi-Fi,promise 会 reject- 实际项目中建议把
getLinkedInfo()的调用放在aboutToAppear中,但要注意页面还没完全显示时网络数据可能还没准备好,最好加个重试机制
常见问题
问题 1:真机正常,模拟器无法获取设备信息
现象: 模拟器上 deviceManager.getDeviceInfo() 一直返回 null,真机正常。
原因: 模拟器对分布式软总线的支持有限,deviceManager 模块需要真实硬件环境下的设备能力信息。模拟器中的设备信息为空是正常现象,不是 Bug。
解决方案: 开发阶段在 queryConnectivity 中加入模拟器判断逻辑:
typescript
import { deviceManager } from '@kit.ConnectivityKit';
import { Environment } from '@kit.AbilityKit';
isEmulator(): boolean {
return Environment.getRunningEnvironment() === Environment.EnvironmentType.Emulator;
}
模拟器环境下返回固定值,避免 UI 显示异常。
问题 2:getLinkedInfo() 请求超时或失败
现象: 在页面刚加载时调用 getLinkedInfo() 有概率失败,日志提示 timeout。
原因: getLinkedInfo() 依赖系统 Wi-Fi 连接服务。如果页面 aboutToAppear 时系统 Wi-Fi 服务还没完全就绪,接口会超时。这个问题在系统刚开机或恢复网络连接后比较明显。
解决方案: 添加重试机制,同时设置合理的重试间隔。
typescript
private retryGetWifiInfo(maxRetries: number = 3): void {
let retryCount = 0;
const tryGetInfo = () => {
wifiManager.getLinkedInfo().then((wifiInfo) => {
this.signalLevel = wifiInfo.rssi;
}).catch((err: BusinessError) => {
retryCount++;
if (retryCount <= maxRetries) {
setTimeout(() => tryGetInfo(), 500); // 间隔 500ms 重试
} else {
console.error(`重试 ${maxRetries} 次后仍失败: ${err.message}`);
}
});
};
tryGetInfo();
}
最佳实践
1. 不要在主线程中做长时间查询
getLinkedInfo() 虽然是异步接口,但它的底层需要和系统的 Wi-Fi 服务交互。如果频繁调用,会影响 UI 线程的响应速度。建议在需要时才查询,或者用定时器间隔查询,不要在每次页面刷新时都调用。
2. 设备信息查询结果可以缓存
deviceManager.getDeviceInfo() 返回的内容在设备运行期间基本不变。多次调用没有意义,可以在 AppStorage 或 PersistentStorage 中缓存一次,后续页面直接读取缓存。
3. 合理处理空值
因为模拟器或不支持分布式软总线的设备上会返回 null,所以在使用查询结果之前一定要做 null 判断。常见错误是直接 deviceInfo.deviceName 导致崩溃,必须加上可选链操作符或条件判断。
FAQ
Q:connectivityKit 和直接使用 @ohos.wifi 模块有什么区别?
A:connectivityKit 是对下层的封装,提供统一的设备发现、连接管理接口。如果只需要调用 Wi-Fi 自身的 API(比如扫描周围热点),直接用 @ohos.wifi 更直接。connectivityKit 的优势在于多协议统一管理和分布式软总线能力。
Q:为什么真机上 getLinkedInfo() 返回的 rssi 数值是负值?
A:RSSI(接收信号强度指示)在 IEEE 802.11 标准中的定义就是负值,单位是 dBm。数值越大(越接近 0)表示信号越强。通常情况下:
- -50 dBm ~ 0 dBm:信号极好
- -70 dBm ~ -50 dBm:信号中等
- 低于 -70 dBm:信号较弱
Q:Connectivity Kit 支持跨设备连接吗?需要什么特殊条件?
A:支持通过分布式软总线连接。条件:两个设备登录同一华为账号,开启蓝牙和 Wi-Fi,并且在近距离内。Framework 会自动选择最优通道(通常优先 Wi-Fi P2P,其次蓝牙 EDR)。
如果你在开发中也遇到过类似问题,建议重点检查设备能力查询和 Wi-Fi 信息获取的生命周期处理。不同设备型号、系统版本间的行为差异可能存在,建议在真机上多做测试。下一篇会深入讲解基于 Connectivity Kit 的设备发现与连接管理完整实现。