You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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权限并开启位置服务。

在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数据:

  1. 获取WifiManager实例:
val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
  1. 注册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数据:

  1. 创建列表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>
  1. 实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 22:53:15