UniApp X 安卓App的Wi-Fi 状态监听器实战指南
前言
在移动应用开发中,实时监听 Wi-Fi 连接状态变化是一个常见需求。本文将详细介绍如何使用 UniApp X (UTS) 开发一个健壮的 Wi-Fi 状态监听器,帮助开发者快速实现网络状态检测功能。
功能特性
- 监听 Wi-Fi 开关状态变化(开启/关闭)
- 监听网络连接状态变化(连接/断开)
- 自动获取当前连接的 Wi-Fi 名称(SSID)
- 单例模式设计,避免重复注册监听器
- 自动释放资源,防止内存泄漏
权限配置
在使用 Wi-Fi 功能之前,需要在 AndroidManifest.xml 中配置相应权限:
xml
<!-- Wi-Fi 权限 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<!-- 获取 SSID 所需的位置权限 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
注意:在 Android 8.0 及以上版本,获取 Wi-Fi SSID 名称需要位置权限。即使应用本身不需要位置功能,也必须申请此权限才能获取到真实的 SSID。
核心代码实现
必须先申请android.permission.ACCESS_FINE_LOCATION 权限 再进行下一步 这里就不写了
typescript
// wifiListener.uts
import Context from "android.content.Context";
import Intent from "android.content.Intent";
import IntentFilter from "android.content.IntentFilter";
import BroadcastReceiver from "android.content.BroadcastReceiver";
import WifiManager from "android.net.wifi.WifiManager";
import WifiInfo from "android.net.wifi.WifiInfo";
import NetworkInfo from "android.net.NetworkInfo";
type WifiStateData = {
isConnected : boolean;
ssid ?: string;
}
// 获取SSID 需要配置权限 android.permission.ACCESS_FINE_LOCATION 即app的位置权限开启 才能获取到 必须先申请权限
class WifiBroadcastReceiver extends BroadcastReceiver {
private cb : (data : WifiStateData) => void;
constructor(callback : (data : WifiStateData) => void) {
super();
this.cb = callback;
}
override onReceive(context : Context, intent : Intent) {
const action = intent.getAction();
if (action === WifiManager.WIFI_STATE_CHANGED_ACTION) {
const state = intent.getIntExtra(
WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN
);
if (state === WifiManager.WIFI_STATE_ENABLED) {
console.log('[Wi-Fi] 已开启');
const ssid = getCurrentSSID();
const hasSsid = ssid != null;
if (hasSsid) {
this.cb({ isConnected: true, ssid: ssid });
} else {
this.cb({ isConnected: false });
}
} else if (state === WifiManager.WIFI_STATE_DISABLED) {
console.log('[Wi-Fi] 已关闭');
this.cb({ isConnected: false });
}
}
else if (action === WifiManager.NETWORK_STATE_CHANGED_ACTION) {
const networkInfo = intent.getParcelableExtra<NetworkInfo>(
WifiManager.EXTRA_NETWORK_INFO
);
if (networkInfo != null && networkInfo.isConnected()) {
const wifiInfo = intent.getParcelableExtra<WifiInfo>(
WifiManager.EXTRA_WIFI_INFO
);
let ssid : string | null = null;
if (wifiInfo != null) {
const raw = wifiInfo.getSSID();
if (raw != null && raw !== '<unknown ssid>') {
ssid = raw.replace(/^"|"$/g, '');
}
}
if (ssid == null) {
ssid = getCurrentSSID();
}
console.log('[Wi-Fi] 已连接:', ssid != null ? ssid : '未知网络');
if (ssid != null) {
this.cb({ isConnected: true, ssid: ssid });
} else {
this.cb({ isConnected: true });
}
} else {
console.log('[Wi-Fi] 已断开');
this.cb({ isConnected: false });
}
}
}
}
/**
* Wi-Fi 状态监听器
* 使用方法:
* const listener = WifiListener.getInstance();
* listener.startListening((state) => { console.log(state); });
* // 页面销毁时:listener.stopListening();
*/
class WifiListener {
private static instance : WifiListener | null = null;
private receiver : BroadcastReceiver | null = null;
private context : Context | null = null;
private constructor() { }
public static getInstance() : WifiListener {
if (WifiListener.instance == null) {
WifiListener.instance = new WifiListener();
}
return WifiListener.instance;
}
private getContext() : Context | null {
if (this.context == null) {
this.context = UTSAndroid.getAppContext();
}
return this.context;
}
/**
* 开始监听 Wi-Fi 状态变化
* @param callback 回调函数,参数为 { isConnected: boolean, ssid?: string }
*/
public startListening(callback : (data : WifiStateData) => void) : void {
const context = this.getContext();
if (context == null) {
console.error('无法获取 Context');
return;
}
this.stopListening();
this.receiver = new WifiBroadcastReceiver(callback);
const filter = new IntentFilter();
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
try {
context.registerReceiver(this.receiver, filter);
console.log('[Wi-Fi] 监听器已注册');
} catch (e) {
console.error('[Wi-Fi] 注册失败:', e);
}
}
/**
* 停止监听,取消注册广播接收器
*/
public stopListening() : void {
if (this.receiver != null) {
const context = this.getContext();
if (context != null) {
try {
context.unregisterReceiver(this.receiver);
console.log('[Wi-Fi] 监听器已取消注册');
} catch (e) {
}
}
this.receiver = null;
}
}
}
function getCurrentSSID() : string | null {
const context = UTSAndroid.getAppContext();
if (context == null) return null;
const wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager;
if (wifiManager == null) return null;
const wifiInfo = wifiManager.getConnectionInfo();
if (wifiInfo == null) return null;
if (wifiInfo.getNetworkId() === -1) return null;
let ssid = wifiInfo.getSSID();
if (ssid != null && ssid !== '<unknown ssid>') {
ssid = ssid.replace(/^"|"$/g, '');
return ssid;
}
return null;
}
export { WifiListener, WifiStateData };
使用示例
在页面中使用
vue
<template>
<view>
<view>Wi-Fi 状态: {{ isConnected ? '已连接' : '未连接' }}</view>
<view v-if="ssid">网络名称: {{ ssid }}</view>
</view>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { WifiListener } from '@/utils/wifiHelper.uts';
const isConnected = ref(false);
const ssid = ref('');
const wifiListener = WifiListener.getInstance();
onMounted(() => {
wifiListener.startListening((state) => {
isConnected.value = state.isConnected;
ssid.value = state.ssid || '';
});
});
onUnmounted(() => {
wifiListener.stopListening();
});
</script>
技术要点解析
1. 为什么需要继承 BroadcastReceiver
Android 的 Wi-Fi 状态变化通过广播机制传递。BroadcastReceiver 是 Android 四大组件之一,用于接收系统广播。要监听 Wi-Fi 状态,必须:
- 创建
BroadcastReceiver的子类 - 重写
onReceive方法处理广播 - 在
AndroidManifest.xml或代码中注册接收器
2. 为什么要使用单例模式
typescript
private static instance: WifiListener | null = null;
public static getInstance(): WifiListener {
if (WifiListener.instance == null) {
WifiListener.instance = new WifiListener();
}
return WifiListener.instance;
}
- 避免重复创建监听器实例
- 确保全局只有一个广播接收器
- 防止多次注册导致的资源浪费
3. SSID 获取的注意事项
typescript
function getCurrentSSID(): string | null {
const wifiInfo = wifiManager.getConnectionInfo();
if (wifiInfo.getNetworkId() === -1) return null;
let ssid = wifiInfo.getSSID();
if (ssid != null && ssid !== '<unknown ssid>') {
ssid = ssid.replace(/^"|"$/g, '');
return ssid;
}
return null;
}
- SSID 返回值可能包含引号,需要去除
<unknown ssid>表示无法获取真实的 SSIDgetNetworkId() === -1表示未连接到任何网络
常见问题
Q: 为什么 SSID 返回 ""?
A: 这是 Android 的安全机制。在 Android 8.0 及以上版本,第三方应用获取 SSID 需要满足以下条件:
- 位置权限已授予
- 定位服务已开启
- 应用具有
ACCESS_FINE_LOCATION权限
Q: 如何处理权限申请?
参考 https://blog.csdn.net/a3212768093/article/details/161656845?spm=1001.2014.3001.5501
总结
本文详细介绍了使用 UniApp X 的 UTS 开发 Android 原生 Wi-Fi 监听器的方法。通过封装单例模式的 WifiListener 类,开发者可以方便地在应用任何页面监听 Wi-Fi 状态变化,无需关心广播接收器的注册和注销细节。
关键技术点:
- 使用
BroadcastReceiver接收系统广播 - 单例模式确保全局唯一监听器
- 正确处理权限和边界情况
- 记得在页面销毁时停止监听