如何解决ConnectivityManager连接SAE加密隐藏SSID超时并稳定连接?
问题描述
使用ConnectivityManager连接SAE加密的隐藏SSID时出现超时,无法成功建立连接;但将该SSID设置为非隐藏状态时,连接流程完全正常。
现有代码实现
连接函数
@RequiresApi(Build.VERSION_CODES.R) fun connectSae(ssid: String, password: String) { val suggestion = WifiNetworkSpecifier.Builder().setSsid(ssid).setWpa3Passphrase(password) .setIsHiddenSsid(if (hide_ssid.equals(true)) true else false).build() val networkRequest = NetworkRequest.Builder().addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .setNetworkSpecifier(suggestion).build() // mCm?.registerNetworkCallback(networkRequest, mNetworkCallback) mCm?.requestNetwork(networkRequest, mNetworkCallback) }
Intent参数处理
if (intent.getBooleanExtra("hide_ssid", false)) { // am start -n com.example.wifiConnect/.MainActivity -e ssid SH-AP-006_5G -e passwd 12345678 --ez hide_ssid true -e type SAE hide_ssid = intent.getBooleanExtra("hide_ssid", false) Log.d(TAG, "intent hide_ssid $hide_ssid") } if (intent.hasExtra("type")) { type = intent.getStringExtra("type").toString() Log.d(TAG, "intent type $type") }
全局变量
companion object { const val TAG = "MainActivity" @SuppressLint("StaticFieldLeak") lateinit var mContext: Context lateinit var mWifiManager: WifiManager var mConfig: WifiConfiguration? = null lateinit var mCm: ConnectivityManager lateinit var myWifiInfo: WifiInfo lateinit var scanResult: List<ScanResult> var hide_ssid = false var type = "" var wifi_action = "" lateinit var SECURITY_TYPE: String lateinit var mNetworkCallback: NetworkCallback }
onCreate初始化逻辑
mContext = getApplicationContext() mWifiManager = mContext.getSystemService(WIFI_SERVICE) as WifiManager mCm = mContext.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager mNetworkCallback = object : ConnectivityManager.NetworkCallback() { override fun onUnavailable() { super.onUnavailable() } override fun onLosing(network: Network, maxMsToLive: Int) { super.onLosing(network, maxMsToLive) } override fun onAvailable(network: Network) { super.onAvailable(network) mCm?.bindProcessToNetwork(network) } override fun onLost(network: Network) { super.onLost(network) } }
解决方案
针对隐藏SSID+SAE加密的连接场景,可通过以下优化实现稳定连接:
1. 优化NetworkSpecifier构建
简化隐藏SSID判断逻辑,同时指定AP工作频段(已知情况下),缩小扫描范围减少超时概率:
@RequiresApi(Build.VERSION_CODES.R) fun connectSae(ssid: String, password: String) { val specifierBuilder = WifiNetworkSpecifier.Builder() .setSsid(ssid) .setWpa3Passphrase(password) .setIsHiddenSsid(hide_ssid) // 已知AP频段时添加,二选一 .setBand(WifiNetworkSpecifier.BAND_5_GHZ) // .setBand(WifiNetworkSpecifier.BAND_2_4_GHZ) val suggestion = specifierBuilder.build() val networkRequest = NetworkRequest.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .setNetworkSpecifier(suggestion) .build() // 先注销旧回调,避免重复注册导致的异常 mCm?.unregisterNetworkCallback(mNetworkCallback) mCm?.requestNetwork(networkRequest, mNetworkCallback) }
2. 完善回调的错误处理与重试机制
隐藏SSID连接易出现超时,添加重试逻辑提升成功率:
mNetworkCallback = object : ConnectivityManager.NetworkCallback() { private var retryCount = 0 private val maxRetry = 3 override fun onUnavailable() { super.onUnavailable() Log.e(TAG, "连接失败,重试 ${retryCount + 1}/$maxRetry") if (retryCount < maxRetry) { retryCount++ Handler(Looper.getMainLooper()).postDelayed({ // 替换为实际传入的ssid和password参数 connectSae(ssid, password) }, 1000) } else { Log.e(TAG, "重试次数耗尽,连接失败") } } override fun onAvailable(network: Network) { super.onAvailable(network) retryCount = 0 // 重置重试计数 mCm?.bindProcessToNetwork(network) Log.d(TAG, "成功连接到隐藏SSID") } override fun onLost(network: Network) { super.onLost(network) Log.d(TAG, "连接丢失,重新尝试连接") connectSae(ssid, password) } }
3. 主动触发WiFi扫描(部分设备适配)
部分设备对隐藏SSID的自动扫描支持不佳,手动触发扫描可提升识别率:
fun triggerWifiScan() { // Android 12+ 可替换为 NEARBY_WIFI_DEVICES 权限 val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { Manifest.permission.NEARBY_WIFI_DEVICES } else { Manifest.permission.ACCESS_FINE_LOCATION } if (ContextCompat.checkSelfPermission(mContext, permission) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, arrayOf(permission), 1001) return } mWifiManager.startScan() }
调用connectSae前先执行triggerWifiScan(),确保设备先扫描到目标网络。
4. 备选方案:结合WifiConfiguration预配置
若上述方法仍不稳定,可先通过WifiManager添加隐藏SSID的配置,再发起连接:
fun addHiddenSaeConfig(ssid: String, password: String): WifiConfiguration? { val config = WifiConfiguration() config.SSID = "\"$ssid\"" config.hiddenSSID = true config.status = WifiConfiguration.Status.ENABLED config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE) config.preSharedKey = "\"$password\"" val networkId = mWifiManager.addNetwork(config) if (networkId != -1) { mWifiManager.enableNetwork(networkId, false) return config } return null }
在connectSae前调用该方法,确保系统已存在目标网络的配置记录。
关键注意事项
- 权限要求:Android 10及以下需
ACCESS_FINE_LOCATION权限;Android 12+可使用NEARBY_WIFI_DEVICES权限替代位置权限。 - 硬件兼容性:确保设备支持WPA3 SAE协议,旧款设备可能仅支持WPA2,无法连接SAE加密网络。
- 频段匹配:若AP仅工作在单一频段,指定频段可避免跨频段扫描的干扰,加快连接速度。
内容的提问来源于stack exchange,提问作者赵小甲
相关产品推荐
相关产品推荐

