查看: 255|回复: 0

ASCF Wi-Fi 信息获取与连接 API 实战:权限、列表与踩坑

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
在鸿蒙元服务开发中,Wi-Fi 相关的操作场景很常见,比如读取当前连接的网络信息、扫描周边可用热点、或者主动连接指定 Wi-Fi。ASCF 提供了一套覆盖这些场景的 Wi-Fi API,整体上手不算复杂,但权限配置和异步回调模式有一些容易踩的坑。本文基于实际使用经验,梳理 Wi-Fi 信息获取与连接的 API 用法、权限申请方式,以及开发过程中需要注意的关键点。

## 权限配置:四个权限一个都不能少

ASCF Wi-Fi API 的权限体系比较繁琐,大部分接口除了 Wi-Fi 自身权限外,还要申请位置权限。原因是 Wi-Fi 列表和热点信息可以被用来做定位,系统因此将其归入位置权限管理。在 module.json5 中,通常需要声明以下四个权限:
  1. {
  2.   "requestPermissions": [
  3.     {
  4.       "name": "ohos.permission.GET_WIFI_INFO",
  5.       "reason": "用于获取Wi-Fi信息",
  6.       "usedScene": {
  7.         "abilities": ["EntryAbility"],
  8.         "when": "inuse"
  9.       }
  10.     },
  11.     {
  12.       "name": "ohos.permission.SET_WIFI_INFO",
  13.       "reason": "用于连接Wi-Fi",
  14.       "usedScene": {
  15.         "abilities": ["EntryAbility"],
  16.         "when": "inuse"
  17.       }
  18.     },
  19.     {
  20.       "name": "ohos.permission.LOCATION",
  21.       "reason": "用于获取Wi-Fi位置信息",
  22.       "usedScene": {
  23.         "abilities": ["EntryAbility"],
  24.         "when": "inuse"
  25.       }
  26.     },
  27.     {
  28.       "name": "ohos.permission.APPROXIMATELY_LOCATION",
  29.       "reason": "用于获取Wi-Fi位置信息",
  30.       "usedScene": {
  31.         "abilities": ["EntryAbility"],
  32.         "when": "inuse"
  33.       }
  34.     }
  35.   ]
  36. }
复制代码

除了静态声明,运行时还需要申请 scope.userLocation 授权。只有在授权成功后才能正常调用 Wi-Fi API。这一点很容易被忽略,尤其是当业务逻辑本身不涉及地图或定位时,开发者可能会觉得位置权限多余,但实际不申请就会直接调用失败。
  1. has.authorize({
  2.   scope: 'scope.userLocation',
  3.   success: () => {
  4.     console.info('位置授权成功');
  5.     // 现在可以调用 Wi-Fi API 了
  6.   },
  7.   fail: (err) => {
  8.     console.error('位置授权失败:', err);
  9.   }
  10. });
复制代码

## 获取当前连接的 Wi-Fi 信息

授权通过后,通过 has.getConnectedWifi 可以拿到当前连接的热点信息,包括 SSID、BSSID、信号强度、频段和是否加密等。
  1. has.authorize({
  2.   scope: 'scope.userLocation',
  3.   success: () => {
  4.     has.getConnectedWifi({
  5.       success: (res) => {
  6.         const wifi = res.wifi;
  7.         console.info('SSID:', wifi.SSID);
  8.         console.info('BSSID:', wifi.BSSID);
  9.         console.info('信号强度:', wifi.signalStrength);
  10.         console.info('频段:', wifi.frequency, 'MHz');
  11.         console.info('是否安全:', wifi.secure);
  12.       },
  13.       fail: (err) => {
  14.         console.error('获取失败:', err);
  15.       }
  16.     });
  17.   }
  18. });
复制代码

如果业务场景只需要展示当前 Wi-Fi 的名称,不需要信号强度等信息,可以将 partialInfo 参数设为 true,这样只会返回 SSID 和 BSSID,减少不必要的数据传输,同时也能降低部分权限要求。
  1. has.getConnectedWifi({
  2.   partialInfo: true,
  3.   success: (res) => {
  4.     console.info('SSID:', res.wifi.SSID);
  5.     // 其他字段不会返回
  6.   }
  7. });
复制代码

## 获取 Wi-Fi 列表:先注册监听,再发起请求

扫描周围 Wi-Fi 列表的接口设计比较特殊:has.getWifiList 的 success 回调只代表列表请求已经发出,真正的 Wi-Fi 列表数据需要通过 has.onGetWifiList 监听返回。也就是说,必须先注册监听器,再调用 getWifiList,否则会收不到列表数据。
  1. has.authorize({
  2.   scope: 'scope.userLocation',
  3.   success: () => {
  4.     // 先注册监听,再请求列表
  5.     has.onGetWifiList(function (res) {
  6.       const wifiList = res.wifiList;
  7.       console.info('发现', wifiList.length, '个 Wi-Fi');
  8.       wifiList.forEach(function (wifi) {
  9.         console.info(wifi.SSID, wifi.signalStrength);
  10.       });
  11.     });
  12.     // 请求获取列表
  13.     has.getWifiList({
  14.       success: () => {
  15.         console.info('Wi-Fi 列表请求成功');
  16.       },
  17.       fail: (err) => {
  18.         console.error('获取列表失败:', err);
  19.       }
  20.     });
  21.   }
  22. });
