Android WiFi Manager enableNetwork返回true,但NetworkInfo状态始终为断开连接/扫描

Android WiFi Manager enableNetwork返回true,但NetworkInfo状态始终为断开连接/扫描,android,rx-java2,wifimanager,Android,Rx Java2,Wifimanager,我编写了一些代码来启用具有给定networkId的网络,并通过BroadcastReceiver处理异步响应。但是,即使enableNetwork返回true(表示操作系统已成功发出命令),myBroadcastReceiver从未接收到处于CONNECTED状态的NetworkInfo,它仍会接收两个事件:断开连接然后断开连接/扫描 从我读过的所有官方文档和各种SO问题来看,如果enableNetwork返回true,则注册用于处理NETWORK\u STATE\u CHANGED\u ACT

我编写了一些代码来启用具有给定
networkId
的网络,并通过
BroadcastReceiver
处理异步响应。但是,即使
enableNetwork
返回true(表示操作系统已成功发出命令),my
BroadcastReceiver
从未接收到处于
CONNECTED
状态的
NetworkInfo
,它仍会接收两个事件:
断开连接
然后
断开连接/扫描

从我读过的所有官方文档和各种SO问题来看,如果
enableNetwork
返回true,则注册用于处理
NETWORK\u STATE\u CHANGED\u ACTION
BroadcastReceiver
对象应始终接收状态为
CONNECTED
NetworkInfo
对象

代码如下:

/**
 * Connects to the wifi access point at specified [ssid] with specified [networkId]
 * And returns the [WifiInfo] of the network that has been connected to
 */
