检查 API 29 上的互联网连接

Posted

技术标签:

【中文标题】检查 API 29 上的互联网连接【英文标题】:Check for internet connectivity on API29 【发布时间】:2019-11-04 16:03:08 【问题描述】:

我使用以下方法检查互联网连接:

public boolean isInternetConnected() 
    ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = cm.getActiveNetworkInfo();
    return networkInfo != null && networkInfo.isConnected();

不过,我发现 NetworkInfogetActiveNetworkInfo()isConnected() 现在都已弃用。我在 SO 上检查了几个线程:

ConnectivityManager getNetworkInfo(int) deprecated

activeNetworkInfo.type is deprecated in API level 28

不过,它们都提供了不推荐使用的方法的答案。我一直在环顾四周,没有任何运气。是否有任何简单的方法来检查互联网连接,或者我应该继续使用我的方法并忽略已弃用的方法,因为它适用于 API29?

谢谢。

【问题讨论】:

【参考方案1】:

看看.hasTransport

val networkAvailability = cm.getNetworkCapabilities(cm.activeNetwork)
if(networkAvailability !=null && networkAvailability.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && networkAvailability.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED))

    //has network
    if (networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))  //wifi
     else if (networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR))  //cellular
    

【讨论】:

非常感谢您提供这个出色的解决方案。我真的很感激。 现实世界中有更多的连接方式【参考方案2】:

这是我对 SDK 29 的解决方案:一个名为 NetworkWatcher 的类,它观察网络的变化。它提供了诸如isWifiOn 之类的原始变量,以及通过Flow 和LiveData 观察网络随时间变化的选项。

@ExperimentalCoroutinesApi
class NetworkWatcher
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
private constructor(
    application: Application
) 

    private val connectivityManager =
        application.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE)
                as ConnectivityManager

    // general availability of Internet over any type
    var isOnline = false
        get() 
            updateFields()
            return field
        

    var isOverWifi = false
        get() 
            updateFields()
            return field
        

    var isOverCellular = false
        get() 
            updateFields()
            return field
        

    var isOverEthernet = false
        get() 
            updateFields()
            return field
        

    companion object 
        @Volatile
        private var INSTANCE: NetworkWatcher? = null

        fun getInstance(application: Application): NetworkWatcher 
            synchronized(this) 
                if (INSTANCE == null) 
                    INSTANCE = NetworkWatcher(application)
                
                return INSTANCE!!
            
        
    

    @Suppress("DEPRECATION")
    private fun updateFields() 

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 

            val networkAvailability =
                connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)

            if (networkAvailability != null &&
                networkAvailability.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
                networkAvailability.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
            ) 
                //has network
                isOnline = true

                // wifi
                isOverWifi =
                    networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)

                // cellular
                isOverCellular =
                    networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)

                // ethernet
                isOverEthernet =
                    networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
             else 
                isOnline = false
                isOverWifi = false
                isOverCellular = false
                isOverEthernet = false
            
         else 

            val info = connectivityManager.activeNetworkInfo
            if (info != null && info.isConnected) 
                isOnline = true

                val wifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
                isOverWifi = wifi != null && wifi.isConnected

                val cellular = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
                isOverCellular = cellular != null && cellular.isConnected

                val ethernet = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET)
                isOverEthernet = ethernet != null && ethernet.isConnected

             else 
                isOnline = false
                isOverWifi = false
                isOverCellular = false
                isOverEthernet = false
            
        
    

    fun watchNetwork(): Flow<Boolean> = watchWifi()
        .combine(watchCellular())  wifi, cellular -> wifi || cellular 
        .combine(watchEthernet())  wifiAndCellular, ethernet -> wifiAndCellular || ethernet 

    fun watchNetworkAsLiveData(): LiveData<Boolean> = watchNetwork().asLiveData()

    fun watchWifi(): Flow<Boolean> = callbackFlowForType(NetworkCapabilities.TRANSPORT_WIFI)

    fun watchWifiAsLiveData() = watchWifi().asLiveData()

    fun watchCellular(): Flow<Boolean> = callbackFlowForType(NetworkCapabilities.TRANSPORT_CELLULAR)

    fun watchCellularAsLiveData() = watchCellular().asLiveData()

    fun watchEthernet(): Flow<Boolean> = callbackFlowForType(NetworkCapabilities.TRANSPORT_ETHERNET)

    fun watchEthernetAsLiveData() = watchEthernet().asLiveData()

    private fun callbackFlowForType(@IntRange(from = 0, to = 7) type: Int) = callbackFlow 

        offer(false)

        val networkRequest = NetworkRequest.Builder()
            .addTransportType(type)
            .build()

        val callback = object : ConnectivityManager.NetworkCallback() 
            override fun onLost(network: Network?) 
                offer(false)
            

            override fun onUnavailable() 
                offer(false)
            

            override fun onLosing(network: Network?, maxMsToLive: Int) 
                // do nothing
            

            override fun onAvailable(network: Network?) 
                offer(true)
            
        

        connectivityManager.registerNetworkCallback(networkRequest, callback)

        awaitClose  connectivityManager.unregisterNetworkCallback(callback) 
    

