代码之家  ›  专栏  ›  技术社区  ›  Thomas Cook

Android WiFi Manager enableNetwork返回true,但NetworkInfo状态始终为DISCONNECTED/SCANNING

  •  0
  • Thomas Cook  · 技术社区  · 6 年前

    我写了一些代码来启用给定的网络 networkId ,并通过 BroadcastReceiver . 然而,即使 enableNetwork issue(issue)成功返回指示my命令的true 广播接收机 NetworkInfo 具有 CONNECTED 状态,它接收2个事件: DISCONNECTED DISCONNECTED/SCANNING .

    从所有的官方文件和我读过的各种问题中,如果 启用网络 广播接收机 登记办理 NETWORK_STATE_CHANGED_ACTION 意向应始终收到 具有状态的对象 .

    代码如下:

    /**
     * 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)
    }
    

    有人能帮忙吗?我真的被难住了。这个 addNetwork 这是成功的,因为它没有返回-1。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Thomas Cook    6 年前

    好吧,我终于弄明白了,我希望我的答案能为将来遇到类似问题的人提供一些启示,因为这很糟糕,让我很头疼。

    WiFiConfig 在中注册的 WiFiConfig文件 表via WiFiConfigManager.addNetwork() .

    WifiConfigManager.addNetwork() . 我假设如果那次行动成功了(即没有返回 -1 allowedAuthAlgorithms allowedProtocols , allowedKeyManagers allowedPairwiseCipher BitSet 我创建的是不正确的,但是 addNetwork() 成功。我相信这是因为 添加网络() 除了验证配置 是有效的 WiFiConfig文件 桌子 ,这与验证 给定WiFi接入点的配置是否正确 . 这是由源代码中的注释支持的 它们不像很多其他状态那样声明异步状态的传递 WiFiManager .

    WiFiConfig文件 对象与由我自己的代码生成的访问点的不一致性我注意到 WiFiConfig文件

    为什么我 WiFiConfig文件 WiFiConfig文件 正确地说,他们似乎都在使用 BitWise 运算符来创建 Int 最终传递给 WiFiConfig.allowedProtocols.set() WiFiConfig.allowedPairwiseCiphers.set() WiFiConfig.allowedKeyManagement.set() WiFiConfig.allowedAuthAlgorithm.set() 功能。

    事实证明 位集合 中的元素的索引对应的WiFiConfig对象中的实例 String 曾经的数组 与上述相关 在WiFiConfig对象中。因此,如果您希望提供 protocols , keyManagements , pairwiseCiphers authAlgorithms set ,传入与所选协议匹配的字符串数组元素对应的正确索引。

    在重新编写我的 创建代码后,问题自行解决。虽然我在原帖子中的代码中有一个错误也已被修复。

    下面是新的WiFiConfig创建代码:

    /**
     * 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
    }
    

    下面是新的connect代码:

    /**
     * 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)
    }