private fun connect(context: Context,
                    wifiManager: WifiManager,
                    ssid: String,
                    networkId: Int) = Single.create<WifiInfo> { emitter ->

    val wifiConnectionReceiver = object : BroadcastReceiver() {
        var oldSupplicantState: SupplicantState? = null

        override fun onReceive(context: Context, intent: Intent) {
            if (intent.action == WifiManager.NETWORK_STATE_CHANGED_ACTION) {
                val networkInfo = intent.getParcelableExtra<NetworkInfo>(WifiManager.EXTRA_NETWORK_INFO) ?: return

                if (networkInfo.detailedState == NetworkInfo.DetailedState.DISCONNECTED) {
                    context.applicationContext.unregisterReceiver(this)
                    emitter.onError(WiFiException("Failed to connect to wifi network"))
                }
                else if (networkInfo.detailedState == NetworkInfo.DetailedState.CONNECTED) {
                    val wifiInfo = intent.getParcelableExtra<WifiInfo>(WifiManager.EXTRA_WIFI_INFO) ?: return
                    if (ssid == wifiInfo.ssid.unescape()) {
                        context.applicationContext.unregisterReceiver(this)
                        emitter.onSuccess(wifiInfo)
                    }
                }
            } else if (intent.action == WifiManager.SUPPLICANT_STATE_CHANGED_ACTION) {
                val supplicantState = intent.getParcelableExtra<SupplicantState>(WifiManager.EXTRA_NEW_STATE)
                val oldSupplicantState = this.oldSupplicantState
                this.oldSupplicantState = supplicantState

                if (supplicantState == SupplicantState.DISCONNECTED) {
                    if (oldSupplicantState == null || oldSupplicantState == SupplicantState.COMPLETED) {
                        return
                    }
                    val possibleError = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, -1)
                    if (possibleError == WifiManager.ERROR_AUTHENTICATING) {
                        context.applicationContext.unregisterReceiver(this)
                        emitter.onError(WiFiException("Wifi authentication failed"))
                    }
                } else if (supplicantState == SupplicantState.SCANNING && oldSupplicantState == SupplicantState.DISCONNECTED) {
                    context.applicationContext.unregisterReceiver(this)
                    emitter.onError(WiFiException("Failed to connect to wifi network"))
                }
            }
        }
    }

    val networkStateChangedFilter = IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION)
    networkStateChangedFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)

    context.applicationContext.registerReceiver(wifiConnectionReceiver, networkStateChangedFilter)

    emitter.setCancellable {
        if (!emitter.isDisposed)
            context.applicationContext.unregisterReceiver(wifiConnectionReceiver)
    }

    wifiManager.enableNetwork(networkId, true)
}
/**
*使用指定的[networkId]在指定的[ssid]连接到wifi接入点
*并返回已连接到的网络的[WifiInfo]
*/
私人娱乐连接(上下文:上下文,
wifiManager:wifiManager,
ssid:String,
networkId:Int)=Single.create{emitter->
val wifiConnectionReceiver=对象:BroadcastReceiver(){
var oldSupplicantState:SupplicantState?=null
覆盖接收(上下文:上下文,意图:意图){
if(intent.action==WifiManager.NETWORK\u STATE\u CHANGED\u action){
val networkInfo=intent.getParcelableExtra(WifiManager.EXTRA\u NETWORK\u INFO)?:返回
if(networkInfo.detailedState==networkInfo.detailedState.DISCONNECTED){
context.applicationContext.unregisterReceiver(此)
emitter.onError(WiFiException(“无法连接到wifi网络”))
}
else if(networkInfo.detailedState==networkInfo.detailedState.CONNECTED){
val wifiInfo=intent.getParcelableExtra(WifiManager.EXTRA\u WIFI\u INFO)?:返回
如果(ssid==wifiInfo.ssid.unescape()){
context.applicationContext.unregisterReceiver(此)
发射器.onSuccess(wifiInfo)
}
}
}else if(intent.action==WifiManager.supliciant\u STATE\u CHANGED\u action){
val supplicantState=intent.getParcelableExtra(WifiManager.EXTRA\u NEW\u STATE)
val oldSupplicantState=this.oldSupplicantState
this.oldSupplicantState=supplicantState
如果(请求状态==请求状态.已断开连接){
如果(oldSupplicantState==null | | oldSupplicantState==SupplicantState.COMPLETED){
回来
}
val-possibleError=intent.getIntExtra(WifiManager.EXTRA\u请求者\u错误,-1)
if(possibleError==WifiManager.ERROR\u身份验证){
context.applicationContext.unregisterReceiver(此)
emitter.onError(WiFiException(“Wifi身份验证失败”))
}
}else if(supplicantState==supplicantState.SCANNING&&oldSupplicantState==supplicantState.DISCONNECTED){
context.applicationContext.unregisterReceiver(此)
emitter.onError(WiFiException(“无法连接到wifi网络”))
}
}
}
}
val networkStateChangedFilter=IntentFilter(WifiManager.NETWORK\u STATE\u CHANGED\u ACTION)
networkStateChangedFilter.addAction(WifiManager.SUPPLICANT\u STATE\u CHANGED\u ACTION)
context.applicationContext.registerReceiver(wifiConnectionReceiver,networkStateChangedFilter)
发射器.setCancelable{
如果(!emitter.isDisposed)
context.applicationContext.unregisterReceiver(wifiConnectionReceiver)
}
wifiManager.enableNetwork(networkId,true)
}

有人能帮忙吗?我真的被难住了。我传递的
networkId
是有效的,因为它是从
addNetwork
创建的,它成功了,因为它没有返回-1。

好的,我终于明白了这一点,我希望我在这里的回答能为将来遇到类似问题的任何人提供一些启示,因为这很恶心,让我很头疼

我问题中的代码并不完全正确,但它也不是我问题的根本原因。问题的根本原因是我错误地配置了
WiFiConfig
对象,该对象是通过
WiFiConfigManager.addNetwork()
WiFiConfig
表中注册的

