场景一:APP获取当前连接网络信息

方案

  1. 以下属性基于netConn对象的getNetCapabilities函数,获取到的netCapabilities对象获取。

       <p id="p11422844122610">网络类型</p> <p id="p34232443263">上行带宽</p> <p id="p17423184417261">下行带宽</p> <p id="p4423154492619">网络能力</p>
    <p id="p6963923192717"><span>属性</span></p> <p id="p9963172310271">bearerTypes</p> <p id="p1296313237276">linkUpBandwidthKbps</p> <p id="p17963523152711">linkDownBandwidthKbps</p> <p id="p19639234277">networkCap</p>
    <p id="p4537142852716"><span>类型</span></p> <p id="p1537142832714">Array<NetBearType></p> <p id="p2537132872716">number</p> <p id="p25371928132714">number</p> <p id="p165381528122711">Array<NetCap></p>
    <p id="p19257173332712"><span>单位</span></p> <p id="p19257183382717">\</p> <p id="p2257233172712">kb/s</p> <p id="p12257133312710">kb/s</p> <p id="p6257033192711">\</p>
  2. 以下属性基于netConn的getConnectionProperties获取到的ConnectionProperties对象中获取。

       <p id="p10362133952816">网卡名称</p> <p id="p1199917108376">所属域</p> <p id="p1736220391280">最大传输单元</p> <p id="p18362639102812">链路信息</p> <p id="p19706221143714">路由信息</p> <p id="p9362173916281">网络地址</p>
    <p id="p10896112917"><span>属性</span></p> <p id="p15891813296">interfaceName</p> <p id="p148919115296">domains</p> <p id="p5892018295">mtu</p> <p id="p1889191172916">linkAddresses</p> <p id="p1189201162919">routes</p> <p id="p198931132912">dnses</p>
    <p id="p237957192910"><span>类型</span></p> <p id="p33791676298">string</p> <p id="p837918720290">string</p> <p id="p1237947162919">number</p> <p id="p153795716292">Array<LinkAddress></p> <p id="p3379167122913">Array<RouteInfo></p> <p id="p63797712913">Array<NetAddress></p>
    <p id="p586411242911"><span>单位</span></p> <p id="p1386491219293">\</p> <p id="p1286431242913">\</p> <p id="p17864181212910">bytes</p> <p id="p886491219297">\</p> <p id="p17864161213295">\</p> <p id="p16864812112915">\</p>
  3. 基于@ohos.net.statistics (流量管理)能力提供的getUidTxBytes接口,获取应用实时网速(bytes)。

核心代码

  1. 基于netConn对象的getNetCapabilities函数,获取netCapabilities对象。

    let netHandle = await connection.getDefaultNet();
    let netCapabilities: connection.NetCapabilities = await connection.getNetCapabilities(netHandle);
  2. 基于netCapabilities对象获取上下行带宽(单位kb/s,0为无法评估当前网络带宽)。

    // 获取上行带宽
    let upKbps = netCapabilities.linkUpBandwidthKbps;
    // 获取下行带宽
    let downKbps = netCapabilities.linkDownBandwidthKbps ;
  3. 基于netCapabilities获取网络类型。

    tips:当Wi-Fi和蜂窝同时连接的时候,通过网络能力获取bearType实际只返回Wi-Fi的状态信息,此为现象为系统规格。

    let type:connection.NetBearType = netCapabilities.bearerTypes[0];
获取到的返回值和如下枚举对应:

<a name="table9900352194013"></a>
<table><thead align="left"><tr id="row890065212407"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.1.4.1.1"><p id="p1189054184017"><a name="p1189054184017"></a><a name="p1189054184017"></a>名称</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.1.4.1.2"><p id="p151893544402"><a name="p151893544402"></a><a name="p151893544402"></a>值</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.1.4.1.3"><p id="p1189155413405"><a name="p1189155413405"></a><a name="p1189155413405"></a>说明</p>
</th>
</tr>
</thead>
<tbody><tr id="row79001352104011"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p1189105418400"><a name="p1189105418400"></a><a name="p1189105418400"></a>BEARER_CELLULAR</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p1718916545406"><a name="p1718916545406"></a><a name="p1718916545406"></a>0</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p018925416402"><a name="p018925416402"></a><a name="p018925416402"></a>蜂窝网络</p>
</td>
</tr>
<tr id="row159001352124018"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p20189135434018"><a name="p20189135434018"></a><a name="p20189135434018"></a>BEARER_WIFI</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p61891054204010"><a name="p61891054204010"></a><a name="p61891054204010"></a>1</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p7189454184011"><a name="p7189454184011"></a><a name="p7189454184011"></a>Wi-Fi网络</p>
</td>
</tr>
<tr id="row15901185213407"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p91894542403"><a name="p91894542403"></a><a name="p91894542403"></a>BEARER_ETHERNET</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p31899549403"><a name="p31899549403"></a><a name="p31899549403"></a>3</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p218935434010"><a name="p218935434010"></a><a name="p218935434010"></a>以太网网络</p>
</td>
</tr>
<tr id="row8901452144014"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p11189165410408"><a name="p11189165410408"></a><a name="p11189165410408"></a>BEARER_VPN</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p1518965412408"><a name="p1518965412408"></a><a name="p1518965412408"></a>4</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p218955417406"><a name="p218955417406"></a><a name="p218955417406"></a>VPN网络</p>
</td>
</tr>
</tbody>
</table>
  1. 基于netCapabilities获取网络具体能力。

    let cap:Array<NetCap> = netCapabilities.networkCap;
