Ler o estado da rede

O Android permite que os apps aprendam sobre mudanças dinâmicas na conectividade. Use as classes a seguir para monitorar e responder a mudanças de conectividade:

  • ConnectivityManager informa o app sobre o estado da conectividade no sistema.
  • A classe Network representa uma das redes a que o dispositivo está conectado. Use o objeto Network como uma chave para coletar informações sobre a rede com ConnectivityManager ou para vincular soquetes na rede. Quando a rede é desconectada, o objeto Network não pode mais ser usado. Mesmo se o dispositivo se conectar novamente à mesma rede, um novo objeto Network representará a nova rede.
  • O objeto LinkProperties contém informações sobre o link de uma rede, como a lista de servidores DNS, endereços IP locais e as rotas instaladas na rede.
  • O objeto NetworkCapabilities contém informações sobre as propriedades de uma rede, como os transportes (Wi-Fi, móvel, Bluetooth) e os recursos da rede. Por exemplo, você pode consultar o objeto para determinar se a rede é capaz de enviar MMS, se tem um portal cativo ou se é limitada.

Os apps interessados no estado imediato da conectividade podem chamar métodos ConnectivityManager a qualquer momento para descobrir que tipo de rede está disponível. Esses métodos são úteis para depuração e, ocasionalmente, para analisar um snapshot de conectividade disponível no momento.

No entanto, os métodos síncronos ConnectivityManager não informam o app sobre o que acontece após uma chamada, então eles não permitem atualizar a interface. Eles também não podem ajustar o comportamento do app com base na desconexão da rede ou quando os recursos da rede mudarem.

A conectividade pode mudar a qualquer momento e a maioria dos apps precisa ter uma visualização sempre atualizada do estado da rede no dispositivo. Os apps podem registrar um callback com ConnectivityManager para serem alertados sobre mudanças importantes para eles. Ao usar o callback, o app pode reagir imediatamente a qualquer mudança relevante da conectividade sem precisar recorrer a pesquisas custosas que podem não refletir atualizações rápidas.

O uso de NetworkCallback, assim como outras maneiras de descobrir o estado de conectividade do dispositivo, não exige nenhuma permissão específica. No entanto, algumas redes estão sujeitas a essas permissões. Por exemplo, pode haver redes restritas que não estejam disponíveis para apps. A vinculação a uma rede em segundo plano requer a permissão CHANGE_NETWORK_STATE. Além disso, algumas chamadas podem precisar de permissões específicas para serem executadas. Para saber mais detalhes, consulte a documentação específica de cada chamada.

Acessar o estado instantâneo

Um dispositivo Android pode manter muitas conexões ao mesmo tempo. Para saber mais sobre o estado atual da rede, extraia uma instância de ConnectivityManager:

Kotlin

val connectivityManager = getSystemService(ConnectivityManager::class.java)

Java

ConnectivityManager connectivityManager = getSystemService(ConnectivityManager.class);

Em seguida, use essa instância para acessar uma referência à rede padrão atual do app:

Kotlin

val currentNetwork = connectivityManager.getActiveNetwork()

Java

Network currentNetwork = connectivityManager.getActiveNetwork();

Com uma referência a uma rede, o app poderá exigir informações sobre ela:

Kotlin

val caps = connectivityManager.getNetworkCapabilities(currentNetwork)
val linkProperties = connectivityManager.getLinkProperties(currentNetwork)

Java

NetworkCapabilities caps = connectivityManager.getNetworkCapabilities(currentNetwork);
LinkProperties linkProperties = connectivityManager.getLinkProperties(currentNetwork);

Para recursos mais úteis, registre um NetworkCallback. Para mais informações sobre como registrar callbacks de rede, consulte Ouvir eventos de rede.

NetworkCapabilities e LinkProperties

Os objetos NetworkCapabilities e LinkProperties fornecem informações sobre todos os atributos que o sistema sabe sobre uma rede.

O objeto LinkProperties sabe sobre rotas, endereços de link, nome da interface, informações do proxy (se houver) e servidores DNS. Chame o método relevante no objeto LinkProperties para acessar as informações necessárias.

