发布时间:2026/7/20 5:09:23
HarmonyOS技术精讲-Connectivity Kit:Wi-Fi扫描与连接实战 开篇一个常见的Wi-Fi开发误区很多人在HarmonyOS NEXT里第一次接触Wi-Fi扫描时会直接按照官方示例写代码然后发现扫描结果出来了但连接总是失败。更头疼的是失败后的错误回调描述不够详细导致调试成本很高。这个问题在HarmonyOS开发里比较常见。Connectivity Kit 的Wi-Fi模块设计思路和Android有差异但更贴近系统底层状态机。如果不对API的生命周期和状态同步做处理很容易出现“扫描正常连接异常”的情况。这篇实战文章会从权限声明开始逐步实现一个完整的Wi-Fi扫描与连接功能。重点是wifiManager的获取、startScan和onScanStateChange的配合、connectToNetwork的正确调用方式以及扫描列表的UI渲染。Connectivity Kit 解决什么问题Connectivity Kit短距通信服务是HarmonyOS提供的无线连接能力集合。其中的Wi-Fi模块主要负责扫描周围可用的Wi-Fi热点建立或断开Wi-Fi连接监听Wi-Fi状态变化连接、断开、信号强度变化适合场景场景说明智能家居配网手机扫描局域网设备热点完成配网办公设备联网设备需要连接到企业Wi-Fi网络诊断工具扫描周边AP分析信道占用和信号覆盖不适合场景后台长期扫描系统对高频Wi-Fi扫描有节流机制不建议在后台持续调用。隐藏网络扫描API未直接暴露被动监听隐藏SSID的能力需要用户主动输入SSID。和“应用内发Intent跳转系统设置”的方式相比直接使用Connectivity Kit API的优点是用户可以完全在应用内完成操作不需要跳转到系统页面体验更流畅。环境说明DevEco Studio 版本DevEco Studio 6.1.0 及以上 HarmonyOS SDK 版本HarmonyOS 6.1.0(23) 及以上 目标设备手机核心实现1. 权限声明Wi-Fi扫描和连接需要两个敏感权限ohos.permission.GET_WIFI_INFO和ohos.permission.SET_WIFI_INFO。前者用于读取Wi-Fi状态后者用于连接Wi-Fi。在entry/src/main/module.json5中添加{module:{requestPermissions:[{name:ohos.permission.GET_WIFI_INFO,reason:用于获取Wi-Fi状态和扫描结果,usedScene:{abilities:[EntryAbility]}},{name:ohos.permission.SET_WIFI_INFO,reason:用于连接指定的Wi-Fi网络,usedScene:{abilities:[EntryAbility]}}]}}注意在HarmonyOS NEXT上权限声明是静态的但运行时仍然需要动态请求部分权限在弹窗后自动授予这里两个权限都属于“用户授权”类型。2. 获取wifiManager对象wifiManager是 Wi-Fi 模块的入口对象。不能直接new必须通过connect接口获取。import{wifiManager}fromkit.ConnectivityKit;import{common}fromkit.AbilityKit;// 获取wifiManager对象functiongetWifiManager(context:common.Context):wifiManager.WifiDevice{// 这里传入的context必须是UIAbility的context不能是页面组件的contextreturnwifiManager.getWifiDevice(context);}官方文档没有强调context的类型限制。如果传入的是this.getUIContext()中获取的组件context会导致wifiManager.getWifiDevice返回undefined。3. 扫描与监听扫描调用startScan但结果不是直接返回的需要通过onScanStateChange监听扫描完成事件。// 发起扫描functionstartWifiScan(wifi:wifiManager.WifiDevice):void{// startScan没有返回值扫描结果通过回调获取wifi.startScan();}// 监听扫描状态变化functiononScanStateChange(wifi:wifiManager.WifiDevice,callback:(state:boolean)void):void{wifi.on(scanStateChange,(state:boolean){// state为true表示扫描成功false表示扫描失败或超时callback(state);});}// 获取扫描结果functiongetScanResults(wifi:wifiManager.WifiDevice):ArraywifiManager.WifiScanInfo{// 必须在扫描完成后调用否则返回空数组returnwifi.getScanInfoResults();}注意onScanStateChange回调是一次性的吗不是。它会在每次扫描完成时触发。如果多次调用startScan回调会被多次触发。建议在页面aboutToDisappear时调用wifi.off(scanStateChange)取消监听。4. 构建Wi-Fi配置并连接连接Wi-Fi需要构建一个WifiDeviceConfig对象然后调用connectToNetwork。import{wifiManager}fromkit.ConnectivityKit;functionconnectToWifi(wifi:wifiManager.WifiDevice,ssid:string,preSharedKey:string):void{// 构建Wi-Fi配置letconfig:wifiManager.WifiDeviceConfig{ssid:ssid,preSharedKey:preSharedKey,securityType:wifiManager.SecurityType.WPA2_PSK// 根据实际情况选择};// 调用连接方法wifi.connectToNetwork(config,(error,data){if(error){console.error(连接失败:${JSON.stringify(error)});return;}console.info(连接成功netId:${data});});}安全类型枚举值枚举对应加密方式WPA2_PSKWPA2个人网WPA3_SAEWPA3个人网OPEN开放网络WEPWEP加密不推荐如果不知道目的AP的加密方式可以先扫描从WifiScanInfo的capabilities字段中提取。基本做法是解析capabilities字符串匹配WPA、WPA2、WPA3等关键字。5. 完整页面实现下面是一个完整的Index.ets页面组件包含扫描列表展示和连接按钮交互。import{wifiManager}fromkit.ConnectivityKit;import{common}fromkit.AbilityKit;import{promptAction}fromkit.ArkUI;EntryComponentstruct Index{StatescanResults:ArraywifiManager.WifiScanInfo[];StateselectedSsid:string;Statepassword:string;StateisScanning:booleanfalse;privatewifi:wifiManager.WifiDevice|undefinedundefined;aboutToAppear():void{// 在UIAbility中使用this.context获取context// 注意页面组件的context和UIAbility的context不同这里假设PageAbility中已处理好// 实际项目中建议将wifiManager对象的获取放在UIAbility中通过全局状态管理letcontextgetContext(this)ascommon.BaseContext;this.wifiwifiManager.getWifiDevice(context);}// 执行扫描doScan():void{if(!this.wifi){promptAction.showToast({message:Wi-Fi管理器获取失败});return;}this.isScanningtrue;// 先清除上一次的扫描结果this.scanResults[];// 注册扫描状态监听this.wifi.on(scanStateChange,(state:boolean){this.isScanningfalse;if(state){this.scanResultsthis.wifi!.getScanInfoResults();promptAction.showToast({message:扫描完成发现${this.scanResults.length}个网络});}else{promptAction.showToast({message:扫描失败});}});// 发起扫描this.wifi.startScan();}// 连接到选中的网络connect():void{if(!this.wifi){promptAction.showToast({message:Wi-Fi管理器获取失败});return;}if(!this.selectedSsid){promptAction.showToast({message:请先选择网络});return;}// 构建配置安全类型暂时固定为WPA2实际可根据capabilities解析letconfig:wifiManager.WifiDeviceConfig{ssid:this.selectedSsid,preSharedKey:this.password,securityType:wifiManager.SecurityType.WPA2_PSK};this.wifi.connectToNetwork(config,(error,data){if(error){promptAction.showToast({message:连接失败:${error.message}});return;}promptAction.showToast({message:连接成功netId:${data}});});}build(){Column(){// 操作按钮区域Row(){Button(扫描Wi-Fi).onClick(()this.doScan()).width(45%)Button(连接).onClick(()this.connect()).width(45%)}.padding(10).width(100%).justifyContent(FlexAlign.SpaceBetween)// 扫描结果列表List(){ForEach(this.scanResults,(item:wifiManager.WifiScanInfo,index:number){ListItem(){Row(){Column(){Text(item.ssid).fontSize(16).fontWeight(FontWeight.Bold)Text(信号强度:${item.rssi}dBm).fontSize(12).fontColor(Color.Gray)}.alignItems(HorizontalAlign.Start).layoutWeight(1)if(this.selectedSsiditem.ssid){Text(已选中).fontSize(14).fontColor(Color.Green)}}.padding(10).width(100%).onClick((){this.selectedSsiditem.ssid;})}.divider({strokeWidth:1,color:#e0e0e0})})}.width(100%).layoutWeight(1)// 密码输入区域if(this.selectedSsid){Row(){Text(密码:)TextInput({placeholder:输入Wi-Fi密码}).onChange((value:string){this.passwordvalue;})}.padding(10).width(100%)}}.width(100%).height(100%)}}这段代码的核心逻辑aboutToAppear中初始化wifiManager对象。doScan方法先清除旧结果注册监听再调用startScan。connect方法使用选中网络的SSID和用户输入密码构建配置调用connectToNetwork。列表项onClick选中一个网络选中后显示密码输入框。注意事项生命周期问题页面销毁时必须取消监听。可以在aboutToDisappear中调用this.wifi.off(scanStateChange)否则下次进入页面会重复注册导致多次回调。状态同步扫描是异步的扫描完成前获取扫描结果会返回空数组。所以用isScanning状态控制UI反馈。UI刷新scanResults是State变量扫描完成后赋值会自动触发列表刷新。踩坑记录坑1onScanStateChange不回调现象调用startScan后onScanStateChange回调完全不触发。原因HarmonyOS对Wi-Fi扫描有节流逻辑。如果在短时间内约30秒连续调用startScan后一次调用会被系统忽略且不会触发任何回调。这其实是系统层面的频率限制官方文档没有明确说明。解决方案在每次扫描前判断距离上次扫描的时间间隔。如果小于30秒提示用户稍后再试或者使用计时器控制扫描频率。实测稳定间隔是40秒以上。坑2connectToNetwork回调顺序不稳定现象调用connectToNetwork后回调被立刻触发但实际连接还没完成比如还没出现Wi-Fi图标。特别是网络密码错误时回调依然返回成功。原因connectToNetwork的异步回调只是表示“连接指令已下发”并不代表“连接已成功建立”。真正判断连接是否成功需要监听wifiManager.on(connectionChange)事件。官方示例里直接用回调判断成功是一个常见的误导这个设计本身有点反直觉。解决方案// 连接成功后等待连接状态变化wifi.on(connectionChange,(state:wifiManager.ConnectionState){if(statewifiManager.ConnectionState.CONNECTED){console.info(Wi-Fi连接成功);// 此时可以获取当前连接信息}elseif(statewifiManager.ConnectionState.DISCONNECTED){console.info(Wi-Fi断开);// 可能是密码错误导致主动断开}});最佳实践使用单例管理wifiManager对象不要在每次操作前都调用getWifiDevice。如果页面销毁后重新创建会导致旧监听失效。推荐在UIAbility中初始化通过AppStorage或全局变量传递给页面。利用秒级Listen频率降低回调漏接概率on(scanStateChange)在扫描完成时触发一次但如果扫描开始后页面立即跳转可能错过回调。可以在aboutToAppear中注册页面内确保监听生命周期与页面一致不跨页面传递。扫描结果列表展示前清理上一次结果getScanInfoResults返回的是全量缓存结果包括上一次扫描的数据。如果不清理列表会显示过时的Wi-Fi。每次扫描前将scanResults置空等待回调后再赋值。FAQQ1为什么真机上能扫描到网络模拟器上扫描不到A模拟器对Wi-Fi硬件的模拟不完整getScanInfoResults在模拟器上始终返回空数组。这是预期行为Wi-Fi相关功能建议使用真机调试。Q2密码输入正确却连接失败错误信息是“INVALID_PARAM”A检查WifiDeviceConfig中的securityType是否和实际AP匹配。最常见的是扫描到的网络是开放网络OPEN但代码里写了WPA2_PSK。建议根据WifiScanInfo.capabilities动态解析安全类型。Q3应用退出后Wi-Fi连接会断开吗A调用connectToNetwork后Wi-Fi连接是由系统管理的应用退出不会自动断开。如果需要主动断开可以调用wifi.disconnect方法。