获取到的返回值和如下枚举对应:

<a name="table1094817616427"></a>
<table><thead align="left"><tr id="row59488611422"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.1.4.1.1"><p id="p7860713184218"><a name="p7860713184218"></a><a name="p7860713184218"></a>名称</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.1.4.1.2"><p id="p7860121364220"><a name="p7860121364220"></a><a name="p7860121364220"></a>值</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.1.4.1.3"><p id="p386018134424"><a name="p386018134424"></a><a name="p386018134424"></a>说明</p>
</th>
</tr>
</thead>
<tbody><tr id="row1948269421"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p13860813184211"><a name="p13860813184211"></a><a name="p13860813184211"></a>NET_CAPABILITY_MMS</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p7860161374211"><a name="p7860161374211"></a><a name="p7860161374211"></a>0</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p108601613144217"><a name="p108601613144217"></a><a name="p108601613144217"></a>表示网络可以访问运营商的MMSC(Multimedia Message Service,多媒体短信服务)发送和接收彩信</p>
</td>
</tr>
<tr id="row179481062428"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p1686041394211"><a name="p1686041394211"></a><a name="p1686041394211"></a>NET_CAPABILITY_NOT_METERED</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p3860101304212"><a name="p3860101304212"></a><a name="p3860101304212"></a>11</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p1386071304212"><a name="p1386071304212"></a><a name="p1386071304212"></a>表示网络流量未被计费</p>
</td>
</tr>
<tr id="row10949362426"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p1086041324216"><a name="p1086041324216"></a><a name="p1086041324216"></a>NET_CAPABILITY_INTERNET</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p148602138426"><a name="p148602138426"></a><a name="p148602138426"></a>12</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p086016135422"><a name="p086016135422"></a><a name="p086016135422"></a>表示该网络应具有访问Internet的能力,该能力由网络提供者设置</p>
</td>
</tr>
<tr id="row18949126114212"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p38605139428"><a name="p38605139428"></a><a name="p38605139428"></a>NET_CAPABILITY_NOT_VPN</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p18860161314421"><a name="p18860161314421"></a><a name="p18860161314421"></a>15</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p15860151324219"><a name="p15860151324219"></a><a name="p15860151324219"></a>表示网络不使用VPN(Virtual Private Network,虚拟专用网络)</p>
</td>
</tr>
<tr id="row994956184210"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p1086013137424"><a name="p1086013137424"></a><a name="p1086013137424"></a>NET_CAPABILITY_VALIDATED</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p18860513204212"><a name="p18860513204212"></a><a name="p18860513204212"></a>16</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p1786111304211"><a name="p1786111304211"></a><a name="p1786111304211"></a>表示该网络访问Internet的能力被网络管理成功验证,该能力由网络管理模块设置</p>
</td>
</tr>
<tr id="row79491961429"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p1286131312423"><a name="p1286131312423"></a><a name="p1286131312423"></a>NET_CAPABILITY_PORTAL12+</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p98616133421"><a name="p98616133421"></a><a name="p98616133421"></a>17</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p108616131426"><a name="p108616131426"></a><a name="p108616131426"></a>表示系统发现该网络存在强制网络门户,需要用户登陆认证,该能力由网络管理模块设置</p>
</td>
</tr>
</tbody>
</table>
  1. 基于netConn的getConnectionProperties函数获取网络连接信息。

    // 获取网卡名称
    let interfaceName: string = properties.interfaceName;
    // 获取所属域
    let domains: string = properties.domains;
    // 获取最大传输单元
    let mtu: number= properties.mtu;
    // 获取链路信息
    let linkAddresses: Array<LinkAddress> = properties.linkAddresses;
    // 获取路由信息
    let routes: Array<RouteInfo> = properties.routes;
    // 获取网络地址
    let dnses: Array<NetAddress> = properties.dnses;
  2. 基于@ohos.net.statistics能力,获取当前应用的网络传输速度。

    获取应用的网络传输速度依赖于getUidTxBytes/getUidRxBytes函数,其中函数入参uid为应用唯一标识,和应用一一对应。

    Tips: 注意uid在应用卸载重装后会发生变化。

    // 导入模块
    import { statistics } from '@kit.NetworkKit';
    import bundleManager from '@ohos.bundle.bundleManager';
    
    // 获取应用程序uid(设备上该应用的唯一标识,和应用一一对应,卸载重装后会发生变化)
    let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION;
    let bundleInfo = await bundleManager.getBundleInfoForSelf(bundleFlags);
    let uid = bundleInfo.appInfo.uid;
    
    // 通过应用uid获取当前应用的上下行带宽
    let txBytes = statistics.getUidTxBytes(uid);
    let rxBytes = statistics.getUidRxBytes(uid);

