引言

网络是移动应用的命脉。在开发中,我们需要知道设备当前是否联网、连接的是 WiFi 还是蜂窝网络、带宽多少、DNS 解析是否正常。HarmonyOS NEXT 通过 @ohos.net.connection 模块将这些网络诊断能力统一暴露为简洁的同步与异步 API,大部分操作无需权限即可使用。

@ohos.net.connection 属于 @kit.NetworkKit,与 Android 的 ConnectivityManager 和 iOS 的 NWPathMonitor 定位类似,但 API 设计更加直接——核心检测全部同步返回,DNS 解析通过 Promise 异步完成,没有复杂的事件订阅机制。

本文将深入讲解 @ohos.net.connection 的网络状态检测、带宽查询、承载类型识别和 DNS 域名解析四大核心能力,并构建一个"网络连接诊断实验室"Demo,在一个页面中完成网络诊断的全部操作。

一、API 架构:同步检测 + 异步解析

1.1 核心设计理念

@ohos.net.connection 的 API 分为两层:同步层负责网络状态检测和能力查询——所有方法都带 Sync 后缀,直接返回结果,零延迟;异步层负责 DNS 域名解析——通过 Promise 返回解析结果,适合耗时网络操作。

import connection from '@ohos.net.connection';

// 同步:瞬间返回,无需 await
const hasNet = connection.hasDefaultNetSync();          // boolean
const netHandle = connection.getDefaultNetSync();       // NetHandle
const caps = connection.getNetCapabilitiesSync(netHandle); // NetCapabilities

// 异步:Promise 返回
connection.getAddressesByName('www.example.com')
  .then((addrs) => { /* Array<NetAddress> */ })
  .catch((e) => { /* Error */ });

这种"同步检测 + 异步解析"的双层设计非常务实:连接检测是高频操作(每次网络请求前都需要判断),同步 API 避免不必要的异步开销;DNS 解析本身涉及网络 I/O,异步 Promise 模型正合适。

1.2 hasDefaultNetSync —— 网络连接检测

hasDefaultNetSync() 是网络诊断中最基础的 API。它同步返回一个 boolean,表示当前是否存在默认数据网络。这个方法无参数、无权限要求,适合在任何地方调用。

private refreshNetState(): void {
  try {
    const hasNet = connection.hasDefaultNetSync();
    this.isConnected = hasNet;
    if (hasNet) {
      // 有默认网络,进一步获取详细信息
      const netHandle = connection.getDefaultNetSync();
      const caps = connection.getNetCapabilitiesSync(netHandle);
      // ... 读取带宽、承载类型等
    } else {
      // 无网络连接
      this.bearerType = '无连接';
    }
  } catch (e) {
    this.isConnected = false;
    // 异常降级:假设无网络
  }
}

关键点:

  • 返回 true 仅表示系统存在默认数据网络路由,不代表目标服务器可达
  • 配合 @ohos.net.http 使用时,hasDefaultNetSync() 可以作为请求前的快速检查
  • 必须在 try/catch 中调用,SDK 内部可能因系统服务异常而抛出错误

1.3 getDefaultNetSync —— 获取默认网络句柄

hasDefaultNetSync() 返回 true 时,可以通过 getDefaultNetSync() 获取当前默认网络的 NetHandle 对象。NetHandle 是一个不透明的网络句柄,本身没有可读属性,它的作用是为 getNetCapabilitiesSync() 提供参数。

const netHandle = connection.getDefaultNetSync();
// netHandle 是一个 NetHandle 对象,用于后续查询
const caps = connection.getNetCapabilitiesSync(netHandle);

NetHandle 的设计类似于文件描述符——它本身不暴露细节,但可以作为钥匙打开对应的能力信息。

1.4 getNetCapabilitiesSync —— 网络能力信息

getNetCapabilitiesSync(netHandle) 是网络诊断的核心 API。它接收一个 NetHandle,返回一个 NetCapabilities 对象,包含当前网络的完整能力描述:

属性 类型 说明
linkDownBandwidthKbps number 下行带宽(kbps),可能为 0 或 undefined
linkUpBandwidthKbps number 上行带宽(kbps),可能为 0 或 undefined
bearerTypes Array<number> 承载类型数组,每个元素为 BearerType 枚举值

注意:linkDownBandwidthKbpslinkUpBandwidthKbps 的值取决于底层网络驱动是否提供了带宽信息。在模拟器或某些网络环境下,这两个值可能为 0 或 undefined,需要做防御性处理。

const caps = connection.getNetCapabilitiesSync(netHandle);
const downBw = caps.linkDownBandwidthKbps;
const upBw = caps.linkUpBandwidthKbps;

// 防御性处理:带宽值为空或 0 时显示占位符
this.downBand = (downBw !== undefined && downBw > 0) ?
  (downBw / 1000).toFixed(1) + ' Mbps' : '--';
this.upBand = (upBw !== undefined && upBw > 0) ?
  (upBw / 1000).toFixed(1) + ' Mbps' : '--';

1.5 bearerTypes —— 承载类型识别

bearerTypesNetCapabilities 中最实用的字段。它返回一个数字数组,每个数字代表一种网络承载类型(BearerType 枚举):

承载类型 说明
0 WiFi IEEE 802.11 无线局域网
1 蜂窝网络 4G/5G 移动网络
2 VPN 虚拟专用网络
3 以太网 有线网络连接

一个网络连接可能同时具有多种承载类型(例如 VPN over WiFi)。在实际使用中,bearerTypes[0] 通常是主承载类型。

private bearerLabel(type: number): string {
  if (type === 0) return 'WiFi';
  if (type === 1) return '蜂窝网络';
  if (type === 2) return 'VPN';
  if (type === 3) return '以太网';
  return '其他';
}

// 使用
const bt = caps.bearerTypes;
if (bt && bt.length > 0) {
  this.bearerType = this.bearerLabel(bt[0] as number);
} else {
  this.bearerType = '未知';
}

二、DNS 域名解析

2.1 getAddressesByName —— 异步 DNS 查询

getAddressesByName(host: string)@ohos.net.connection 提供的 DNS 解析 API。它接收一个域名字符串,返回 Promise<Array<NetAddress>>。每个 NetAddress 对象包含三个字段:

属性 类型 说明
address string IP 地址字符串(IPv4 或 IPv6 格式)
family number 协议族(1 = IPv4,2 = IPv6)
port number 端口号(DNS 查询中通常为 0)
private resolveDNS(): void {
  const host = this.dnsHost.trim();
  if (host === '') {
    this.addLog('请输入域名', 'error');
    return;
  }
  this.dnsLoading = true;
  this.dnsResult = '解析中...';

  connection.getAddressesByName(host)
    .then((addrs: Array<connection.NetAddress>) => {
      this.dnsLoading = false;
      if (addrs.length > 0) {
        const ipList: string[] = [];
        for (let i = 0; i < addrs.length; i++) {
          ipList.push(addrs[i].address);
        }
        this.dnsResult = ipList.join('\n');
        this.addLog('DNS: ' + host + ' → ' +
          addrs.length.toString() + ' 个地址', 'success');
      } else {
        this.dnsResult = '未解析到地址';
        this.addLog('DNS: ' + host + ' 无记录', 'system');
      }
    })
    .catch((e: Error) => {
      this.dnsLoading = false;
      this.dnsResult = '解析失败: ' + e.message;
      this.addLog('DNS 失败: ' + e.message, 'error');
    });
}

