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 no momento. Use o objetoNetwork
como uma chave para coletar informações sobre a rede comConnectivityManager
ou para vincular soquetes na rede. Quando a rede é desconectada, o objetoNetwork
não pode mais ser usado, mesmo que o dispositivo se conecte novamente à mesma rede. Um novo objetoNetwork
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, celular, 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 e 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 a qualquer momento. No entanto, os métodos síncronos
ConnectivityManager
não informam o app sobre o que acontece
após uma chamada. Eles não permitem atualizar a IU nem ajustar o comportamento
do app com base na desconexão da rede ou quando os recursos da rede
mudarem.
Como 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.
Como receber o estado instantâneo
Um dispositivo Android pode manter muitas conexões ao mesmo tempo. Primeiro, acesse
uma instância do ConnectivityManager
:
Kotlin
val connectivityManager = getSystemService(ConnectivityManager::class.java)
Java
ConnectivityManager connectivityManager = getSystemService(ConnectivityManager.class);
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á consultar 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);
A consulta de estado instantâneo não é útil para a maioria dos apps, exceto para
depuração. Para recursos mais úteis, como receber alertas quando novas
redes forem disponibilizadas e se redes forem desconectadas, registre um
NetworkCallback
.
Para descobrir como registrar callbacks de rede, consulte
Como detectar 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 recuperar 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 celular, mas também podem incluir VPN ou Wi-Fi ponto a ponto.
No Android, uma rede pode ter vários transportes ao mesmo tempo. Um exemplo
disso seria uma VPN operando em redes Wi-Fi e celular. Essa
rede teria os transportes Wi-Fi, celular e VPN. Para descobrir se uma
rede tem um transporte específico, use
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. Uma rede com o recurso NOT_METERED
não cobra o
usuário pelo uso de dados. O app pode verificar os recursos apropriados usando o método
NetworkCapabilities.hasCapability(int)
com uma das constantes NetworkCapabilities.NET_CAPABILITY_*
.
As constantes NET_CAPABILITY_*
mais úteis incluem:
NET_CAPABILITY_INTERNET
: esse recurso 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 celular de uma operadora costuma ter o recurso
INTERNET
, enquanto uma rede Wi-Fi P2P local normalmente não tem. Para ver a conectividade real, consulteNET_CAPABILITY_VALIDATED
.NET_CAPABILITY_NOT_METERED
: esse recurso 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 bateria/desempenho.NET_CAPABILITY_NOT_VPN
: esse recurso indica que a rede não é uma rede privada virtual.NET_CAPABILITY_VALIDATED
: esse recurso indica que, na última vez que foi sondada, foi confirmado que a rede pode fornecer acesso real à Internet pública. 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 a filtragem baseada em IP ou sofrer perdas repentinas de conectividade devido a problemas, como sinal fraco.NET_CAPABILITY_CAPTIVE_PORTAL
: esse recurso indica que, na última vez que foi sondada, foi detectado que a rede tem um portal cativo.
Há outros recursos pelos quais apps mais especializados podem se interessar.
Leia as definições de parâmetro em
NetworkCapabilities.hasCapability(int)
para conferir mais informações.
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 a 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 celular
para Wi-Fi. Nesse caso, a rede perderá o transporte TRANSPORT_CELLULAR
e receberá o transporte TRANSPORT_WIFI
, mantendo o
TRANSPORT_VPN
.
Como detectar 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. O sistema decide qual será
a rede padrão. 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 mais informações, consulte Mais
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 celular. O dispositivo se conectaria a esse ponto de acesso e alternaria 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 da seguinte 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 apropriada 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
ou não ter sido 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 celular. 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. Consulte
NetworkCapabilities e LinkProperties para saber mais
informações.
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 um NetworkRequest
que corresponde às
necessidades deles e chamam
ConnectivityManager.registerNetworkCallback(NetworkRequest, NetworkCallback)
. O processo é semelhante à detecção
de uma rede padrão. A principal diferença é que, embora possa haver apenas uma
rede padrão que se aplique a um app por vez, essa versão permite que o
app veja 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. Por exemplo, se o app estiver 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 garante que o app detecte todas as mudanças relacionadas a qualquer rede ilimitada no sistema.
Para o callback de rede padrão, há uma versão de
registerNetworkCallback(NetworkRequest, NetworkCallback, Handler)
que aceita um Handler
para não carregar a linha de execução Connectivity
do
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 escrever o código do app, verifique se os padrões correspondem ao seu caso de uso e apague-os caso o app também precise ser notificado sobre redes que não têm esses recursos. Por outro lado, seu app precisa adicionar recursos para evitar ser chamado 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
à NetworkRequest
para evitar receber notificações sobre todas as redes que não podem
enviar mensagens MMS ou
TRANSPORT_WIFI_AWARE
se ele estiver interessado apenas 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.
Um exemplo
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. A seção também pressupõe que o dispositivo tenha ativado a configuração Dados móveis sempre ativados.
O cronograma é o seguinte:
Quando o app chamar
registerNetworkCallback()
, o callback receberá imediatamente chamadas deonAvailable()
,onNetworkCapabilitiesChanged()
eonLinkPropertiesChanged()
da rede celular, porque apenas essa rede está disponível. Se outra rede estivesse disponível, o app também teria recebido callbacks para a outra rede.
Figura 1. Estado do app depois de chamarregisterNetworkCallback()
.Depois, o app chamará
registerDefaultNetworkCallback()
. O callback de rede padrão começa a receber chamadas deonAvailable()
,onNetworkCapabilitiesChanged()
eonLinkPropertiesChanged()
para a rede celular porque ela é a rede padrão. Se outra rede não padrão estivesse ativa, o app não teria recebido chamadas para a rede não padrão.
Figura 2. Estado do app depois de registrar uma rede padrão.Em seguida, o dispositivo se conectará a uma rede Wi-Fi (ilimitada). O callback normal da rede recebe chamadas de
onAvailable()
,onNetworkCapabilitiesChanged()
eonLinkPropertiesChanged()
para a rede Wi-Fi.
Figura 3. Estado do app depois de se conectar a uma rede Wi-Fi ilimitada.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 incluiriam o recursoNET_CAPABILITY_VALIDATED
. Depois de um curto período, ele receberia uma chamada paraonNetworkCapabilitiesChanged()
, em que os novos recursos incluiriamNET_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 celular, principalmente porque é ilimitada. A rede Wi-Fi se tornará a rede padrão. Portanto, o callback da rede padrão vai receber uma chamada para
onAvailable()
,onNetworkCapabilitiesChanged()
eonLinkPropertiesChanged()
da rede Wi-Fi. A rede celular será movida para o segundo plano, e o callback de rede normal vai receber uma chamadaonLosing()
da rede celular.Como este exemplo supõe que os dados móveis estejam sempre ativados neste dispositivo, a rede móvel nunca é desconectada. Se essa configuração estivesse desativada, depois de um tempo a rede celular seria desconectada e o callback de rede normal receberia uma chamada para
onLost()
.
Figura 4. Estado do app após a validação da rede Wi-Fi.Mais tarde, o dispositivo se desconecta do Wi-Fi subitamente porque saiu do alcance. Como o Wi-Fi está desconectado, o callback de rede normal vai receber uma chamada
onLost()
da conexão Wi-Fi. Como a rede celular passa a ser nova rede padrão, o callback de rede padrão receberá chamadasonAvailable()
,onNetworkCapabilitiesChanged()
eonLinkPropertiesChanged()
da rede celular.
Figura 5. Estado do app após a desconexão da rede Wi-Fi.
Se a configuração Dados móveis sempre ativados estivesse desativada, quando o Wi-Fi
fosse desconectado, o dispositivo tentaria se reconectar à rede celular. O cenário seria
semelhante, mas com um pequeno atraso extra para as chamadas onAvailable()
, e
o callback de rede normal também receberia chamadas para onAvailable()
,
onNetworkCapabilitiesChanged()
e onLinkPropertiesChanged()
porque a rede
celular seria a única 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 (consulte
NET_CAPABILITY_INTERNET
e
NET_CAPABILITY_VALIDATED
para verificar a conectividade com a Internet) e algumas redes podem estar restritas a
apps privilegiados.
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
. Os apps com essa permissão também podem pedir que o sistema tente
abrir uma rede que não está ativa no momento, como a rede celular quando
o dispositivo estiver conectado a uma rede Wi-Fi. Esse app pode chamar
ConnectivityManager.requestNetwork(NetworkRequest, NetworkCallback)
e, quando a rede estiver ativa, um NetworkCallback
.