自学内容网 自学内容网

判断是否连接了wifi(坑、坑、坑)

在公司的一台Android球机设备上,制造商修改了系统,在连接wifi后,如果还插有sim卡,则网络是走sim卡的流量,不走wifi,所以此时我们ping wifi局域网的网关或局域网中别的ip是ping不通的,因为网络走的sim卡不走wifi。在这种情况下,一些判断wifi是否已连接的代码将失效(为什么此时我要判断wifi是否已连接?因为我要判断wifi是连接的话我就关闭sim卡数据流量,以让流量走wifi,如果wifi没连接我就开启sim卡数据流量,以让网络走sim卡。恶心的厂家乱改!)。

示例代码所需权限:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
fun isWifiConnected(): Boolean {
    val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    val networkInfo = cm.activeNetworkInfo
    println("isConnected = ${networkInfo?.isConnected}")
    println("isMobile = ${networkInfo?.type == ConnectivityManager.TYPE_MOBILE}")
    return networkInfo != null && networkInfo.type == ConnectivityManager.TYPE_WIFI
}

用这个函数判断wifi是否连接是不准的,运行结果如下:

isConnected = true
isMobile = true

当前,设备是连接了wifi了的,但是由于系统被改为wifi和sim卡同时存在时走sim卡,所以这里获取的activeNetworkInfo是 sim卡的,并不是 wifi的。

同理,用下面的函数判断wifi是否已连接也是不准确的,如下:

private fun isWifiConnected(): Boolean {
    val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    val activeNetwork = connectivityManager.activeNetwork
    val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork)
    return networkCapabilities?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ?: false
}

下面的方式也不准:

fun isWifiConnected(): Boolean {
    val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    val networkInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
    println("isConnected = ${networkInfo?.isConnected}")
    return networkInfo?.isConnected ?: false
}

运行结果如下:

isConnected = false

另一种方式来自ChatGPT:

fun isWifiConnected(): Boolean {
    val wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
    println("networkId = ${wifiManager.connectionInfo.networkId}")
    return wifiManager.connectionInfo.networkId != -1
}

运行结果如下:

networkId = -1

明明连接了wifi了,但是它竟然返回-1,获取ssid也获取不到,后来查看connectionInfo的文档声明,发现它需要定位权限,于是把权限加上:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

加上权限再次运行就OK了,可以成功判断wifi是否连接。

另外我自己想了一个方式,因为wifi连接之后会分配到ip,所以我通过判断wifi网络接口是否有ip,有的话就是wifi已经连接上了,该方式需要网络权限,如下:

<uses-permission android:name="android.permission.INTERNET"/>
fun isWifiConnected(): Boolean {
    val networkInterface = NetworkInterface.getByName("wlan0")
    val inet4Address = networkInterface?.inetAddresses?.asSequence()?.find { it is Inet4Address }
    println("ip = ${inet4Address?.hostAddress}")
    return inet4Address != null
}

运行结果如下:

192.168.1.173

断开wifi连接再运行,结果如下:

ip = null

这里我们取了ipv4的ip地址,简单一点应该是只要有ip就行,不管你是ipv4还是ipv6,如下:

fun isWifiConnected(): Boolean {
    val networkInterface = NetworkInterface.getByName("wlan0")
    return networkInterface?.inetAddresses?.hasMoreElements() ?: false
}

这种方式虽然实现了我们需要的功能,但总感觉不是很正规的样子,Android官方有提供正规的方式,如 下:

fun isWifiConnected(): Boolean {
    val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    val allNetworks = connectivityManager.allNetworks
    for (network in allNetworks) {
        val networkCapabilities = connectivityManager.getNetworkCapabilities(network)
        if (networkCapabilities != null && networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
            return true
        }
    }
    return false
}

在IDE中显示connectivityManager.allNetworks是过时的,然后推荐了另一种方式,如下:

fun isWifiConnected() {
    val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    val request = NetworkRequest.Builder()
        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
        .build()
    val networkCallback = object : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: android.net.Network) {
            println("wifi已连接")
        }
        override fun onLost(network: android.net.Network) {
            println("wifi未连接")
        }
    }
    connectivityManager.registerNetworkCallback(request, networkCallback)
}

如上方法,当wifi是连接的情况下,它就像是个粘性广播,一调用register函数就会立马收到回调,但是如果wifi是未连接的情况下,调用register函数时不会收到回调,所以这点不是很好,感觉像是Android官方Bug,你推荐我们用这种方式,但是当wifi未连接时,调用register函数确实收不到回调通知。当我们已经调用注册了,此时才把wifi断开,这是可以收到回调的。所以,如果要监听wifi连接、断开的事件,可以使用这个注册回调的方式,如果要主动获取,则还是使用前一种方式,或者使用判断是否有ip的方式。

总结:可以准确获取wifi连接状态的方式有4种,如下:

fun isWifiConnected(): Boolean {
    val networkInterface = NetworkInterface.getByName("wlan0")
    return networkInterface?.inetAddresses?.hasMoreElements() ?: false
}
fun isWifiConnected(): Boolean {
    val wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
    return wifiManager.connectionInfo.networkId != -1
}
fun isWifiConnected(): Boolean {
    val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    val allNetworks = connectivityManager.allNetworks
    for (network in allNetworks) {
        val networkCapabilities = connectivityManager.getNetworkCapabilities(network)
        if (networkCapabilities != null && networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
            return true
        }
    }
    return false
}
fun isWifiConnected() {
    val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    val request = NetworkRequest.Builder()
        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
        .build()
    val networkCallback = object : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: android.net.Network) {
            println("wifi已连接")
        }
        override fun onLost(network: android.net.Network) {
            println("wifi未连接")
        }
    }
    connectivityManager.registerNetworkCallback(request, networkCallback)
}

原文地址:https://blog.csdn.net/android_cai_niao/article/details/140554152

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!