相关新闻

2026/7/19 3:31:25

安全可靠的母排冲剪机服务商

在电气设备制造、母线槽生产等行业中,母排冲剪机的重要性不言而喻。它直接影响着生产效率、产品质量以及企业的成本控制。然而,市场上母排冲剪机服务商众多,质量参差不齐,如何选择一家安全可靠的服务商成为了众多企业面临的难题。…

2026/7/19 3:31:25

基于Spark的在线广告推荐系统任务书

一、项目概述 随着互联网流量生态的持续迭代,在线广告已成为互联网平台商业化运营的核心支撑,涵盖信息流广告、搜索广告、弹窗广告、短视频植入广告等多种形式。海量用户每日产生的广告点击、浏览、停留、跳过、转化、收藏等行为数据呈指数级增长&#x…

2026/7/19 3:26:25

Sqribble:面向结构化文档的轻量级操作系统

1. 项目概述:当模板不再是“套壳”,而是一套可执行的文档操作系统你有没有过这种经历:手头有一篇写得不错的行业分析,想快速做成一份体面的PDF报告发给客户;或者刚录完一期播客,想把文字稿整理成带封面、目…

2026/7/20 0:18:52

互联网大厂常见Java面试题及答案汇总(2026持续更新)

金九银十即将来袭,又是一个跳槽的好季节,准备跳槽的同学都摩拳擦掌准备大面好几场,今天为大家准备了互联网面试必备的 1 到 5 年 Java 面试者都需要掌握的面试题,分别 JVM,并发编程,MySQL,Tomca…

