Métodos de verificar la conexión a internet para Android usando Kotlin


Al crear una aplicación que requiere de internet, el alguna parte del código se requiere detectar si el dispositivo tiene internet disponible o bien si la app no funciona sin conexión a internet lo mejor es supervisar en tiempo real el estado de la conexión.

Permisos necesarios

Se debe añadir los siguientes permisos para detectar la conexión a internet

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

NetworkUtils

Métodos de ayuda para la deteción de conectividad de una red y verificar si hay internet disponible.

  • isNetworkAvailable: para obtener si el dispositivo está conectado a una red
  • isInternetRecheable: para verificar la conexión a internet
  • openInternetConnectivity: para abrir el panel de conexión a una red del sistema android
import android.Manifest
import android.content.Context
import android.content.Intent
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.provider.Settings
import androidx.annotation.RequiresPermission
import androidx.core.app.ActivityCompat.startActivity
import java.io.IOException
import java.net.HttpURLConnection
import java.net.URL

object NetworkUtils {

    @RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
    fun isNetworkAvailable(context: Context): Boolean {
        val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val activeNetwork = connectivityManager.activeNetwork ?: return false
            val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false
            return when {
                networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
                networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
                networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> true
                networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
                else -> false
            }
        } else @Suppress("deprecation") {
            val activeNetwork = connectivityManager.activeNetworkInfo ?: return false
            return activeNetwork.isConnectedOrConnecting
        }
    }

    @RequiresPermission(anyOf = [Manifest.permission.ACCESS_NETWORK_STATE, Manifest.permission.INTERNET])
    fun isInternetReachable(context: Context): Boolean {
        if (isNetworkAvailable(context)) {
            //Network is available, check if internet is reachable
            try {
                val httpConnection: HttpURLConnection = URL("https://clients3.google.com/generate_204")
                    .openConnection() as HttpURLConnection
                httpConnection.setRequestProperty("User-Agent", "Android")
                httpConnection.setRequestProperty("Connection", "close")
                httpConnection.connectTimeout = 1500
                httpConnection.connect()

                return httpConnection.responseCode == 204
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
        return false
    }

    fun openInternetConnectivityPanel(context: Context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            val panelIntent = Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY)
            startActivity(context, panelIntent, null)
        }
    }

}

Verificar si hay conectividad

Caso de uso para verificar si hay salida a internet, usando el método isInternetRecheable

GlobalScope.async {

    if (NetworkUtils.isInternetReachable(requireContext())) {
        //Has Internet
        findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
    } else {
        //No Internet found
        withContext(Dispatchers.Main) {
            Toast.makeText(requireContext(), getString(R.string.error_internet_connection), Toast.LENGTH_SHORT).show()
        }
    }

}

Verificar si hay red disponible

Caso de uso para verificar si hay conexión a una red y luego testear si tiene capacidad de Internet, primero se usará el método isNetworkAvailable, si hay una red establecida se llamará isInternetRecheable, si no está disponible una red, mostrará una snackbar con la opción de abrir el panel de conectividad del sistema android con el método openInternetConnectivity

GlobalScope.async {
    if (NetworkUtils.isInternetReachable(this@MainActivity)) {
        withContext(Dispatchers.Main) {
            Toast.makeText(this@MainActivity, "eurekaaaaaa!", Toast.LENGTH_SHORT).show()
        }
    } else {
        if (!NetworkUtils.isNetworkAvailable(this@MainActivity)) {
            Snackbar.make(view, getString(R.string.error_network_not_available), Snackbar.LENGTH_LONG)
                .setAnchorView(R.id.fab)
                .setAction(getString(R.string.error_network_not_available_action)) {
                    NetworkUtils.openInternetConnectivityPanel(this@MainActivity)
                }.show()
        } else {
            withContext(Dispatchers.Main) {
                Toast.makeText(this@MainActivity, getString(R.string.error_internet_connection), Toast.LENGTH_SHORT).show()
            }
        }

    }
}