O objeto NetworkCapabilities encapsula informações sobre os transportes de rede e os respectivos recursos.

Um transporte é uma abstração de um meio físico pelo qual uma rede opera. Exemplos comuns de transportes são Ethernet, Wi-Fi e dados móveis. VPNs e Wi-Fi ponto a ponto também podem cumprir essa função. No Android, uma rede pode ter vários transportes ao mesmo tempo. Um exemplo é uma VPN que opera em redes Wi-Fi e móveis. Ela tem os transportes Wi-Fi, móveis e VPN. Para descobrir se uma rede tem um transporte específico, use o método NetworkCapabilities.hasTransport(int) com uma das constantes NetworkCapabilities.TRANSPORT_*.

Um recurso descreve uma propriedade da rede. Os recursos de exemplo incluem MMS, NOT_METERED e INTERNET. Uma rede com o recurso de MMS pode enviar e receber mensagens de serviços de mensagens multimídia, enquanto uma rede sem esse recurso não pode. Redes com o recurso NOT_METERED não cobram o usuário pelo uso de dados. O app pode verificar os recursos adequados usando o método NetworkCapabilities.hasCapability(int) com uma das constantes NetworkCapabilities.NET_CAPABILITY_*.

As constantes NET_CAPABILITY_* mais úteis incluem:

  • NET_CAPABILITY_INTERNET: indica que a rede está configurada para acessar a Internet. Isso está relacionado à configuração, e não à capacidade real de acessar servidores públicos. Por exemplo, uma rede pode estar configurada para acessar a Internet, mas estar sujeita a um portal cativo.

    A rede móvel de uma operadora normalmente tem o recurso INTERNET, enquanto uma rede Wi-Fi P2P local normalmente não tem. Para conferir a conectividade real, consulte NET_CAPABILITY_VALIDATED.

  • NET_CAPABILITY_NOT_METERED: indica que a rede não é limitada. Uma rede é classificada como limitada quando o usuário precisa se preocupar com o uso intenso de dados nessa conexão devido a custos monetários, limitações de dados ou problemas de desempenho da bateria.

  • NET_CAPABILITY_NOT_VPN: indica que a rede não é uma rede privada virtual.

  • NET_CAPABILITY_VALIDATED: indica que a rede fornece acesso real à Internet pública quando é sondada. Uma rede protegida por um portal cativo ou uma rede que não fornece resolução de nome de domínio não tem esse recurso. Esse é o máximo de precisão que o sistema pode ter ao indicar se uma rede está realmente fornecendo acesso. No entanto, uma rede validada ainda pode, a princípio, estar sujeita à filtragem baseada em IP ou sofrer perdas repentinas de conectividade devido a problemas, como sinal fraco.

  • NET_CAPABILITY_CAPTIVE_PORTAL: indica que a rede tem um portal cativo quando é sondada.

Há outros recursos pelos quais apps mais especializados podem se interessar. Para mais informações, leia as definições de parâmetro em NetworkCapabilities.hasCapability(int).

Os recursos de uma rede podem mudar a qualquer momento. Quando o sistema detectar um portal cativo, ele mostrará uma notificação pedindo que o usuário faça login. Enquanto isso estiver em andamento, a rede terá os recursos NET_CAPABILITY_INTERNET e NET_CAPABILITY_CAPTIVE_PORTAL, mas não o NET_CAPABILITY_VALIDATED.

Quando o usuário realizar ações e fizer login na página do portal cativo, o dispositivo poderá acessar a Internet pública. A rede passará a ter o recurso NET_CAPABILITY_VALIDATED e perderá o recurso NET_CAPABILITY_CAPTIVE_PORTAL.

Da mesma forma, os transportes de uma rede podem mudar dinamicamente. Por exemplo, uma VPN pode ser reconfigurada para usar uma rede mais rápida que acabou de ficar disponível, como alternar a rede atual de móvel para Wi-Fi. Nesse caso, a rede vai perder o transporte TRANSPORT_CELLULAR e receber o transporte TRANSPORT_WIFI, mantendo o TRANSPORT_VPN.