2026/7/20 0:13:52

python数据可视化技巧的100个练习 -- 31. 类别数据的点图

重要性★★★☆☆ 难度★★☆☆☆ 你是一家零售公司的数据分析师。你的经理要求你可视化最近产品发布的客户满意度评级分布。评级是分类的,范围从“非常不满意”到“非常满意”。创建一个点图以显示每个评级类别的频率。使用 Python 进行数据处理和可视化。在代码中生成输入…

2026/7/20 0:13:52

智能体走进物理世界,千里科技携舱驾协同成果亮相WAIC 2026

在2026世界人工智能大会(WAIC 2026)举办期间,千里科技董事长、阶跃星辰董事长印奇作为特邀嘉宾出席大会开幕式并在大会主论坛(上午场)发表主题演讲《当智能体进入物理世界》。在印奇看来,"智能体"…

2026/7/20 0:13:52

ngx_output_chain_get_buf

1 定义 ngx_output_chain_get_buf 函数 定义在 src/core/ngx_output_chain.cstatic ngx_int_t ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize) {size_t size;ngx_buf_t *b, *in;ngx_uint_t recycled;in ctx->in->buf;size ctx->buf…

2026/7/19 0:00:15

Unity与Python本地通信:基于Flask的跨语言数据交换实战

1. 项目概述:为什么我们需要一个本地通信服务器?在游戏开发、数字孪生、仿真训练等众多领域,Unity作为强大的实时3D内容创作平台,其核心逻辑通常由C#驱动。然而,当我们需要进行复杂的数据分析、机器学习推理、科学计算…

2026/7/20 0:03:51

基于大数据爬虫+Hadoop+Spark的茶叶销售数据分析与可视化系统开题报告

一、课题研究背景与意义 茶叶作为我国特色农产品与核心经济作物,线上电商销售规模持续逐年扩增,各大电商平台、社交交易渠道积累了海量茶叶商品数据、交易订单数据、用户消费行为与评价数据。传统茶叶销售行业多采用小型数据库存储数据、人工统计分析的运…

2026/7/20 0:03:51

STM32H7 QSPI Flash下载算法制作指南

1. STM32H7 QSPI Flash下载算法制作概述在STM32H7系列微控制器的开发过程中,外部QSPI Flash存储器常被用于扩展存储空间。然而,MDK开发环境默认并不支持所有型号的QSPI Flash编程,这就需要我们自行制作下载算法。本文将详细介绍如何为STM32H7…

2026/7/20 0:03:51

深入解析TI PRU-ICSS:硬实时子系统架构与工业应用实践

1. 项目概述:深入理解PRU-ICSS的架构价值在嵌入式系统,尤其是工业自动化、电机驱动和实时网络通信领域,我们常常会遇到一个核心矛盾:主处理器(如Arm Cortex-A系列)需要处理复杂的操作系统、网络协议栈和用户…

2026/7/19 16:59:11

3个高效策略:快速掌握Axure中文界面配置

3个高效策略:快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…