DNS 解析的完整流程:

  1. 用户输入域名(如 www.example.com
  2. 调用 getAddressesByName(host) 发起系统级 DNS 查询
  3. 系统返回所有解析到的 IP 地址(可能有多个,包括 IPv4 和 IPv6 地址)
  4. 遍历 NetAddress 数组,提取 address 字段展示

2.2 DNS 解析的实际意义

在网络诊断场景中,DNS 解析是判断"网络是否真正可用"的重要依据。hasDefaultNetSync() 返回 true 只说明设备有网络连接,而 DNS 解析成功才说明 DNS 服务器可达、域名可以正常解析。这两个检查配合使用,可以准确定位网络问题:

  • hasDefaultNetSync() = false → 设备无网络连接,检查 WiFi/蜂窝开关
  • hasDefaultNetSync() = true 但 DNS 解析失败 → 网络已连接但 DNS 不通,检查路由器/DNS 配置
  • 两者都正常 → 网络连通性良好
    在这里插入图片描述
    在这里插入图片描述

三、实战 Demo:网络连接诊断实验室

3.1 页面设计

"网络连接诊断实验室"页面分为五个功能区域:

  1. 连接状态卡片:最上方展示当前网络连接状态(绿色圆点 + "已连接"或红色圆点 + “未连接”),右侧显示承载类型标签(WiFi / 蜂窝网络 / VPN / 以太网)。下方三栏卡片分别展示下行带宽、上行带宽和承载类型。

  2. 网络操作区:两个按钮——"刷新网络状态"重新读取当前网络信息,"检测连接"调用 hasDefaultNetSync() 并在日志中输出结果。

  3. DNS 域名解析区:文本输入框 + "解析"按钮,下方三个预设域名快捷按钮(example.com、baidu.com、github.com),点击后自动填入域名并执行解析。解析结果显示在底部灰色代码框中,支持多行展示。

  4. API 能力说明区:以灰色文字展示核心 API 的方法签名和功能说明,帮助开发者快速了解模块能力。

  5. 操作日志区:按时间倒序记录所有操作,不同类别(success / error / system)使用不同颜色标记。

3.2 核心实现

数据模型:

interface ConnLog {
  time: string;
  msg: string;
  category: string;
}

@State isConnected: boolean = false;
@State bearerType: string = '--';
@State downBand: string = '--';
@State upBand: string = '--';
@State dnsHost: string = 'www.example.com';
@State dnsResult: string = '--';
@State dnsLoading: boolean = false;
@State logs: ConnLog[] = [];

状态设计要点:

  • isConnected 控制连接状态的 UI 颜色和文字
  • bearerType 在三种场景下取值不同:正常连接时显示承载标签,无连接时显示"无连接",异常时显示"–"
  • dnsLoading 同时控制按钮文字和禁用状态,防止重复点击
  • logs 使用 ConnLog 接口统一日志格式,包含时间戳、消息内容和分类

日志系统:

private addLog(msg: string, category: string): void {
  const now = new Date();
  const ts = now.getHours().toString().padStart(2, '0') + ':' +
    now.getMinutes().toString().padStart(2, '0') + ':' +
    now.getSeconds().toString().padStart(2, '0');
  const entry: ConnLog = { time: ts, msg: msg, category: category };
  const newLogs: ConnLog[] = [entry];
  this.logs = newLogs.concat(this.logs).slice(0, 30);
}

日志采用"新在前、旧在后"的顺序(newLogs.concat(this.logs)),最多保留 30 条记录。时间格式化为 HH:MM:SS 并补零对齐。

日志颜色函数:

private logColor(cat: string): string {
  if (cat === 'success') return '#10B981';
  if (cat === 'error') return '#EF4444';
  return '#64748B';
}

统计卡片 Builder:

@Builder
statCard(label: string, value: string, color: string) {
  Column() {
    Text(label)
      .fontSize(10).fontColor('#94A3B8').margin({ bottom: 4 })
    Text(value)
      .fontSize(13).fontColor(color)
      .fontWeight(FontWeight.Bold).fontFamily('monospace')
  }
  .alignItems(HorizontalAlign.Center)
  .layoutWeight(1)
  .padding({ top: 8, bottom: 8 })
  .backgroundColor('#F8FAFC').borderRadius(8)
  .border({ width: 1, color: '#E2E8F0' })
  .margin({ right: 8 })
}

3.3 交互方式

Demo 提供三个核心交互点:

  1. 刷新网络状态:单击按钮后重新执行 refreshNetState(),读取最新的网络连接状态、带宽数据和承载类型。适合在切换 WiFi / 移动网络后验证。

  2. 检测连接:直接调用 hasDefaultNetSync() 并输出结果到日志。这是一个最轻量的网络检查操作。

  3. DNS 域名解析:输入域名后点击"解析"按钮,或点击预设域名快捷按钮(example.com / baidu.com / github.com)直接触发解析。解析过程中按钮变为灰色"解析中…"并禁用,防止重复提交。解析结果按行展示所有 IP 地址。

四、实际应用场景

4.1 网络请求前的连通性检查

在发起 HTTP 请求前,先用 hasDefaultNetSync() 判断网络状态,避免无网络时发起注定失败的请求:

function safeHttpRequest(url: string): void {
  if (!connection.hasDefaultNetSync()) {
    console.error('无网络连接,取消请求');
    return;
  }
  // 发起 HTTP 请求
  const httpRequest = http.createHttp();
  httpRequest.request(url);
}

4.2 根据网络类型调整策略

通过 bearerTypes 判断当前网络类型,在 WiFi 下预加载高清资源,在蜂窝网络下使用低质量资源:

function shouldPreloadHD(): boolean {
  try {
    const netHandle = connection.getDefaultNetSync();
    const caps = connection.getNetCapabilitiesSync(netHandle);
    const bt = caps.bearerTypes;
    // 仅 WiFi 或以太网下预加载高清资源
    return bt && bt.length > 0 && (bt[0] === 0 || bt[0] === 3);
  } catch (e) {
    return false; // 异常时保守策略:不预加载
  }
}

4.3 网络诊断工具

构建一个完整的网络诊断函数,依次检查连接状态、网络类型、DNS 解析:

interface NetDiagnosis {
  connected: boolean;
  bearerType: string;
  dnsResolved: boolean;
  dnsAddresses: string[];
}

async function runNetDiagnosis(host: string): Promise<NetDiagnosis> {
  const result: NetDiagnosis = {
    connected: false,
    bearerType: '未知',
    dnsResolved: false,
    dnsAddresses: []
  };

  try {
    result.connected = connection.hasDefaultNetSync();
    if (result.connected) {
      const handle = connection.getDefaultNetSync();
      const caps = connection.getNetCapabilitiesSync(handle);
      if (caps.bearerTypes && caps.bearerTypes.length > 0) {
        result.bearerType = ['WiFi', '蜂窝网络', 'VPN', '以太网'][caps.bearerTypes[0]] || '其他';
      }

      const addrs = await connection.getAddressesByName(host);
      result.dnsResolved = addrs.length > 0;
      for (let i = 0; i < addrs.length; i++) {
        result.dnsAddresses.push(addrs[i].address);
      }
    }
  } catch (e) {
    // 诊断失败,返回默认值
  }

  return result;
}

五、与 @ohos.net.http 的协作关系

@ohos.net.connection@ohos.net.http 同属 @kit.NetworkKit,两者职责分明、配合紧密:

模块 职责 典型 API
@ohos.net.connection 网络状态检测、能力查询、DNS 解析 hasDefaultNetSync, getNetCapabilitiesSync, getAddressesByName
@ohos.net.http HTTP 请求发送、响应处理 createHttp, request, HttpResponse

协作模式:

// 1. 先检测网络状态
if (!connection.hasDefaultNetSync()) {
  showToast('网络未连接');
  return;
}

// 2. 可选:根据网络类型调整请求策略
const caps = connection.getNetCapabilitiesSync(connection.getDefaultNetSync());

// 3. 发起 HTTP 请求
const req = http.createHttp();
req.request('https://api.example.com/data', {
  method: http.RequestMethod.GET,
  connectTimeout: caps.bearerTypes?.[0] === 1 ? 15000 : 5000  // 蜂窝网络给更长超时
});

六、ArkTS 使用注意事项

6.1 API 版本差异

@ohos.net.connection 在 API 24 中提供的是精简版 API。实际可用的 API 包括:

  • hasDefaultNetSync() — 同步检测
  • getDefaultNetSync() — 获取默认网络句柄
  • getNetCapabilitiesSync(netHandle) — 获取网络能力
  • getAddressesByName(host) — DNS 解析(异步 Promise)

文档中可能提到的 connection.on('netCapabilitiesChange')connection.off('netCapabilitiesChange') 事件订阅机制在当前 SDK 版本中不可用。如果需要持续监听网络状态变化,应通过定时轮询 hasDefaultNetSync() 来实现。

6.2 带宽值的防御性处理

linkDownBandwidthKbpslinkUpBandwidthKbps 在以下情况下可能为 0 或 undefined:

  • 模拟器环境
  • 部分 VPN 连接
  • 驱动未提供带宽信息

代码必须做空值判断:

const bw = caps.linkDownBandwidthKbps;
const display = (bw !== undefined && bw > 0) ?
  (bw / 1000).toFixed(1) + ' Mbps' : '--';

6.3 权限说明

  • hasDefaultNetSync()getDefaultNetSync() 无权限要求
  • getNetCapabilitiesSync() 的带宽属性需要 ohos.permission.GET_NETWORK_INFO 权限(缺省声明不影响编译)
  • getAddressesByName() 需要 ohos.permission.INTERNET 权限

七、总结

@ohos.net.connection 是 HarmonyOS NEXT 中检测网络连接状态和执行 DNS 解析的核心模块。通过本文的学习,你应该已经掌握:

  1. 同步检测模型hasDefaultNetSync() 无参数无权限,直接返回 boolean,完成最基础的网络连通性判断
  2. 网络能力查询getDefaultNetSync() + getNetCapabilitiesSync() 组合获取完整网络能力信息,包括带宽(linkDownBandwidthKbps/linkUpBandwidthKbps)和承载类型(bearerTypes:WiFi/蜂窝/VPN/以太网)
  3. DNS 域名解析getAddressesByName(host) 异步 Promise 返回 Array<NetAddress>,支持 IPv4/IPv6 多地址解析
  4. 防御性编程:带宽值可能为空或 0,承载类型数组可能为空——所有网络数据都需要做空值判断
  5. 与 http 模块协作:connection 负责检测网络状态和类型,http 负责发起请求——两者同属 @kit.NetworkKit,形成完整的网络通信栈

@ohos.net.connection 的最佳使用模式可以总结为:

请求前用 hasDefaultNetSync 快速判断,需要详情时用 getNetCapabilitiesSync 查询能力,怀疑 DNS 问题时用 getAddressesByName 验证解析。所有 API 同步为主、异步为辅——简洁高效。

网络连接状态是应用通信的基础。虽然 @ohos.net.connection 的 API 数量不多,但它与 @ohos.net.http 的组合覆盖了从网络检测到数据通信的完整链路。在应用架构中为网络诊断保留一个标准化的检查流程,是所有网络相关应用的必修课。

@ohos.net.connection 属于 @kit.NetworkKit,是 HarmonyOS NEXT 网络通信能力的基础模块。它的同步 API 零开销、异步 DNS 解析简洁高效,相比 Android 的 ConnectivityManager 回调模式和 iOS 的 NWPathMonitor 异步监听,@ohos.net.connection 的同步优先设计更符合"先检测、再请求"的直觉编程模型。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