Ouvir eventos de rede

Para saber mais sobre eventos de rede, use a classe NetworkCallback com ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback) e ConnectivityManager.registerNetworkCallback(NetworkCallback). Esses dois métodos têm propósitos distintos.

Todos os apps Android têm uma rede padrão determinada pelo sistema. Normalmente, o sistema prefere usar as redes ilimitadas em vez das limitadas, e as redes mais rápidas em vez das lentas.

Quando um app enviar uma solicitação de rede, como HttpsURLConnection, o sistema completa essa solicitação usando a rede padrão. Os apps também podem enviar tráfego em outras redes. Para saber mais, consulte a seção sobre outras redes.

A rede definida como padrão pode mudar a qualquer momento durante o ciclo de vida de um app. Um exemplo típico seria o dispositivo entrando no alcance de um ponto de acesso Wi-Fi ilimitado, ativo e mais rápido que o sinal da rede móvel. O dispositivo se conecta a esse ponto de acesso e muda a rede padrão de todos os apps para a nova rede Wi-Fi.

Quando uma nova rede se tornar a rede padrão, qualquer nova conexão aberta por um app usará essa rede. Em algum momento posterior, todas as conexões restantes na rede padrão anterior serão encerradas à força. Se for importante que o app saiba quando a rede padrão mudar, ele precisará registrar um callback de rede padrão desta forma:

Kotlin

connectivityManager.registerDefaultNetworkCallback(object : ConnectivityManager.NetworkCallback() {
    override fun onAvailable(network : Network) {
        Log.e(TAG, "The default network is now: " + network)
    }

    override fun onLost(network : Network) {
        Log.e(TAG, "The application no longer has a default network. The last default network was " + network)
    }

    override fun onCapabilitiesChanged(network : Network, networkCapabilities : NetworkCapabilities) {
        Log.e(TAG, "The default network changed capabilities: " + networkCapabilities)
    }

    override fun onLinkPropertiesChanged(network : Network, linkProperties : LinkProperties) {
        Log.e(TAG, "The default network changed link properties: " + linkProperties)
    }
})

Java

connectivityManager.registerDefaultNetworkCallback(new ConnectivityManager.NetworkCallback() {
    @Override
    public void onAvailable(Network network) {
        Log.e(TAG, "The default network is now: " + network);
    }

    @Override
    public void onLost(Network network) {
        Log.e(TAG, "The application no longer has a default network. The last default network was " + network);
    }

    @Override
    public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
        Log.e(TAG, "The default network changed capabilities: " + networkCapabilities);
    }

    @Override
    public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
        Log.e(TAG, "The default network changed link properties: " + linkProperties);
    }
});

Quando uma nova rede se tornar a padrão, o app receberá uma chamada de onAvailable(Network) para a nova rede. Implemente onCapabilitiesChanged(Network,NetworkCapabilities), onLinkPropertiesChanged(Network,LinkProperties) ou ambos para reagir de maneira adequada a mudanças na conectividade.

Para um callback registrado com registerDefaultNetworkCallback(), onLost() significa que a rede perdeu o status de rede padrão. Ela pode estar desconectada.

Para saber mais sobre os transportes que a rede padrão está usando, consulte NetworkCapabilities.hasTransport(int). Esse é um proxy ruim em relação à largura de banda ou redes limitadas. O app não pode presumir que o Wi-Fi sempre seja ilimitado e sempre forneça uma largura de banda melhor do que a rede móvel.

Em vez disso, use NetworkCapabilities.getLinkDownstreamBandwidthKbps() para medir a largura de banda e NetworkCapabilites.hasCapability(int) com argumentos NET_CAPABILITY_NOT_METERED para determinar a limitação da rede. Para mais informações, consulte a seção NetworkCapabilities e LinkProperties.

Por padrão, os métodos de callback são chamados na linha de execução de conectividade do app, que é uma linha de execução separada usada por ConnectivityManager. Se a implementação dos callbacks precisar realizar trabalhos mais longos, chame-os em uma linha de execução de worker separada usando a variante ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback, Handler).

