Android 10+下智能设备APP如何实现WiFi列表自定义展示?
Android 10+ 实现自定义WiFi列表界面方案
针对智能设备配网场景下的自定义WiFi列表需求,Android 10(API 29)弃用WifiManager.startScan()后,可通过以下方案实现:
一、申请必要权限
权限要求随系统版本不同有所区别:
- Android 10-11(API 29-30):必须申请
ACCESS_FINE_LOCATION危险权限,且用户需手动开启系统位置服务,否则无法获取有效WiFi扫描结果。 - Android 12+(API 31+):
- 仅需扫描WiFi列表:申请
NEARBY_WIFI_DEVICES危险权限即可,无需位置服务,但此时获取到的SSID/BSSID会显示为<unknown ssid>/<unknown bssid>。 - 需要显示真实SSID/BSSID:仍需申请
ACCESS_FINE_LOCATION权限并开启位置服务。
- 仅需扫描WiFi列表:申请
在AndroidManifest.xml中声明权限:
<!-- Android 10-11 所需权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- Android 12+ 所需权限 --> <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" android:usesPermissionFlags="neverForLocation" /> <!-- 可选:如果需要连接WiFi,添加此权限 --> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
二、注册扫描结果回调获取WiFi列表
弃用主动扫描后,通过注册系统扫描回调来获取实时WiFi数据:
- 获取
WifiManager实例:
val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
- 注册
ScanResultsCallback监听扫描结果更新:
val scanCallback = object : WifiManager.ScanResultsCallback { override fun onScanResultsAvailable() { // 获取最新扫描结果 val scanResults = wifiManager.scanResults // 过滤并处理结果 val filteredWifiList = processScanResults(scanResults) // 更新自定义列表UI updateWifiListUI(filteredWifiList) } } // 注册回调(Android 10+支持) wifiManager.registerScanResultsCallback( context.mainExecutor, scanCallback )
三、过滤并处理扫描结果
原始扫描结果可能包含重复、隐藏网络或无效条目,需做过滤处理:
private fun processScanResults(scanResults: List<ScanResult>): List<WifiItem> { val wifiMap = mutableMapOf<String, WifiItem>() scanResults.forEach { result -> // 跳过隐藏网络(SSID为空) if (result.SSID.isBlank()) return@forEach // 按SSID去重,保留信号最强的条目 val existingItem = wifiMap[result.SSID] if (existingItem == null || result.level > existingItem.signalLevel) { // 判断加密类型 val securityType = when { result.capabilities.contains("WPA3") -> "WPA3" result.capabilities.contains("WPA2") -> "WPA2" result.capabilities.contains("WPA") -> "WPA" result.capabilities.contains("WEP") -> "WEP" else -> "开放" } // 转换信号强度(-100到-50对应0到4格) val signalLevel = WifiManager.calculateSignalLevel(result.level, 5) wifiMap[result.SSID] = WifiItem(result.SSID, securityType, signalLevel) } } return wifiMap.values.toList().sortedByDescending { it.signalLevel } } // 定义数据类存储WiFi信息 data class WifiItem(val ssid: String, val securityType: String, val signalLevel: Int)
四、实现自定义WiFi列表UI
用RecyclerView展示处理后的WiFi数据:
- 创建列表Item布局(示例):
<!-- item_wifi.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" android:orientation="horizontal" android:gravity="center_vertical"> <TextView android:id="@+id/tv_ssid" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:textSize="16sp"/> <TextView android:id="@+id/tv_security" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="12sp" android:textColor="@android:color/darker_gray"/> <!-- 信号强度图标,可根据signalLevel切换资源 --> <ImageView android:id="@+id/iv_signal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="16dp"/> </LinearLayout>
- 实现
RecyclerView.Adapter:
class WifiListAdapter(private val wifiList: List<WifiItem>) : RecyclerView.Adapter<WifiListAdapter.ViewHolder>() { inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val tvSsid: TextView = itemView.findViewById(R.id.tv_ssid) val tvSecurity: TextView = itemView.findViewById(R.id.tv_security) val ivSignal: ImageView = itemView.findViewById(R.id.iv_signal) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.item_wifi, parent, false) return ViewHolder(view) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val item = wifiList[position] holder.tvSsid.text = item.ssid holder.tvSecurity.text = item.securityType // 根据信号强度设置图标 val signalRes = when(item.signalLevel) { 0 -> R.drawable.ic_signal_0 1 -> R.drawable.ic_signal_1 2 -> R.drawable.ic_signal_2 3 -> R.drawable.ic_signal_3 else -> R.drawable.ic_signal_4 } holder.ivSignal.setImageResource(signalRes) } override fun getItemCount() = wifiList.size }
五、注意事项
- 系统会自动周期性扫描WiFi,无需主动触发扫描;若需立即更新,可尝试开启再关闭WiFi(不推荐,影响用户体验)。
- Android 12+中,若仅申请
NEARBY_WIFI_DEVICES权限,无法获取WiFi的SSID和BSSID具体值,仅能用于判断WiFi是否存在。 - 扫描结果可能受系统限制(如省电模式下扫描频率降低),需在UI上提示用户相关情况。
内容的提问来源于stack exchange,提问作者Vlad
相关产品推荐
相关产品推荐

