HarmonyOS —— NetworkKit 网络连接管理实战笔记
HarmonyOS —— NetworkKit 网络连接管理实战笔记
这一节可以理解成:
“我有好几张网(Wi-Fi / 蜂窝 / 有线),系统怎么选?应用怎么跟着切?”
你这段文档主要讲的是:用 @kit.NetworkKit 里的 connection 模块,管理和感知网络连接。
包括:
- 监听网络状态变化(默认网 & 指定网)
- 多网络共存时怎么“监控 + 跟着重连”
- 获取所有网络、默认网络、指定网络的信息
- 判断“当前默认网络能不能上网”
- 用默认网络做 DNS 解析
下面我按“开发视角”帮你梳一遍。
一、先把几个“名词”捋清楚
文档里这几个概念很关键,考试/面试也爱问:
- 网络生产者:提供数据网络的那一侧
- 例:Wi-Fi、蜂窝、Ethernet
- 网络消费者:用网络的人(或服务)
- 例:应用、系统服务
- 网络探测:看这条网到底能不能用,避免切到一条“摆烂网”
- 绑定网络探测 / DNS 探测 / HTTP / HTTPS 探测
- 网络优选:多条网络同时存在时,选哪条为“默认网”
- 默认网络:带默认路由的网络(所有不绑网的请求通常都从这里走)
API 调用习惯:
- 大部分都是 异步,同时提供:
Promise风格callback风格(文档示例用 Promise,我们也是)
二、监听“指定网络”的状态变化
1. 权限
先在 module.json5 里声明权限:
"requestPermissions": [
{
"name": "ohos.permission.GET_NETWORK_INFO"
}
]
权限级别是
normal,只要符合基本原则就行。
2. 创建一个“我要的网络”说明:NetSpecifier
比如:默认网络是 Wi-Fi,但我想单独弄一条蜂窝网络来用:
import { connection } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';
let netSpecifier: connection.NetSpecifier = {
netCapabilities: {
// 我要“蜂窝网”
bearerTypes: [connection.NetBearType.BEARER_CELLULAR],
// 且要有上网能力(Internet)
networkCap: [connection.NetCap.NET_CAPABILITY_INTERNET]
},
};
// 超时时间 10s(单位 ms)
let timeout = 10 * 1000;
// 创建 NetConnection 对象
let conn = connection.createNetConnection(netSpecifier, timeout);
3. 订阅网络状态事件
// 网络可用时回调
conn.on('netAvailable', (data: connection.NetHandle) => {
console.info('net is available, netId is ' + data.netId);
});
// 网络不可用时回调
conn.on('netUnavailable', (data: void) => {
console.info('net is unavailable, data is ' + JSON.stringify(data));
});
4. 正式“注册”监听 & 取消
// 开始监听指定网络的状态变化(要在 on() 之后调)
conn.register((err: BusinessError) => {
console.info(JSON.stringify(err));
});
// 不用了记得取消
conn.unregister((err: BusinessError) => {
console.info(JSON.stringify(err));
});
心智模型:
createNetConnection= 我要什么样的网
on + register= 开始订阅它的生死状态
unregister= 不看了
三、默认网络切换时,如何“顺滑重连”?
场景:
- Wi-Fi 很弱 → 系统把默认网切到蜂窝
- 关了 Wi-Fi / 关了蜂窝 → 默认网切换
- Wi-Fi 之间 / 蜂窝之间跨网切换
对你来说,重点是:
“默认网变了,原来的 Socket 可能废了,要重建连接。”
1. 监听默认网络变化
import { connection } from '@kit.NetworkKit';
const netConnection = connection.createNetConnection();
// 这里不传 NetSpecifier,就是“盯默认网络”
netConnection.on('netAvailable', (data: connection.NetHandle) => {
console.info('default network changed: ' + JSON.stringify(data));
});
2. 如果你用 socket 建连接,怎么做?
import { connection, socket } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';
// 全局持有一个 socket
let sock: socket.TCPSocket = socket.constructTCPSocketInstance();
function useSocket() {
const address: socket.NetAddress = {
address: '192.168.xx.xxx',
port: 8080,
};
const tcpConnectOptions: socket.TCPConnectOptions = {
address,
timeout: 6000,
};
sock.connect(tcpConnectOptions, (err: BusinessError) => {
if (err) {
console.error('connect fail: ' + JSON.stringify(err));
return;
}
console.info('connect success');
const sendOptions: socket.TCPSendOptions = {
data: 'Hello, server!',
};
socketSend(sendOptions);
});
}
function socketSend(sendOptions: socket.TCPSendOptions) {
sock
.send(sendOptions)
.then(() => console.info('send success'))
.catch((err: BusinessError) => console.error('send fail: ' + JSON.stringify(err)));
}
把“重连逻辑”挂在默认网络变化上:
function socketTest() {
const netConnection = connection.createNetConnection();
netConnection.on('netAvailable', (netHandle: connection.NetHandle) => {
console.info('default network changed: ' + JSON.stringify(netHandle));
// 原连接作废,先关掉
sock.close();
// 新建一个 socket 实例
sock = socket.constructTCPSocketInstance();
// 再次建立连接并发送数据
useSocket();
});
// 注册监听
netConnection.register((error: BusinessError) => {
if (error) {
console.error('register fail: ' + JSON.stringify(error));
} else {
console.info('register success');
}
});
}
一句话:“默认网一变,socket 全部重建一遍。”
如果你用的是 Socket Library(另一套封装),思路也是一样:监听 → 关闭旧连接 → 重连。
四、获取“所有注册网络”
目标:看看当前设备有哪些网络“处于连接状态”。
import { connection } from '@kit.NetworkKit';
// 需要 ohos.permission.GET_NETWORK_INFO
connection.getAllNets().then((data: connection.NetHandle[]) => {
console.info('Succeeded to get data: ' + JSON.stringify(data));
if (data) {
// 比如丢到全局上下文里存起来
GlobalContext.getContext().netList = data;
}
});
这里拿到的是一组 NetHandle,后面可以配合 getNetCapabilities / getConnectionProperties 查看每条网络的详细信息。
五、查询默认网络 / 所有网络的详细信息
1. 查默认网络信息
import { connection } from '@kit.NetworkKit';
function getDefaultNetsInfo() {
let netHandleInfo: connection.NetHandle | null = null;
connection.getDefaultNet().then((data: connection.NetHandle) => {
if (data.netId === 0) {
console.info("don't have defaultNet");
return;
}
if (data) {
console.info('getDefaultNet get data: ' + JSON.stringify(data));
netHandleInfo = data;
// 能力信息:类型 + 能力
connection.getNetCapabilities(netHandleInfo).then((caps: connection.NetCapabilities) => {
console.info('getNetCapabilities get data: ' + JSON.stringify(caps));
// 网络类型:bearerTypes
const bearerSet = new Set(caps.bearerTypes);
for (const item of Array.from(bearerSet.values())) {
if (item === connection.NetBearType.BEARER_CELLULAR) {
console.info('BEARER_CELLULAR');
} else if (item === connection.NetBearType.BEARER_WIFI) {
console.info('BEARER_WIFI');
} else if (item === connection.NetBearType.BEARER_ETHERNET) {
console.info('BEARER_ETHERNET');
}
}
// 网络能力:networkCap
const capSet = new Set(caps.networkCap);
for (const item of Array.from(capSet.values())) {
if (item === connection.NetCap.NET_CAPABILITY_MMS) {
console.info('NET_CAPABILITY_MMS');
} else if (item === connection.NetCap.NET_CAPABILITY_NOT_METERED) {
console.info('NET_CAPABILITY_NOT_METERED');
} else if (item === connection.NetCap.NET_CAPABILITY_INTERNET) {
console.info('NET_CAPABILITY_INTERNET');
} else if (item === connection.NetCap.NET_CAPABILITY_NOT_VPN) {
console.info('NET_CAPABILITY_NOT_VPN');
} else if (item === connection.NetCap.NET_CAPABILITY_VALIDATED) {
console.info('NET_CAPABILITY_VALIDATED');
}
}
});
}
});
// 连接属性(IP、路由等)
connection.getConnectionProperties(netHandleInfo).then((props: connection.ConnectionProperties) => {
console.info('getConnectionProperties get data: ' + JSON.stringify(props));
});
}
2. 查所有网络的详细信息
import { connection } from '@kit.NetworkKit';
function getAllNetsInfo() {
connection.getAllNets().then((handles: connection.NetHandle[]) => {
console.info('getAllNets get data: ' + JSON.stringify(handles));
if (!handles) return;
const handleSet = new Set(handles);
for (const h of Array.from(handleSet.values())) {
// 每条网络的能力
connection.getNetCapabilities(h).then((caps) => {
console.info('getNetCapabilities get data: ' + JSON.stringify(caps));
});
// 每条网络的连接属性
connection.getConnectionProperties(h).then((props) => {
console.info('getConnectionProperties get data: ' + JSON.stringify(props));
});
}
});
}
六、判断“当前默认网络能不能上网”
核心能力:看 networkCap 是否包含 NET_CAPABILITY_VALIDATED。
还有一个
NET_CAPABILITY_CHECKING_CONNECTIVITY表示“正在校验中”。
import { connection } from '@kit.NetworkKit';
// 同步获取默认网
const netHandle = connection.getDefaultNetSync();
if (!netHandle || netHandle.netId === 0) {
console.error('getDefaultNetSync fail');
} else {
console.info('default network: ' + JSON.stringify(netHandle));
const netCapabilities = connection.getNetCapabilitiesSync(netHandle);
const cap = netCapabilities.networkCap;
console.info('network capabilities: ' + JSON.stringify(netCapabilities));
if (cap?.includes(connection.NetCap.NET_CAPABILITY_CHECKING_CONNECTIVITY)) {
// 正在做连通性判断
console.info('default network is checking, please try again later');
} else {
if (cap?.includes(connection.NetCap.NET_CAPABILITY_VALIDATED)) {
// 连通性验证通过:可访问互联网
console.info('default network is validated');
} else {
// 验证失败:这网连不上外网
console.info('default network is not validated');
}
}
}
这个逻辑在“网络质量判断 + 动态降级策略”里很好用,
例如:验证失败就只展示本地缓存 / 提示用户换网络。
七、用默认网络做 DNS 解析
最后一个小能力:用当前默认网解析域名 → 拿到 IP 列表。
import { connection } from '@kit.NetworkKit';
// "xxxx" 替换成真正要解析的域名
connection.getAddressesByName('xxxx').then((data: connection.NetAddress[]) => {
console.info('Succeeded to get data: ' + JSON.stringify(data));
});
这里同样受网络类型 & 默认网络影响,比如默认走的是 VPN,就会用 VPN 那边的 DNS。
八、你可以怎么用在实际项目里?
给你几个可以直接套用的思路:
- IM / 长连接类 App
- 监听默认网络变化 → 自动重建 TCP / WebSocket 连接
- 判断
NET_CAPABILITY_VALIDATED→ 决定是否展示“当前网络不可用”提示
- 多媒体 / 下载器
- 枚举所有网络 → 做自己的“网络优选策略”(例如更倾向 Wi-Fi + notMetered)
- 用
getAddressesByName做 显式 DNS 解析 + 打点
- 诊断工具 / 开发者选项
- 展示当前所有网络的:
- 类型(Wi-Fi / 蜂窝 / 以太网)
- 能力(INTERNET / VALIDATED / NOT_METERED 等)
- 做一个“网络体检”页面
- 展示当前所有网络的:

浙公网安备 33010602011771号