复制代码

这种“监听回调 + 请求触发”的模式,在 AS CF 的异步接口中比较常见,和普通的“请求-响应”模型不太一样。建议在页面加载时注册监听,在页面销毁时记得移除,避免内存泄漏。

## 连接指定 Wi-Fi

has.connectWifi 用于主动连接某个热点。需要注意的是,password 参数是必填的,即使是开放网络也要传空字符串,不能省略。
  1. has.authorize({
  2.   scope: 'scope.userLocation',
  3.   success: () => {
  4.     has.connectWifi({
  5.       SSID: 'MyWiFi',
  6.       password: 'mypassword123',
  7.       success: () => {
  8.         console.info('Wi-Fi 连接成功');
  9.         has.showToast({ title: '连接成功' });
  10.       },
  11.       fail: (err) => {
  12.         console.error('连接失败:', err);
  13.       }
  14.     });
  15.   }
  16. });
复制代码

connectWifi 还有一个 manual 参数。如果设为 true,API 不会直接发起连接,而是跳转到系统 Wi-Fi 设置页面,让用户手动选择网络并输入密码。这种模式适合不确定密码、或者需要用户主动确认的场景,体验上更像是“引导用户去设置”,而不是应用内直接控制。

## 监听 Wi-Fi 连接状态

如果需要在连接状态变化时收到通知,可以使用 onWifiConnected 注册监听。注意,移除监听时要传入同一个函数对象,否则无法移除。用匿名函数注册的话,后续就没法单独解除监听,所以建议把回调函数保存成变量。
  1. // 定义回调函数(需要保存引用才能移除)
  2. const onConnected = function (res) {
  3.   const wifi = res.wifi;
  4.   console.info('Wi-Fi 已连接:', wifi.SSID);
  5. };
  6. // 注册监听
  7. has.onWifiConnected(onConnected);
  8. // 移除监听(需要传同一个函数对象)
  9. has.offWifiConnected(onConnected);
  10. // 或者移除所有监听
  11. has.offWifiConnected();
复制代码

另外,ASCF 还提供了 onWifiConnectedWithPartialInfo 接口,这个 API 从 1.0.14 版本才开始支持。它和 onWifiConnected 的区别在于只返回部分 Wi-Fi 信息,适用于只需要知道当前连接了哪个热点的场景,权限要求也更低。在不需要完整信息时,优先使用这个接口会更轻量。

## 实际开发中容易踩的坑

结合上面的 API 使用,有几个问题在开发时尤其容易遇到:

1. 必须先授权再操作。大部分 Wi-Fi API 依赖 scope.userLocation 授权,不授权直接调用会失败。很多开发者以为只有获取位置才需要位置权限,结果在 Wi-Fi 接口上栽了跟头。

2. getWifiList 的结果在监听回调里返回。getWifiList 的 success 回调只表示请求发出去了,真正的数据要等 onGetWifiList 触发。顺序必须是先注册监听,再调用 getWifiList。

3. 移除监听要传同一个函数对象。如果注册时用的是匿名函数,就无法单独移除,只能调用 offWifiConnected 不带参数来移除所有监听。这会带来潜在的风险,建议始终用变量保存回调引用。

4. signalStrength 不是 dBm。返回的信号强度是一个 0 到 1 之间的浮点数,1 表示最强,0 表示最弱。如果要显示信号图标,可以按 0.25 一档来划分等级,而不是直接用 dBm 去套。

5. connectWifi 的密码必填。即使连接的是开放网络,password 参数也必须传,传空字符串 '' 即可。

## API 方法速查

- has.getConnectedWifi:获取当前连接的 Wi-Fi 信息,支持 partialInfo 精简返回。
- has.getWifiList + has.onGetWifiList:获取并监听 Wi-Fi 列表,先注册监听再请求。
- has.connectWifi:连接指定 Wi-Fi,支持 manual 跳转系统设置。
- has.onWifiConnected / has.offWifiConnected:监听/移除 Wi-Fi 连接状态。
- has.onWifiConnectedWithPartialInfo:轻量级连接状态监听,仅返回部分信息,1.0.14 起可用。

整体来看,ASCF Wi-Fi API 的权限要求确实偏多,module.json5 里需要声明四个权限,运行时还要再申请位置授权。但接口本身的设计逻辑并不复杂,只要理解了“先注册监听再请求”这个模式,再注意权限和回调用引用的问题,日常的 Wi-Fi 获取与连接需求基本都能顺利实现。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-9-2 10:30 , Processed in 0.024844 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部