• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { connection } from '@kit.NetworkKit';
17import { BusinessError, emitter } from '@kit.BasicServicesKit';
18import { radio } from '@kit.TelephonyKit';
19import { wifiManager } from '@kit.ConnectivityKit';
20import { logger } from './Logger';
21import { NetworkEventData } from './EmitterData';
22import { HashMap, JSON } from '@kit.ArkTS';
23
24type NetworkData = boolean | connection.NetBlockStatusInfo | connection.NetBearType
25  | connection.NetConnectionPropertyInfo | connection.NetCapabilityInfo;
26
27// 网络监听emitter事件
28export enum NetworkEventName {
29  // 注册网络监听订阅事件
30  NetObserverRegister,
31  // 网络可用
32  NetAvailable,
33  // 网络阻塞
34  NetBlock,
35  // 网络丢失/断开
36  NetLost,
37  // 当网络能力变化时,如网络从无网络到有网络、从4G切换到5G
38  NetCapabilitiesChange,
39  // 网络不可用
40  NetUnavailable,
41  // WIFI状态改变
42  WifiStateChange,
43  // WIFI连接状态改变
44  WifiConnectionChange,
45  // 弱网
46  WeakNet,
47  // 订阅网络连接信息变化事件,当网络连接信息变化时,如从无网络到有网络、从Wi-Fi切换到蜂窝
48  NetConnectionPropertiesChange
49}
50
51export class NetUtils {
52  public static instance: NetUtils;
53  private connectionMap: HashMap<connection.NetBearType, connection.NetConnection> = new HashMap();
54  // 网络状态监听eventId
55  private networkEventId: number = 10001;
56  // 网络监听相关结果数据
57  private emitterEvent: NetworkEventData;
58
59  constructor() {
60    this.emitterEvent = new NetworkEventData(this.networkEventId);
61  }
62
63  static getInstance(): NetUtils {
64    if (!NetUtils.instance) {
65      NetUtils.instance = new NetUtils();
66    }
67    return NetUtils.instance;
68  }
69
70  public getEmitterEvent(): NetworkEventData {
71    return this.emitterEvent;
72  }
73
74  private setEventPriority(priority: emitter.EventPriority): void {
75    this.emitterEvent.priority = priority;
76  }
77
78  /**
79   * 通过emitter将结果传递给页面
80   * @param eventName 事件名称
81   * @param status    网络状态(可传递不同的监听结果数据类型)
82   * @param netType   网络类型(WI-FI、蜂窝数据等)
83   * @param priority  emitter事件权重
84   */
85  private postEvent(eventName: NetworkEventName, status: NetworkData, netType?: connection.NetBearType,
86    priority?: emitter.EventPriority) {
87    this.emitterEvent.priority = priority;
88    emitter.emit(this.emitterEvent, {
89      data: new NetEventData(eventName, status, netType)
90    })
91  }
92
93  /**
94   * 开启网络监听
95   * @param netType 需要监听的网络类型
96   */
97  public startNetObserve(...netType: connection.NetBearType[]) {
98    netType.forEach((type: connection.NetBearType) => {
99      this.networkObserve(type);
100      if (type === connection.NetBearType.BEARER_WIFI) {
101        this.wifiStateObserve();
102      }
103    })
104  }
105
106  /**
107   * 停止网络监听
108   */
109  public stopNetObserve(netType: connection.NetBearType) {
110    this.connectionMap.get(netType).unregister(() => {
111      logger.info('Success unregister:' + netType.toString());
112    })
113  }
114
115  /**
116   * 停止所有网络监听
117   */
118  public stopAllNetObserve() {
119    emitter.off(this.getEmitterEvent().eventId);
120    this.connectionMap.forEach((netConnection: connection.NetConnection, netType: connection.NetBearType) => {
121      netConnection.unregister(() => {
122        logger.info('Success unregister:' + netType.toString());
123      });
124    })
125  }
126
127  /**
128   * 获取当前网络连接类型
129   * 判断当前使用的网络是蜂窝或者Wi-Fi
130   * BEARER_CELLULAR时(值为0),表示蜂窝网络
131   * BEARER_WIFI时(值为1),表示Wi-Fi网络
132   * BEARER_BLUETOOTH时(值为2),表示蓝牙网络
133   * BEARER_ETHERNET时(值为3),表示以太网网络
134   * BEARER_VPN时(值为4),表示VPN网络
135   * @returns 当前可用网络类型的列表
136   */
137  getNetworkConnectionType(): Array<connection.NetBearType> {
138    try {
139      // 获取默认激活的数据网络
140      let netHandle = connection.getDefaultNetSync();
141      if (!netHandle || netHandle.netId === 0) {
142        return [];
143      }
144      // 获取网络的类型、拥有的能力等信息
145      let netCapability = connection.getNetCapabilitiesSync(netHandle);
146      return netCapability.bearerTypes;
147    } catch (e) {
148      let err = e as BusinessError;
149      logger.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
150      return [];
151    }
152  }
153
154  /**
155   * 判断当前网络是否可用
156   * 使用网络前,例如打开一个应用时,需要检查当前连接的网络是否可用。
157   * 如果可用,则正常进行网络请求;如果不可用,则需要提示用户网络不可用。
158   * @returns 当前网络是否可用
159   */
160  judgeHasNet(): boolean {
161    try {
162      let netHandle = connection.getDefaultNetSync();
163      if (!netHandle || netHandle.netId === 0) {
164        return false;
165      }
166      let netCapability = connection.getNetCapabilitiesSync(netHandle);
167      let cap = netCapability.networkCap || [];
168      if (cap.includes(connection.NetCap.NET_CAPABILITY_VALIDATED)) {
169        //connection.NetCap.NET_CAPABILITY_VALIDATED,该值代表网络是通的,能够发起HTTP和HTTPS的请求。
170        // 网络信息变化,网络可用
171        return true;
172      } else {
173        // 网络信息变化,网络不可用
174        return false;
175      }
176    } catch (e) {
177      let err = e as BusinessError;
178      logger.error('JudgeHasNet' + JSON.stringify(err));
179    }
180    return false;
181  }
182
183  /**
184   * 获取网络状态,查询手机卡注册网络的运营商名称、是否处于漫游状态、设备的网络注册状态等信息
185   */
186  getNetworkStatus() {
187    radio.getNetworkState((err: BusinessError, data: radio.NetworkState) => {
188      if (err) {
189        logger.error(`getNetworkState failed, callback: err->${JSON.stringify(err)}`);
190      }
191      // regState字段表示设备的网络注册状态
192      // (REG_STATE_POWER_OFF,值为3)蜂窝无线电已关闭,modem下电,无法和网侧进行通信
193      logger.info('Success getNetworkStatus:' + JSON.stringify(data));
194    });
195  }
196
197  /**
198   * 查询当前网络是3G/4G/5G
199   * SignalInformation.signalType表示蜂窝网络的类型
200   * 未知(值为0)
201   * 2G:GSM(值为1)、CDMA(值为2)
202   * 3G:WCDMA(值为3)、TDSCDMA(值为4)
203   * 4G:LTE(值为5)
204   * 5G:NR(值为6)
205   * @returns 指定SIM卡槽对应的注册网络信号强度信息列表
206   */
207  async getSignalType(): Promise<radio.SignalInformation[]> {
208    let slotId: number = await radio.getPrimarySlotId();
209    let data: radio.SignalInformation[] = radio.getSignalInformationSync(slotId);
210    // signalType代表网络类型NetworkType
211    let signalType = data[0].signalType;
212    logger.info('getSignalType:' + JSON.stringify(data));
213    return data;
214  }
215
216  /**
217   * 查询WLAN是否已使能,可以帮助用户快速了解自己是否可以使用Wi-Fi网络进行连接。
218   * 当Wi-Fi跟蜂窝同时存在时,有助于实现网络连接的无缝切换。
219   * @returns true:已使能, false:未使能
220   */
221  getWifiStatus(): boolean {
222    try {
223      let isWifiActive: boolean = wifiManager.isWifiActive();
224      return isWifiActive;
225    } catch (error) {
226      logger.error('failed:' + JSON.stringify(error));
227    }
228    return false;
229  }
230
231  /**
232   * 查询WLAN是否已连接是判断能否通过Wi-Fi 进行各种网络活动的直接方式。
233   * @returns true,已连接。false,未连接
234   */
235  getWifiIsConnected(): boolean {
236    try {
237      let ret = wifiManager.isConnected();
238      logger.info('isConnected:' + ret);
239      return ret;
240    } catch (error) {
241      logger.error('failed:' + JSON.stringify(error));
242    }
243    return false;
244  }
245
246  /**
247   * 获取当前连接Wi-Fi的信号强度
248   * 通过获取信号强度,用户可以初步判断当前网络是否能够满足其对速度的需求。
249   * 取值范围为[0, 4],取值越大表示信号越强
250   * @returns 信号强度,取值范围[0, 4],-1表示报错
251   */
252  async getSignalLevel(): Promise<number> {
253    try {
254      let wifiLinkedInfo: wifiManager.WifiLinkedInfo = await wifiManager.getLinkedInfo();
255      let rssi = wifiLinkedInfo.rssi;
256      let band = wifiLinkedInfo.band;
257      let level = wifiManager.getSignalLevel(rssi, band);
258      logger.info('level:' + JSON.stringify(level));
259      return level;
260    } catch (error) {
261      logger.error('failed:' + JSON.stringify(error));
262    }
263    return -1;
264  }
265
266  /**
267   * 监听网络状态
268   * @param netType  监听的网络类型(WI-FI、蜂窝数据等)
269   */
270  networkObserve(netType: connection.NetBearType) {
271    // TODO:根据网络类型,设置不同的网络监听,用于WI-FI和蜂窝网络切换时判断各自网络状态的变化。
272    let netConnection: connection.NetConnection = connection.createNetConnection({
273      netCapabilities: {
274        bearerTypes: [netType]
275      }
276    })
277    // 注册网络监听,注册成功后才能监听到对应类型的网络状态变化
278    netConnection.register((error: BusinessError) => {
279      let result = true;
280      if (error) {
281        logger.info('NetUtils', 'NetType :' + netType + ', network register failed: ' + JSON.stringify(error));
282        result = false;
283      }
284      logger.info('NetUtils', 'NetType :' + netType + ', network register succeed');
285      this.postEvent(NetworkEventName.NetObserverRegister, result, netType);
286    });
287    // 网络能力改变监听,当网络能力变化时,如网络从无网络到有网络、从4G切换到5G时,会触发该事件。
288    netConnection.on('netCapabilitiesChange', (data: connection.NetCapabilityInfo) => {
289      logger.info('NetUtils', 'NetType :' + netType + ', network netCapabilitiesChange: ' + JSON.stringify(data));
290      this.postEvent(NetworkEventName.NetCapabilitiesChange, data, netType);
291    })
292    // 网络可用监听,当网络可用时触发该事件。
293    netConnection.on('netAvailable', (data: connection.NetHandle) => {
294      logger.info('NetUtils',
295        'NetType :' + netType + ', network succeeded to get netAvailable: ' + JSON.stringify(data));
296      // 检查默认数据网络是否被激活,使用同步方式返回接口,如果被激活则返回true,否则返回false。
297      this.postEvent(NetworkEventName.NetAvailable, connection.hasDefaultNetSync(), netType);
298    });
299
300    // 订阅网络阻塞状态事件,当网络阻塞时,如网络性能下降、数据传输出现延迟等情况时,会触发该事件
301    netConnection.on('netBlockStatusChange', (data: connection.NetBlockStatusInfo) => {
302      logger.info('NetUtils', 'NetType :' + netType + ', network netBlockStatusChange ' + JSON.stringify(data));
303      this.postEvent(NetworkEventName.NetBlock, data, netType);
304    });
305    // 网络连接信息变化监听,当网络连接信息变化时,如从无网络到有网络、从Wi-Fi切换到蜂窝时,会触发该事件。
306    netConnection.on('netConnectionPropertiesChange', (data: connection.NetConnectionPropertyInfo) => {
307      logger.info('NetUtils',
308        'NetType :' + netType + ', network netConnectionPropertiesChange ' + JSON.stringify(data));
309      this.postEvent(NetworkEventName.NetConnectionPropertiesChange, data, netType);
310    });
311
312    // 订阅网络丢失事件,当网络严重中断或正常断开时触发该事件
313    // 网络丢失是指网络严重中断或正常断开事件,当断开Wi-Fi时,是属于正常断开网络连接,会触发netLost事件
314    netConnection.on('netLost', (data: connection.NetHandle) => {
315      this.postEvent(NetworkEventName.NetLost, true, netType);
316      logger.info('NetUtils', 'NetType :' + netType + ', Succeeded to get netLost: ' + JSON.stringify(data));
317    });
318
319    // 订阅网络不可用事件,当网络不可用时触发该事件
320    // 网络不可用是指网络不可用事件,当连接的网络不能使用时,会触发netUnavailable事件。
321    netConnection.on('netUnavailable', () => {
322      logger.info('NetUtils', 'NetType :' + netType + ', Succeeded to get unavailable net event');
323      this.postEvent(NetworkEventName.NetUnavailable, true, netType);
324    });
325
326    this.connectionMap.set(netType, netConnection);
327  }
328
329  /**
330   * WI-FI状态监听
331   */
332  wifiStateObserve() {
333    // 注册WLAN状态改变事件
334    // 0,未激活;1,已激活;2,激活中;3:去激活中
335    wifiManager.on('wifiStateChange', (result: number) => {
336      logger.info('NetUtils', 'wifiStateChange: ' + result);
337      this.postEvent(NetworkEventName.WifiStateChange, result);
338    });
339    // 注册WLAN连接状态改变事件
340    // 0,已断开;1,已连接
341    wifiManager.on('wifiConnectionChange', (result: number) => {
342      logger.info('NetUtils', 'wifiConnectionChange: ' + result);
343      this.postEvent(NetworkEventName.WifiConnectionChange, result);
344    });
345  }
346
347  /**
348   * 解析网络监听结果,用于打印日志
349   * @param data  网络监听结果
350   * @returns 解析后的结果数据
351   */
352  parseResult(data: emitter.EventData): string {
353    if (data.data) {
354      if (!data.data.eventName) {
355        logger.info('parseResult data.data.eventName is undefined.');
356        return '';
357      }
358    } else {
359      logger.info('parseResult data.data is undefined.');
360      return '';
361    }
362    let result = '';
363    let name: number = (data.data)!.eventName ?? -1;
364    switch (name) {
365      case NetworkEventName.NetObserverRegister.valueOf():
366        result = 'NetObserverRegister';
367        break;
368      case NetworkEventName.NetAvailable.valueOf():
369        result = 'NetAvailable';
370        break;
371      case NetworkEventName.NetBlock.valueOf():
372        result = 'NetBlock';
373        break;
374      case NetworkEventName.NetLost.valueOf():
375        result = 'NetLost';
376        break;
377      case NetworkEventName.NetCapabilitiesChange.valueOf():
378        result = 'NetCapabilitiesChange';
379        break;
380      case NetworkEventName.NetUnavailable.valueOf():
381        result = 'NetUnavailable';
382        break;
383      case NetworkEventName.NetConnectionPropertiesChange.valueOf():
384        result = 'NetConnectionPropertiesChange';
385        break;
386      case NetworkEventName.WifiStateChange.valueOf():
387        result = 'WifiStateChange';
388        break;
389      case NetworkEventName.WifiConnectionChange.valueOf():
390        result = 'WifiConnectionChange';
391        break;
392      case NetworkEventName.WeakNet.valueOf():
393        result = 'WeakNet';
394        break;
395      default:
396        result = name.toString();
397        break;
398    }
399
400    let netTemp: string = '';
401    let temp: number = data.data!.netType ?? -1;
402    if (temp === 1) {
403      netTemp = 'WIFI';
404    }
405    if (temp === 0) {
406      netTemp = 'CELLULAR';
407    }
408    if (temp === -1) {
409      netTemp = temp.toString();
410    }
411
412    result = result + '------' + (data.data!.status ?? -1) + '------' + netTemp;
413
414    return result;
415  }
416}
417
418export class NetEventData {
419  public eventName: NetworkEventName;
420  public status: NetworkData;
421  public netType: connection.NetBearType;
422
423  constructor(eventName: NetworkEventName, status: NetworkData, netType: connection.NetBearType) {
424    this.eventName = eventName;
425    this.status = status;
426    this.netType = netType;
427  }
428}