Chame ConnectivityManager.unregisterNetworkCallback(NetworkCallback) para cancelar o registro do seu callback quando não precisar mais usá-lo. O método onPause() da sua atividade principal é um bom lugar para fazer isso, especialmente se você registrar o callback em onResume().

Mais redes

Embora a rede padrão seja a única rede relevante para a maioria dos apps, alguns podem precisar de outras redes disponíveis. Para saber mais sobre essas redes, os apps criam uma NetworkRequest que corresponde às necessidades deles e chamam ConnectivityManager.registerNetworkCallback(NetworkRequest, NetworkCallback).

O processo é semelhante à detecção de uma rede padrão. Embora possa haver apenas uma rede padrão que se aplique a um app por vez, essa versão permite que o app verifique todas as redes disponíveis simultaneamente. Dessa forma, uma chamada para onLost(Network) significa que a rede foi completamente desconectada, e não que ela deixou de ser a rede padrão.

O app cria uma NetworkRequest para informar ao ConnectivityManager sobre o tipo de rede que ele quer detectar. O exemplo abaixo mostra como criar uma NetworkRequest para um app que está interessado apenas em conexões de Internet ilimitadas:

Kotlin

val request = NetworkRequest.Builder()
  .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
  .addCapability(NET_CAPABILITY_INTERNET)
  .build()

connectivityManager.registerNetworkCallback(request, myNetworkCallback)

Java

NetworkRequest request = new NetworkRequest.Builder()
  .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
  .addCapability(NET_CAPABILITY_INTERNET)
  .build();

connectivityManager.registerNetworkCallback(request, myNetworkCallback);

Isso significa que o app detecta todas as mudanças relacionadas a qualquer rede ilimitada no sistema.

Para o callback de rede padrão, há uma versão do registerNetworkCallback(NetworkRequest, NetworkCallback, Handler) que aceita um Handler para que ele não carregue a linha de execução Connectivity do seu app.

Chame ConnectivityManager.unregisterNetworkCallback(NetworkCallback) quando o callback não for mais relevante. Um app pode registrar simultaneamente vários callbacks de rede.

Por conveniência, o objeto NetworkRequest contém os recursos comuns que a maioria dos apps precisa, incluindo:

Ao criar seu app, verifique se padrões correspondem ao caso de uso e apague-os se quiser que o app seja notificado sobre redes que não têm esses recursos. Por outro lado, adicione recursos para evitar chamadas para qualquer mudança de conectividade nas redes com as quais o app não interage.

Por exemplo, se o app precisar enviar mensagens MMS, adicione NET_CAPABILITY_MMS ao NetworkRequest para evitar notificações sobre todas as redes que não podem enviar mensagens MMS. Adicione TRANSPORT_WIFI_AWARE se o app só tiver interesse na conectividade Wi-Fi P2P. NET_CAPABILITY_INTERNET e NET_CAPABILITY_VALIDATED são úteis se você tiver interesse em transferir dados com um servidor na Internet.

Exemplo de sequência de callbacks

Esta seção descreve a sequência de callbacks que um app pode receber se registrar um callback padrão e um callback normal em um dispositivo que tenha conectividade móvel. Neste exemplo, o dispositivo se conecta a um bom ponto de acesso Wi-Fi e depois se desconecta. O exemplo também pressupõe que o dispositivo tenha ativado a configuração Dados móveis sempre ativados.

Ocorre o seguinte:

  1. Quando o app chamar registerNetworkCallback(), o callback receberá imediatamente chamadas de onAvailable(), onNetworkCapabilitiesChanged() e onLinkPropertiesChanged() da rede móvel, porque apenas essa rede está disponível. Se outra rede estiver disponível, o app também vai receber callbacks para a outra rede.

    Diagrama de estado mostrando o registro do evento do callback da rede e os callbacks acionados pelo evento
    Figura 1. Estado do app depois de chamar registerNetworkCallback().

  2. Depois, o app chamará registerDefaultNetworkCallback(). O callback de rede padrão começa a receber chamadas para onAvailable(), onNetworkCapabilitiesChanged() e onLinkPropertiesChanged() na rede móvel porque ela é a rede padrão. Se outra rede não padrão estiver ativa, o app não vai poder receber chamadas dessa rede.

    Diagrama de estado que mostra o registro do evento de callback da rede padrão e
