引言
App 没网时给个友好提示、网络切换时自动重连、直播时检测弱网降码率------这些能力都靠网络连接诊断。HarmonyOS 的 @ohos.net.connection 模块提供了完整的网络状态监测能力。
一、基础:检测当前网络状态
typescript
import connection from '@ohos.net.connection';
1.1 获取网络状态
typescript
async function getNetworkState() {
const netHandle = await connection.getDefaultNet();
const state = await connection.getNetCapabilities(netHandle);
console.log('网络类型:', state.bearerTypes); // 例如 [BearerType.CELLULAR]
console.log('网络能力:', state.networkCapabilities); // 例如 [NET_CAPABILITY_INTERNET]
}
1.2 获取网络类型
typescript
// 判断是否有网络
async function isNetworkAvailable(): Promise<boolean> {
try {
const netHandle = await connection.getDefaultNet();
const state = await connection.getNetCapabilities(netHandle);
return state.bearerTypes.length > 0;
} catch {
return false;
}
}
// 判断当前是 WiFi 还是蜂窝
async function getConnectionType(): Promise<'wifi' | 'cellular' | 'none'> {
try {
const netHandle = await connection.getDefaultNet();
const state = await connection.getNetCapabilities(netHandle);
if (state.bearerTypes.includes(connection.BearerType.WIFI)) return 'wifi';
if (state.bearerTypes.includes(connection.BearerType.CELLULAR)) return 'cellular';
return 'none';
} catch {
return 'none';
}
}
二、网络状态实时监听
#mermaid-svg-wMWRlg1OCLXTmPUC{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-wMWRlg1OCLXTmPUC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-wMWRlg1OCLXTmPUC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-wMWRlg1OCLXTmPUC .error-icon{fill:#552222;}#mermaid-svg-wMWRlg1OCLXTmPUC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-wMWRlg1OCLXTmPUC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-wMWRlg1OCLXTmPUC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-wMWRlg1OCLXTmPUC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-wMWRlg1OCLXTmPUC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-wMWRlg1OCLXTmPUC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-wMWRlg1OCLXTmPUC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-wMWRlg1OCLXTmPUC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-wMWRlg1OCLXTmPUC .marker.cross{stroke:#333333;}#mermaid-svg-wMWRlg1OCLXTmPUC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-wMWRlg1OCLXTmPUC p{margin:0;}#mermaid-svg-wMWRlg1OCLXTmPUC .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-wMWRlg1OCLXTmPUC .cluster-label text{fill:#333;}#mermaid-svg-wMWRlg1OCLXTmPUC .cluster-label span{color:#333;}#mermaid-svg-wMWRlg1OCLXTmPUC .cluster-label span p{background-color:transparent;}#mermaid-svg-wMWRlg1OCLXTmPUC .label text,#mermaid-svg-wMWRlg1OCLXTmPUC span{fill:#333;color:#333;}#mermaid-svg-wMWRlg1OCLXTmPUC .node rect,#mermaid-svg-wMWRlg1OCLXTmPUC .node circle,#mermaid-svg-wMWRlg1OCLXTmPUC .node ellipse,#mermaid-svg-wMWRlg1OCLXTmPUC .node polygon,#mermaid-svg-wMWRlg1OCLXTmPUC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-wMWRlg1OCLXTmPUC .rough-node .label text,#mermaid-svg-wMWRlg1OCLXTmPUC .node .label text,#mermaid-svg-wMWRlg1OCLXTmPUC .image-shape .label,#mermaid-svg-wMWRlg1OCLXTmPUC .icon-shape .label{text-anchor:middle;}#mermaid-svg-wMWRlg1OCLXTmPUC .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-wMWRlg1OCLXTmPUC .rough-node .label,#mermaid-svg-wMWRlg1OCLXTmPUC .node .label,#mermaid-svg-wMWRlg1OCLXTmPUC .image-shape .label,#mermaid-svg-wMWRlg1OCLXTmPUC .icon-shape .label{text-align:center;}#mermaid-svg-wMWRlg1OCLXTmPUC .node.clickable{cursor:pointer;}#mermaid-svg-wMWRlg1OCLXTmPUC .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-wMWRlg1OCLXTmPUC .arrowheadPath{fill:#333333;}#mermaid-svg-wMWRlg1OCLXTmPUC .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-wMWRlg1OCLXTmPUC .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-wMWRlg1OCLXTmPUC .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wMWRlg1OCLXTmPUC .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-wMWRlg1OCLXTmPUC .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wMWRlg1OCLXTmPUC .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-wMWRlg1OCLXTmPUC .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-wMWRlg1OCLXTmPUC .cluster text{fill:#333;}#mermaid-svg-wMWRlg1OCLXTmPUC .cluster span{color:#333;}#mermaid-svg-wMWRlg1OCLXTmPUC div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-wMWRlg1OCLXTmPUC .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-wMWRlg1OCLXTmPUC rect.text{fill:none;stroke-width:0;}#mermaid-svg-wMWRlg1OCLXTmPUC .icon-shape,#mermaid-svg-wMWRlg1OCLXTmPUC .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wMWRlg1OCLXTmPUC .icon-shape p,#mermaid-svg-wMWRlg1OCLXTmPUC .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-wMWRlg1OCLXTmPUC .icon-shape .label rect,#mermaid-svg-wMWRlg1OCLXTmPUC .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wMWRlg1OCLXTmPUC .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-wMWRlg1OCLXTmPUC .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-wMWRlg1OCLXTmPUC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} WiFi断开
网络恢复
质量变化
注册监听
on netCapabilitiesChange
网络变化
切换到蜂窝/显示提示
重试未完成的请求
调整应用行为
2.1 网络能力变化监听
typescript
aboutToAppear() {
connection.on('netCapabilitiesChange', async (netHandle) => {
const state = await connection.getNetCapabilities(netHandle);
const hasInternet = state.networkCapabilities.includes(
connection.NetCap.NET_CAPABILITY_INTERNET
);
if (hasInternet) {
this.networkStatus = '已连接';
this.retryFailedRequests(); // 重试失败的请求
} else {
this.networkStatus = '无网络';
this.showNetworkError();
}
});
}
2.2 网络连接/断开监听
typescript
// WiFi 连接/断开
connection.on('netAvailable', (netHandle) => {
console.log('网络可用:', netHandle.netId);
});
connection.on('netLost', (netHandle) => {
console.log('网络丢失:', netHandle.netId);
});
// 连接状态变化(更细粒度)
connection.on('netStateChange', (data) => {
console.log('是否WiFi:', data.isWifi);
console.log('是否蜂窝:', data.isCellular);
console.log('是否有网络:', data.isAvailable);
});
三、网络地址与 DNS 查询
3.1 获取 IP 地址
typescript
async function getLocalIp(): Promise<string[]> {
const netHandle = await connection.getDefaultNet();
const addrs = await connection.getAddressesByName(netHandle, 'localhost');
return addrs.map(a => a.address.address);
}
3.2 DNS 解析
typescript
async function dnsLookup(host: string): Promise<string[]> {
const netHandle = await connection.getDefaultNet();
const addrs = await connection.getAddressesByName(netHandle, host);
return addrs.map(a => `${a.address.address}:${a.port}`);
}
// 使用
dnsLookup('api.example.com').then(addrs => {
console.log('DNS解析结果:', addrs); // ['203.0.113.5:0', '2401:xxxx::1:0']
});
3.3 获取网络代理信息
typescript
async function getProxyInfo() {
const netHandle = await connection.getDefaultNet();
const proxy = await connection.getDefaultHttpProxy();
console.log('代理主机:', proxy.host);
console.log('代理端口:', proxy.port);
console.log('排除列表:', proxy.exclusionList);
}
四、实战:网络诊断工具
typescript
class NetworkDiagnostics {
private isOnline: boolean = false;
private currentType: string = 'none';
async init() {
try {
const netHandle = await connection.getDefaultNet();
const state = await connection.getNetCapabilities(netHandle);
this.isOnline = state.networkCapabilities.includes(
connection.NetCap.NET_CAPABILITY_INTERNET
);
this.updateType(state);
} catch {
this.isOnline = false;
}
this.startListening();
}
private updateType(state: connection.NetCap) {
if (state.bearerTypes.includes(connection.BearerType.WIFI)) {
this.currentType = 'WiFi';
} else if (state.bearerTypes.includes(connection.BearerType.CELLULAR)) {
this.currentType = '蜂窝网络';
} else {
this.currentType = '其他';
}
}
private startListening() {
connection.on('netCapabilitiesChange', async (handle) => {
const state = await connection.getNetCapabilities(handle);
this.isOnline = state.networkCapabilities.includes(
connection.NetCap.NET_CAPABILITY_INTERNET
);
this.updateType(state);
console.log(`网络更新: ${this.currentType}, 在线: ${this.isOnline}`);
});
}
getStatus() {
return {
online: this.isOnline,
type: this.currentType
};
}
destroy() {
connection.off('netCapabilitiesChange');
connection.off('netAvailable');
connection.off('netLost');
}
}
// 使用
const diag = new NetworkDiagnostics();
diag.init();
五、弱网检测与应对策略
typescript
// 检测弱网并降低资源消耗
class WeakNetworkHandler {
private isWeakNetwork: boolean = false;
private checkInterval: number = 3000; // 3秒检测一次
async startMonitoring() {
setInterval(async () => {
try {
const netHandle = await connection.getDefaultNet();
const state = await connection.getNetCapabilities(netHandle);
// 如果没有 INTERNET 能力或只有蜂窝(通常比WiFi慢),认为是弱网
const hasInternet = state.networkCapabilities.includes(
connection.NetCap.NET_CAPABILITY_INTERNET
);
const isCellularOnly =
state.bearerTypes.includes(connection.BearerType.CELLULAR) &&
!state.bearerTypes.includes(connection.BearerType.WIFI);
this.isWeakNetwork = !hasInternet || isCellularOnly;
if (this.isWeakNetwork) {
console.log('弱网环境,切换为低资源模式');
// 降低图片质量
// 减少预加载
// 增加超时时间
}
} catch {
this.isWeakNetwork = true;
}
}, this.checkInterval);
}
shouldLoadHDContent(): boolean {
return !this.isWeakNetwork;
}
}
六、API 速查表
| API | 说明 | 异步 |
|---|---|---|
getDefaultNet() |
获取默认网络 | ✅ |
getNetCapabilities(handle) |
获取网络能力 | ✅ |
getAddressesByName(handle, host) |
DNS解析 | ✅ |
getDefaultHttpProxy() |
获取代理 | ✅ |
on('netAvailable') |
网络可用监听 | - |
on('netLost') |
网络丢失监听 | - |
on('netCapabilitiesChange') |
网络能力变化 | - |
on('netStateChange') |
网络状态变化 | - |
off(event) |
移除监听 | - |
| BearerType | 说明 |
|---|---|
WIFI |
WiFi网络 |
CELLULAR |
蜂窝网络 |
ETHERNET |
以太网 |
BLUETOOTH |
蓝牙 |
| NetCap | 说明 |
|---|---|
NET_CAPABILITY_INTERNET |
可访问互联网 |
NET_CAPABILITY_NOT_METERED |
非计费网络(如WiFi) |
NET_CAPABILITY_NOT_VPN |
非VPN连接 |
总结
#mermaid-svg-yMOBWnUrboG5lHe2{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yMOBWnUrboG5lHe2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yMOBWnUrboG5lHe2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yMOBWnUrboG5lHe2 .error-icon{fill:#552222;}#mermaid-svg-yMOBWnUrboG5lHe2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yMOBWnUrboG5lHe2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yMOBWnUrboG5lHe2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yMOBWnUrboG5lHe2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yMOBWnUrboG5lHe2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yMOBWnUrboG5lHe2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yMOBWnUrboG5lHe2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yMOBWnUrboG5lHe2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yMOBWnUrboG5lHe2 .marker.cross{stroke:#333333;}#mermaid-svg-yMOBWnUrboG5lHe2 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yMOBWnUrboG5lHe2 p{margin:0;}#mermaid-svg-yMOBWnUrboG5lHe2 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-yMOBWnUrboG5lHe2 .cluster-label text{fill:#333;}#mermaid-svg-yMOBWnUrboG5lHe2 .cluster-label span{color:#333;}#mermaid-svg-yMOBWnUrboG5lHe2 .cluster-label span p{background-color:transparent;}#mermaid-svg-yMOBWnUrboG5lHe2 .label text,#mermaid-svg-yMOBWnUrboG5lHe2 span{fill:#333;color:#333;}#mermaid-svg-yMOBWnUrboG5lHe2 .node rect,#mermaid-svg-yMOBWnUrboG5lHe2 .node circle,#mermaid-svg-yMOBWnUrboG5lHe2 .node ellipse,#mermaid-svg-yMOBWnUrboG5lHe2 .node polygon,#mermaid-svg-yMOBWnUrboG5lHe2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yMOBWnUrboG5lHe2 .rough-node .label text,#mermaid-svg-yMOBWnUrboG5lHe2 .node .label text,#mermaid-svg-yMOBWnUrboG5lHe2 .image-shape .label,#mermaid-svg-yMOBWnUrboG5lHe2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-yMOBWnUrboG5lHe2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yMOBWnUrboG5lHe2 .rough-node .label,#mermaid-svg-yMOBWnUrboG5lHe2 .node .label,#mermaid-svg-yMOBWnUrboG5lHe2 .image-shape .label,#mermaid-svg-yMOBWnUrboG5lHe2 .icon-shape .label{text-align:center;}#mermaid-svg-yMOBWnUrboG5lHe2 .node.clickable{cursor:pointer;}#mermaid-svg-yMOBWnUrboG5lHe2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yMOBWnUrboG5lHe2 .arrowheadPath{fill:#333333;}#mermaid-svg-yMOBWnUrboG5lHe2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yMOBWnUrboG5lHe2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yMOBWnUrboG5lHe2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yMOBWnUrboG5lHe2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yMOBWnUrboG5lHe2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yMOBWnUrboG5lHe2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yMOBWnUrboG5lHe2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yMOBWnUrboG5lHe2 .cluster text{fill:#333;}#mermaid-svg-yMOBWnUrboG5lHe2 .cluster span{color:#333;}#mermaid-svg-yMOBWnUrboG5lHe2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-yMOBWnUrboG5lHe2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yMOBWnUrboG5lHe2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-yMOBWnUrboG5lHe2 .icon-shape,#mermaid-svg-yMOBWnUrboG5lHe2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yMOBWnUrboG5lHe2 .icon-shape p,#mermaid-svg-yMOBWnUrboG5lHe2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yMOBWnUrboG5lHe2 .icon-shape .label rect,#mermaid-svg-yMOBWnUrboG5lHe2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yMOBWnUrboG5lHe2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yMOBWnUrboG5lHe2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yMOBWnUrboG5lHe2 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} WiFi
蜂窝
无网络
connection.on监听网络变化
网络类型?
加载高清内容
降低流量消耗
显示离线状态/缓存数据
netCapabilitiesChange
实时更新
网络连接诊断是App体验的隐形护城河------好的App会在网络变化时无声地处理好一切,用户甚至不会察觉到。