我对
WifiConfigManager.addNetwork()
的契约做了大量假设。我假设如果该操作成功(即未返回
-1
),则传递的
WiFiConfig
配置正确。这个假设是不正确的,我创建的
WiFiConfig
上的
allowedAuthAlgorithms
allowedProtocols
AllowedKeyManager
allowedPairwiseCipher
位集不正确,但对
addNetwork()
的调用成功。我认为这是因为对
addNetwork()
的调用实际上除了验证配置是否可以有效地放入
WiFiConfig
表之外没有做任何事情,这与验证它是否是给定WiFi接入点的正确配置大不相同。这是由
addNetwork()
源代码中的注释所支持的,这些注释不像许多其他
WiFiManager
函数那样说明异步状态的交付,表明(至少对我来说)操作系统没有试图通过调用
addNetwork()与接入点通信

因为一位同事提出了一个非常有用的建议
/**
 * Emits a single of the [WifiConfiguration] created from the passed [scanResult] and [preSharedKey]
 */
private fun createWifiConfiguration(scanResult: WiFiScanResult, preSharedKey: String) = Single.fromCallable<WifiConfiguration> {
    val auth = scanResult.auth
    val keyManagement = scanResult.keyManagement
    val pairwiseCipher = scanResult.pairwiseCipher

    val config = WifiConfiguration()
    config.SSID = "\"" +  scanResult.ssid + "\""
    config.BSSID = scanResult.bssid

    if (auth.contains("WPA") || auth.contains("WPA2")) {
        config.allowedProtocols.set(WifiConfiguration.Protocol.WPA)
        config.allowedProtocols.set(WifiConfiguration.Protocol.RSN)
    }

    if (auth.contains("EAP"))
        config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.LEAP)
    else if (auth.contains("WPA") || auth.contains("WPA2"))
        config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN)
    else if (auth.contains("WEP"))
        config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED)

    if (keyManagement.contains("IEEE802.1X"))
        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X)
    else if (auth.contains("WPA") && keyManagement.contains("EAP"))
        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP)
    else if (auth.contains("WPA") && keyManagement.contains("PSK"))
        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK)
    else if (auth.contains("WPA2") && keyManagement.contains("PSK"))
        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK)

    if (pairwiseCipher.contains("CCMP") || pairwiseCipher.contains("TKIP")) {
        config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP)
        config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP)
    }

    if (preSharedKey.isNotEmpty()) {
        if (auth.contains("WEP")) {
            if (preSharedKey.matches("\\p{XDigit}+".toRegex())) {
                config.wepKeys[0] = preSharedKey
            } else {
                config.wepKeys[0] = "\"" + preSharedKey + "\""
            }
            config.wepTxKeyIndex = 0
        } else {
            config.preSharedKey = "\"" + preSharedKey + "\""
        }
    }

    config
}
/**
 * Connects to the wifi access point at specified [ssid] with specified [networkId]
 * And returns the [WifiInfo] of the network that has been connected to
 */
private fun connect(context: Context,
                    wifiManager: WifiManager,
                    ssid: String,
                    networkId: Int) = Single.create<WifiInfo> { emitter ->

    val wifiConnectionReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            if (intent.action == WifiManager.NETWORK_STATE_CHANGED_ACTION) {
                val networkInfo = intent.getParcelableExtra<NetworkInfo>(WifiManager.EXTRA_NETWORK_INFO) ?: return

                if (networkInfo.detailedState == NetworkInfo.DetailedState.CONNECTED) {
                    val wifiInfo = intent.getParcelableExtra<WifiInfo>(WifiManager.EXTRA_WIFI_INFO) ?: return
                    if (ssid.unescape() == wifiInfo.ssid.unescape()) {
                        context.applicationContext.unregisterReceiver(this)
                        emitter.onSuccess(wifiInfo)
                    }
                }
            }
        }
    }

    val networkStateChangedFilter = IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION)
    networkStateChangedFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)

    context.applicationContext.registerReceiver(wifiConnectionReceiver, networkStateChangedFilter)

    emitter.setCancellable {
        if (!emitter.isDisposed)
            context.applicationContext.unregisterReceiver(wifiConnectionReceiver)
    }

    wifiManager.enableNetwork(networkId, true)
}