os callbacks acionados pelo evento
    Figura 2. Estado do app depois de registrar uma rede padrão.

  3. Em seguida, o dispositivo se conectará a uma rede Wi-Fi (ilimitada). O callback normal da rede recebe chamadas de onAvailable(), onNetworkCapabilitiesChanged() e onLinkPropertiesChanged() na rede Wi-Fi.

    Diagrama de estado mostrando os callbacks acionados quando o app se conecta a uma
nova rede
    Figura 3. Estado do app depois de se conectar a uma rede Wi-Fi ilimitada.

  4. Talvez leve algum tempo até que a rede Wi-Fi seja validada. Nesse caso, as chamadas onNetworkCapabilitiesChanged() para o callback normal da rede não incluem o recurso NET_CAPABILITY_VALIDATED. Depois de um curto período, ele recebe uma chamada para onNetworkCapabilitiesChanged(), em que os novos recursos incluem NET_CAPABILITY_VALIDATED. Na maioria dos casos, a validação é muito rápida.

    Quando a rede Wi-Fi é validada, o sistema a prioriza em relação à rede móvel, principalmente porque é ilimitada. A rede Wi-Fi se tornará a rede padrão. O callback da rede padrão vai receber uma chamada para onAvailable(), onNetworkCapabilitiesChanged() e onLinkPropertiesChanged() da rede Wi-Fi. A rede móvel será movida para o segundo plano, e o callback de rede normal vai receber uma chamada onLosing() da rede móvel.

    Como este exemplo supõe que os dados móveis estejam sempre ativados neste dispositivo, a rede móvel nunca é desconectada. Se a configuração for desativada, após um tempo a rede móvel será desconectada e o callback de rede normal vai receber uma chamada para onLost().

    Diagrama de estado mostrando os callbacks acionados quando uma conexão
de rede Wi-Fi é validada
    Figura 4. Estado do app após a validação da rede Wi-Fi.

  5. Mais tarde, o dispositivo se desconecta do Wi-Fi subitamente porque saiu do alcance. Como o Wi-Fi se desconecta, o callback de rede normal receberá uma chamada onLost() da conexão Wi-Fi. Como a rede móvel passa a ser a padrão, o callback de rede padrão receberá chamadas onAvailable(), onNetworkCapabilitiesChanged() e onLinkPropertiesChanged() da rede móvel.

    Diagrama de estado mostrando os callbacks acionados quando uma conexão
de rede Wi-Fi é perdida
    Figura 5. Estado do app após a desconexão da rede Wi-Fi.

Se a configuração Dados móveis sempre ativados estiver desativada, quando o Wi-Fi for desconectado, o dispositivo tentará se reconectar à rede móvel. O cenário é semelhante, mas com um pequeno atraso extra para as chamadas onAvailable(), e o callback de rede normal também recebe chamadas para onAvailable(), onNetworkCapabilitiesChanged() e onLinkPropertiesChanged() porque a rede móvel fica disponível.

Restrições do uso da rede para transferência de dados

Conseguir detectar uma rede com um callback de rede não significa que seu app pode usá-la para transferência de dados. Algumas redes não oferecem conectividade com a Internet e outras podem estar restritas a apps privilegiados. Para verificar a conectividade de Internet, consulte NET_CAPABILITY_INTERNET e NET_CAPABILITY_VALIDATED.

O uso de redes em segundo plano também está sujeito a verificações de permissão. Se o app quiser usar uma rede em segundo plano, ele vai precisar da permissão CHANGE_NETWORK_STATE.

Apps com essa permissão deixam o sistema tentar abrir uma rede que não esteja ativa, como a rede móvel, quando o dispositivo está conectado a uma rede Wi-Fi. Esse app chama ConnectivityManager.requestNetwork(NetworkRequest, NetworkCallback) com um NetworkCallback para ser chamado quando a rede for ativada.