wifi局域网配网开发
- 准备工作
- 逻辑
- 优化
如题,项目软件需要配网(wifi),每次现场安装都需要使用鼠标键盘进行配网的操作。影响安装效率,在参考市面上的大多数类似设备后,决定添加通过wifi热点进行局域网配网的功能。
为实现该功能,需要做一些准备工作
准备工作
- 权限
① 配网的功能需要使用到定位和wifi权限。注意事项:不同的安卓版本需要的权限不同,博主是安卓14的版本,14-17应该差不多,安卓8等较低版本权限可能有所不同,可以问AI;定位权限只开放不启动就行
<!--网络基础权限--><uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/><uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/><uses-permission android:name="android.permission.INTERNET"/><!--WiFi扫描权限(Android10+)--><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/><uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES"android:usesPermissionFlags="neverForLocation"/>②开关wifi需要系统级的权限,要么联系厂家拿系统签名,然后打包。要么找厂家要相关的jar/aar包,通过该包调用相应的api。没有系统权限的app打包了也无法正常使用wifi相关的功能
逻辑
由于大部分代码都是AI(ds,gpt,claude都用了)写的,因此只说明大致流程。下面是大概的功能描述
Android IoT 设备设计的 WiFi 配网库,实现了:
- 零键鼠配网:通过 AP 热点 + Web 配网页面完成 WiFi 配置,无需键鼠/显示器
- AP 热点常驻:AP 热点永久开启,方便随时访问配网服务
- 双模式支持:WiFi 连接成功后自动尝试 AP+STA 双模式
- Captive Portal:手机连接热点后自动弹窗进入配网页面
- 状态监控:WiFi 断开自动恢复,AP 热点保持运行
获得权限后先判断设备是否已经连接wifi,是则无需开启热点相关的服务;否则通过开启局域网和热点服务,让用户通过手机等设备连接相应的wifi,然后找到wifi,输入密码。即可完成配网的操作
注意事项:配网的前端服务需要固定好ip和端口号,否则默认是动态的,如果不看日志就不知道ip和端口号是哪个了
优化
当前放置在项目中运行,暂时没有什么问题。实际遇到可以优化的就是关于wifi修改密码的问题,如果用户直接通过键鼠的方式强行修改过系统的wifi密码,并且是错误的,此时项目中的就失效了。系统输入的wifi密码权限如果没有系统签名的话会被拒绝
提示类似下图的信息,导致无法正常修改密码。该问题当前还在联系厂家
根本原因 :Android 10+ 限制应用只能修改自己创建的WiFi配置。用户在系统设置中输入错误密码后,配置由系统Settings创建,我们的app无权删除、修改或通过 connect() API 连接。
解决方案:使用 su 命令绕过权限限制,先忘记旧网络再连接。
/** * 使用 wpa_cli 命令连接WiFi(cmd wifi的后备方案) */privatestaticbooleanconnectWithWpaCli(Stringssid,Stringpassword){try{Processprocess=Runtime.getRuntime().exec("su");java.io.DataOutputStreamos=newjava.io.DataOutputStream(process.getOutputStream());// wpa_cli 命令序列os.writeBytes("wpa_cli add_network\n");// 等待add_network返回ID比较复杂,直接用一个固定的流程// 先remove所有匹配SSID的网络,再添加新的os.writeBytes("wpa_cli list_networks\n");if(password==null||password.isEmpty()){os.writeBytes("wpa_cli set_network 0 ssid '\""+ssid+"\"'\n");os.writeBytes("wpa_cli set_network 0 key_mgmt NONE\n");}else{os.writeBytes("wpa_cli set_network 0 ssid '\""+ssid+"\"'\n");os.writeBytes("wpa_cli set_network 0 psk '\""+password+"\"'\n");}os.writeBytes("wpa_cli enable_network 0\n");os.writeBytes("wpa_cli select_network 0\n");os.writeBytes("wpa_cli save_config\n");os.writeBytes("exit\n");os.flush();os.close();java.io.BufferedReaderreader=newjava.io.BufferedReader(newjava.io.InputStreamReader(process.getInputStream()));Stringline;while((line=reader.readLine())!=null){Log.i(TAG,"wpa_cli: "+line);}intresult=process.waitFor();Log.i(TAG,"wpa_cli 结果: "+result);returnresult==0;}catch(Exceptione){Log.e(TAG,"wpa_cli连接失败",e);returnfalse;}}