场景二:APP感知当前连接网络的状态

方案

基于@ohos.net.connection模块能力,监听网络可用,网络切换,网络不可用,网络丢失等事件,使用前需要调用register开启监听,监听结束后需要调用unregister关闭当前监听请求。

Tips: 各事件监听没有各自独立的off函数,也就是说所有使用该能力监听的事件,只能一起随着unregister的调用关闭监听。

各种场景切换说明:

  1. 当Wi-Fi以及蜂窝都断开的情况下,设备从无网络到有网络会触发netAvailable事件,netCapabilitiesChange事件和netConnectionPropertiesChange事件。
  2. 当Wi-Fi或蜂窝某一个正常连接的情况下,设备从有网络到无网络状态会触发netLost事件。
  3. 当Wi-Fi和蜂窝都正常连接的情况下,设备从Wi-Fi到蜂窝会触发netLost事件(Wi-Fi丢失)之后触发 netAvaliable事件(蜂窝可用)。

核心代码

回调参数解析

  1. 下列监听回调中connection.NetHandle类型参数data为数据网络句柄,主要关注其netid属性,此属性可以对网络进行唯一标识。

    例如:通过监听on('netAvailable'),保存当前网络的netId,当切换网络时回调该接口,通过比对netId判断是否同一网络。

  2. netCapabilitiesChange回调中的参数data为connection.NetCapabilityInfo类型,包含netHandle和netCap两个属性,其中netHandle属性同其它回调一样,此处不再赘述。netCap属性用来存储数据网络的传输能力和承载类型,主要关注其中networkCap(网络能力)和bearType(网络类型)两个属性,用来观察当前网络的能力和类型变化。

    // 无效值常量
    private static COMMON_INIT_VAL: number = -1
    // 保存上次可用的netId
    private lastAvailableNetId: number = Index.COMMON_INIT_VAL;
    
    //监听网络是否可用
    this.netConn.on('netAvailable', (data: connection.NetHandle) => {
      if (this.lastAvailableNetId === Index.COMMON_INIT_VAL) {
        this.lastAvailableNetId = data.netId;
      } else if (this.lastAvailableNetId === data.netId) { // 当前再次恢复可用的网络和之前的网络为同一网络
        // TODO
      } else { // 当前再次恢复可用的网络和之前的网络为不同网络
        // TODO
      }
    })
    
    //网络丢失(比如网络断开)
    this.netConn.on("netLost",(data: connection.NetHandle) => {
      console.log("net lost" + JSON.stringify(data))
    })
    
    //网络不可用(比如已连接Wi-Fi,但是Wi-Fi图标上有感叹号)
    this.netConn.on("netUnavailable", () => {
      console.log("net unavailable id is " + this.lastAvailableNetId);
    })
    
    this.netConn.on('netCapabilitiesChange', (data: connection.NetCapabilityInfo) => {
      console.log('net capabilities change: ' + JSON.stringify(data));
      let currentNetCap = data.netCap.networkCap
      // TODO 对比及对比出现异同的处理逻辑由开发者自定义
    
      // 获取当前网络类型,可与之前保存的网络类型做对比(之前在哪里保存,由开发者自定义)
      let currentBearType = data.netCap.bearerTypes;
      // TODO 对比及对比出现异同的处理逻辑由开发者自定义
    
      // 获取netid,与之前保存的做对比
      let currentNetId = data.netHandle.netId;
      // TODO 对比及对比出现异同的处理逻辑由开发者自定义
    });
    
    listenNetConnEvent(): void {
      //开启监听事件
      this.netConn.register((error: BusinessError) => {
      console.log('netConn register error: ' + JSON.stringify(error));
    });
    
    // 使用unregister接口取消订阅
    this.netConn.unregister((error: BusinessError) => {
      console.log('netConn unregister error: ' + JSON.stringify(error));
    });
    }

常见问题

  1. 如何实现弱网自动切换?

    应用中实时感知当前网络速度,在网络可用且网速低于某一阈值(由用户根据自己的实际场景定义)的情况下由应用进行切换。

  2. 网络管理部分的系统原生能力是否支持应用主动进行网络切换?

    不支持,仅支持通过回调感知系统网络切换。

说明:
netConn均代表connection.NetConnection对象,该对象在创建时,根据关注的网络类型不同有所区别。当关注蜂窝网络时,需要传入相关的网络特征,Wi-Fi则不需要。
Wi-Fi:

let netConn = connection.createNetConnection();

蜂窝:

let netConn= netConn.createNetConnection({
 netCapabilities: {
   bearerTypes: [connection.NetBearType.BEARER_CELLULAR]
 }
});

HarmonyOS码上奇行
9.3k 声望3.3k 粉丝

欢迎关注 HarmonyOS 开发者社区:[链接]