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

Android设备WiFi已开启但无网络连接的检测方案需求

检测WiFi已开启但无互联网连接的解决方案

原代码仅监听网络的物理连接状态(是否有WiFi/蜂窝网络连接),但无法区分网络已连接但无互联网访问的场景(比如WiFi连接到无网的路由器)。以下是两种可行的解决方案:


方案一:利用Android系统NetworkCapabilities验证

Android API 23及以上提供NetworkCapabilities接口,可直接判断网络是否具备真实的互联网访问能力。核心是检查NET_CAPABILITY_VALIDATED(系统验证该网络可访问互联网)和NET_CAPABILITY_INTERNET(网络具备互联网访问的基础能力)。

完整修改代码

首先更新ConnectivityObserver的状态枚举,新增对应状态:

interface ConnectivityObserver {
    enum class Status {
        Available,                  // 有网络且可访问互联网
        ConnectedWithoutInternet,   // 网络已连接但无互联网访问
        Losing,
        Lost,
        Unavailable
    }

    fun observe(): Flow<Status>
}

修改后的NetworkConnectivityObserver实现:

class NetworkConnectivityObserver(
    private val context: Context
) : ConnectivityObserver {

    private val connectivityManager =
        context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    private val networkRequest = NetworkRequest.Builder()
        .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
        .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
        .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
        .build()

    override fun observe(): Flow<ConnectivityObserver.Status> {
        return callbackFlow {
            val callback = object : ConnectivityManager.NetworkCallback() {
                override fun onAvailable(network: Network) {
                    super.onAvailable(network)
                    launch { send(getNetworkStatus(network)) }
                }

                override fun onCapabilitiesChanged(
                    network: Network,
                    networkCapabilities: NetworkCapabilities
                ) {
                    super.onCapabilitiesChanged(network, networkCapabilities)
                    launch { send(getNetworkStatus(network)) }
                }

                override fun onLosing(network: Network, maxMsToLive: Int) {
                    super.onLosing(network, maxMsToLive)
                    launch { send(ConnectivityObserver.Status.Losing) }
                }

                override fun onLost(network: Network) {
                    super.onLost(network)
                    launch { send(ConnectivityObserver.Status.Lost) }
                }

                override fun onUnavailable() {
                    super.onUnavailable()
                    launch { send(ConnectivityObserver.Status.Unavailable) }
                }
            }

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                connectivityManager.registerDefaultNetworkCallback(callback)
            } else {
                connectivityManager.registerNetworkCallback(networkRequest, callback)
            }

            awaitClose {
                connectivityManager.unregisterNetworkCallback(callback)
            }
        }.distinctUntilChanged()
    }

    private fun getNetworkStatus(network: Network): ConnectivityObserver.Status {
        val capabilities = connectivityManager.getNetworkCapabilities(network)
        val hasInternet = capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == true
        val isValidated = capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) == true

        return when {
            hasInternet && isValidated -> ConnectivityObserver.Status.Available
            hasInternet -> ConnectivityObserver.Status.ConnectedWithoutInternet
            else -> ConnectivityObserver.Status.Unavailable
        }
    }
}

关键说明

  • NET_CAPABILITY_VALIDATED:系统通过内部验证确认该网络可访问互联网
  • 重写onCapabilitiesChanged方法,确保网络能力变化时及时更新状态
  • 需在Manifest中添加权限:<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

方案二:主动网络探测(补充方案)

系统验证在部分场景下可能不准确(比如内网环境需访问特定公网资源),此时可通过主动发起轻量网络请求验证连通性。

实现逻辑

  1. 网络连接状态变化时,定期发起HEAD请求到可靠的轻量资源(如Google的204无内容接口,流量极小)
  2. 根据请求结果判断是否有互联网访问
  3. 结合系统监听避免无效请求

示例代码

在原Flow中添加主动探测逻辑:

override fun observe(): Flow<ConnectivityObserver.Status> {
    return callbackFlow {
        // 原有callback注册逻辑保持不变
    }.distinctUntilChanged()
        .flatMapLatest { status ->
            if (status == ConnectivityObserver.Status.Available || status == ConnectivityObserver.Status.ConnectedWithoutInternet) {
                flow {
                    while (true) {
                        val hasInternet = isInternetAvailable()
                        emit(if (hasInternet) ConnectivityObserver.Status.Available else ConnectivityObserver.Status.ConnectedWithoutInternet)
                        delay(5000) // 每5秒检测一次,可按需调整
                    }
                }
            } else {
                flow { emit(status) }
            }
        }.distinctUntilChanged()
}

private fun isInternetAvailable(): Boolean {
    return try {
        // 可根据地区替换为国内可靠接口,如https://connect.rom.miui.com/generate_204
        val url = URL("https://www.google.com/generate_204")
        val connection = url.openConnection() as HttpURLConnection
        connection.connectTimeout = 3000
        connection.readTimeout = 3000
        connection.requestMethod = "HEAD"
        connection.responseCode in 200..399
    } catch (e: Exception) {
        false
    }
}

注意事项

  • 需添加权限:<uses-permission android:name="android.permission.INTERNET" />
  • 避免过于频繁的请求,防止消耗过多流量
  • 可根据用户所在地区替换探测接口,提升准确性

内容的提问来源于stack exchange,提问作者Krupali Shingala

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 23:25:30