例如,您可以在应用程序中订阅有关手机网络状态的更新,例如:

GlobalScope.launch 
    NetworkWatcher.getInstance(this@MyApplication).watchNetwork().collect  connected ->
        Log.d("TAG", "Network In App: $connected")
    

或者要回答您的问题,只需阅读 Wifi 值,例如:

if (NetworkWatcher.getInstance(this@BaseApp).isOverWifi) 
    // do stuff

旁注:我没有一直使用getInstance(),而是使用Koin 等DI 框架将NetworkWatcher 注入到我需要的地方。

【讨论】:

【参考方案3】:

在 AndroidManifest.xml 中添加:

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

现在检查网络状态:

 @IntRange(from = 0, to = 3)
fun getConnectionType(context: Context): Int 
    var result = 0 // Returns connection type. 0: none; 1: mobile data; 2: wifi
    val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 

        val capabilities =
            cm.getNetworkCapabilities(cm.activeNetwork)
        if (capabilities != null) 
            if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) 
                result = 2
             else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) 
                result = 1
             else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_***)) 
                result = 3
            

        
     else 

        val activeNetwork = cm.activeNetworkInfo
        if (activeNetwork != null) 
            // connected to the internet
            if (activeNetwork.type === ConnectivityManager.TYPE_WIFI) 
                result = 2
             else if (activeNetwork.type === ConnectivityManager.TYPE_MOBILE) 
                result = 1
             else if (activeNetwork.type === ConnectivityManager.TYPE_***) 
                result = 3
            
        
    
    return result

【讨论】:

【参考方案4】:

我的答案很干净,在 Kotlin 中,还可以处理不同的 API 级别

fun isOnline(): Boolean 
        val connectivityManager =
            ContextCompat.getSystemService(DreamPad.appContext, ConnectivityManager::class.java)
        connectivityManager ?: return false
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
            val nw = connectivityManager.activeNetwork ?: return false
            val actNw = connectivityManager.getNetworkCapabilities(nw) ?: return false
            when 
                actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
                actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
                //for other device how are able to connect with Ethernet
                actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
                //for check internet over Bluetooth
                actNw.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> true
                else -> false
            
         else 
            @Suppress("DEPRECATION")
            connectivityManager.activeNetworkInfo?.isConnected ?: false
        
    

【讨论】:

以上是关于检查 API 29 上的互联网连接的主要内容,如果未能解决你的问题,请参考以下文章

尝试使用 Alamofire 检查 iOS 设备上的互联网连接

java 检查Android上的互联网连接

无法连接到 Heroku API,请检查互联网连接并重试

检查 iPhone 上的互联网连接并监控变化

不断检查 Flutter 应用程序上的互联网断开连接

让最基本的 ajax 在 Windows 7 上的 xampp 上工作以检查互联网连接