Supervisar la conexión a internet

En caso de querer supervisar en tiempo real el estado a internet, si el usuario cambia de red sin capacidad de Internet etc…, para ello se usa un livedata ConnectionLiveData que monitorice el estado

import android.content.Context
import android.content.Context.CONNECTIVITY_SERVICE
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkRequest
import androidx.lifecycle.LiveData
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.IOException
import java.net.InetSocketAddress
import javax.net.SocketFactory

class ConnectionLiveData(val context: Context) : LiveData<Boolean>() {

    private lateinit var networkCallback: ConnectivityManager.NetworkCallback
    private val connectivityManager =
        context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
    private val validNetworks: MutableSet<Network> = HashSet()

    private fun checkValidNetworks() {
        postValue(validNetworks.size > 0)
    }

    override fun onActive() {
        networkCallback = createNetworkCallback()
        val networkRequest = NetworkRequest.Builder()
            .addCapability(NET_CAPABILITY_INTERNET)
            .build()
        connectivityManager.registerNetworkCallback(networkRequest, networkCallback)


        CoroutineScope(Dispatchers.IO).launch {
            val activeNetwork = connectivityManager.activeNetwork

            if (activeNetwork == null) {
                postValue(false)
            } else {
                val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork)
                val hasInternetCapability = networkCapabilities?.hasCapability(NET_CAPABILITY_INTERNET)

                if (hasInternetCapability == true) {
                    val hasInternet = DoesNetworkHaveInternet.execute(activeNetwork.socketFactory)
                    postValue(hasInternet)
                }else {
                    postValue(false)
                }
            }
        }

    }

    override fun onInactive() {
        connectivityManager.unregisterNetworkCallback(networkCallback)
    }

    private fun createNetworkCallback() = object : ConnectivityManager.NetworkCallback() {

        override fun onAvailable(network: Network) {
            val networkCapabilities = connectivityManager.getNetworkCapabilities(network)
            val hasInternetCapability = networkCapabilities?.hasCapability(NET_CAPABILITY_INTERNET)

            if (hasInternetCapability == true) {
                // Check if this network actually has internet
                CoroutineScope(Dispatchers.IO).launch {
                    val hasInternet = DoesNetworkHaveInternet.execute(network.socketFactory)
                    if (hasInternet) {
                        withContext(Dispatchers.Main) {

                            validNetworks.add(network)
                            checkValidNetworks()
                        }
                    }
                }
            }
        }

        override fun onLost(network: Network) {
            validNetworks.remove(network)
            checkValidNetworks()
        }
    }

    object DoesNetworkHaveInternet {

        fun execute(socketFactory: SocketFactory): Boolean {
            // Make sure to execute this on a background thread.
            return try {
                val socket = socketFactory.createSocket() ?: throw IOException("Socket is null.")
                socket.connect(InetSocketAddress("8.8.8.8", 53), 1500)
                socket.close()
                true
            } catch (e: IOException) {
                false
            }
        }
    }
}

en la actividad declarar el observador

private fun initObservers() {
    val netStatusView = binding.contentMain.networkStatus
    val connectionLiveData: ConnectionLiveData = ConnectionLiveData(this)

    connectionLiveData.observe(this) { isNetworkAvailable ->
        Log.d(TAG, "initObservers() called with: isNetworkAvailable = $isNetworkAvailable")
        if (isNetworkAvailable) {
            Toast.makeText(this@MainActivity, "Connected", Toast.LENGTH_SHORT).show()

        } else {
            Toast.makeText(this@MainActivity, "Lost", Toast.LENGTH_SHORT).show()

            }
        }
    }

}
Anuncio publicitario

Publicado por Codelaby

Mobile DevDesigner

Deja una respuesta

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Salir /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Salir /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Salir /  Cambiar )

Conectando a %s

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

A %d blogueros les gusta esto: