Lire l'état du réseau

Android permet aux applications d'en savoir plus sur les changements dynamiques de connectivité. Utilisez les classes suivantes pour suivre les changements de connectivité et y répondre :

  • ConnectivityManager indique à votre application l'état de connectivité du système.
  • La classe Network représente l'un des réseaux auxquels l'appareil est actuellement connecté. Vous pouvez utiliser l'objet Network comme clé pour recueillir des informations sur le réseau avec ConnectivityManager ou pour lier des sockets sur le réseau. Lorsque le réseau se déconnecte, l'objet Network cesse d'être utilisable. Même si l'appareil se reconnecte par la suite au même dispositif, le nouveau réseau est représenté par un nouvel objet Network.
  • L'objet LinkProperties contient des informations sur le lien d'un réseau telles que la liste des serveurs DNS, des adresses IP locales et des routes installées pour le réseau.
  • L'objet NetworkCapabilities contient des informations sur les propriétés du réseau, comme les modes de transport (Wi-Fi, mobile, Bluetooth) et les capacités de ce réseau. Par exemple, vous pouvez interroger l'objet pour déterminer si le réseau peut envoyer des MMS, s'il se trouve derrière un portail captif ou s'il est facturé à l'usage.

Les applications qui souhaitent connaître l'état de connectivité immédiat à un moment donné peuvent appeler les méthodes ConnectivityManager pour déterminer le type de réseau disponible. Ces méthodes sont utiles pour le débogage et pour examiner, de temps à autre, un instantané de la connectivité disponible à un certain moment.

Cependant, les méthodes ConnectivityManager synchrones n'informent pas votre application de ce qui se passe après un appel. Elles ne vous permettent donc pas de mettre à jour votre UI ni d'ajuster le comportement de l'application en fonction de la déconnexion du réseau ou d'un changement de ses capacités.

La connectivité peut changer à tout moment et que la plupart des applications doivent disposer d'une vue toujours actualisée de l'état du réseau sur l'appareil. Les applications peuvent enregistrer un rappel auprès avec ConnectivityManager pour être informées des modifications dont elles effectuent le suivi. Grâce à ce rappel, votre application peut réagir immédiatement à tout changement de connectivité pertinent sans avoir à recourir à des sondages coûteux pour lesquels il peut manquer des mises à jour rapides.

L'utilisation de NetworkCallback et d'autres méthodes permettant de connaître l'état de la connectivité de l'appareil ne nécessite aucune autorisation particulière. Cependant, certains réseaux sont soumis à des autorisations spécifiques. Par exemple, il peut y avoir des réseaux limités auxquels les applications n'ont pas accès. La liaison à un réseau en arrière-plan nécessite l'autorisation CHANGE_NETWORK_STATE. L'exécution de certains appels peut être soumise à des autorisations spécifiques. Pour en savoir plus, consultez la documentation spécifique à chaque appel.

Obtenir l'état instantané

Un appareil Android peut établir plusieurs connexions simultanées. Pour recevoir des informations sur l'état actuel du réseau, obtenez d'abord une instance de ConnectivityManager :

Kotlin

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

Java

ConnectivityManager connectivityManager = getSystemService(ConnectivityManager.class);

Ensuite, utilisez cette instance pour obtenir une référence au réseau par défaut actuel de votre application :

Kotlin

val currentNetwork = connectivityManager.getActiveNetwork()

Java

Network currentNetwork = connectivityManager.getActiveNetwork();

Lorsque vous faites référence à un réseau, votre application peut demander des informations à son sujet :

Kotlin

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

Java

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

Pour bénéficier de fonctionnalités plus utiles, enregistrez un NetworkCallback. Pour en savoir plus sur l'enregistrement des rappels réseau, consultez la section Écouter les événements réseau.

NetworkCapabilities et LinkProperties

Les objets NetworkCapabilities et LinkProperties fournissent des informations sur tous les attributs connus du système à propos d'un réseau.

L'objet LinkProperties connaît les routes, les adresses de lien, le nom de l'interface, les informations de proxy (le cas échéant) et les serveurs DNS. Appelez la méthode appropriée sur l'objet LinkProperties pour récupérer les informations dont vous avez besoin.

L'objet NetworkCapabilities encapsule les informations sur les transports réseau et leurs capacités.

Un transport est une abstraction d'un support physique sur lequel fonctionne un réseau. Les réseaux Ethernet, Wi-Fi et mobile sont des exemples courants de transport, tout comme les VPN et le Wi-Fi peer-to-peer. Dans Android, un réseau peut avoir plusieurs transports simultanés. C'est le cas, par exemple, d'un VPN fonctionnant à la fois sur les réseaux Wi-Fi et mobiles. Le VPN utilise alors les transports Wi-Fi, mobile et VPN. Pour savoir si un réseau est associé à un transport particulier, utilisez la méthode NetworkCapabilities.hasTransport(int) avec l'une des constantes NetworkCapabilities.TRANSPORT_*.

Une capacité décrit une propriété du réseau. MMS, NOT_METERED et INTERNET sont des exemples de capacité. Un réseau doté de la capacité MMS peut envoyer et recevoir des messages MMS, contrairement à un réseau qui n'en dispose pas. Un réseau doté de la capacité NOT_METERED ne facture pas les données à l'utilisateur. Votre application peut rechercher les capacités appropriées en utilisant la méthode NetworkCapabilities.hasCapability(int) avec l'une des constantes NetworkCapabilities.NET_CAPABILITY_*.

Les constantes NET_CAPABILITY_* les plus utiles sont les suivantes :

  • NET_CAPABILITY_INTERNET : indique que le réseau est configuré pour accéder à Internet. Il s'agit d'une configuration et non de la capacité réelle à accéder à des serveurs publics. Par exemple, un réseau peut être configuré pour accéder à Internet, tout en étant soumis à un portail captif.

    Le réseau mobile d'un opérateur offre généralement la capacité INTERNET, contrairement à un réseau Wi-Fi P2P local. Pour en savoir plus sur la connectivité réelle, consultez NET_CAPABILITY_VALIDATED.

  • NET_CAPABILITY_NOT_METERED : indique que le réseau n'est pas facturé à l'usage. Un réseau est classé comme étant facturé à l'usage lorsque l'utilisateur est sensible à une consommation intensive des données sur cette connexion en raison des coûts, des limites de données ou des problèmes de performances ou de batterie.

  • NET_CAPABILITY_NOT_VPN : indique que le réseau n'est pas un réseau privé virtuel.

  • NET_CAPABILITY_VALIDATED : indique que le réseau fournit un accès réel à l'Internet public lorsqu'il est examiné. Un réseau situé derrière un portail captif ou qui ne résout pas les noms de domaine ne dispose pas de cette capacité. C'est ce que le système peut dire de mieux sur un réseau qui fournit un accès réel, même si, en principe, un réseau validé peut toujours être soumis à un filtrage basé sur l'adresse IP ou subir des pertes de connectivité soudaines en raison de problèmes tels qu'un signal faible.

  • NET_CAPABILITY_CAPTIVE_PORTAL : indique que le réseau a un portail captif lors de la vérification.

D'autres capacités peuvent s'avérer intéressantes pour des applications plus spécialisées. Pour en savoir plus, consultez la définition des paramètres dans NetworkCapabilities.hasCapability(int).

Les capacités d'un réseau peuvent changer à tout moment. Lorsque le système détecte un portail captif, il affiche une notification invitant l'utilisateur à se connecter. Tant que cette opération est en cours, le réseau dispose des capacités NET_CAPABILITY_INTERNET et NET_CAPABILITY_CAPTIVE_PORTAL, mais pas de la capacité NET_CAPABILITY_VALIDATED.

Lorsque l'utilisateur se connecte à la page du portail captif, l'appareil est en mesure d'accéder à l'Internet public, et le réseau acquiert la capacité NET_CAPABILITY_VALIDATED et perd la capacité NET_CAPABILITY_CAPTIVE_PORTAL.

De même, les transports d'un réseau peuvent changer de façon dynamique. Par exemple, un VPN peut se reconfigurer afin d'utiliser un réseau plus rapide qui vient d'apparaître ; il peut par exemple basculer du réseau mobile vers le Wi-Fi en tant que réseau sous-jacent. Dans ce cas, le réseau perd le transport TRANSPORT_CELLULAR et acquiert le transport TRANSPORT_WIFI, tout en conservant le transport TRANSPORT_VPN.

Écouter les événements réseau

Pour découvrir les événements réseau, utilisez la classe NetworkCallback avec ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback) et ConnectivityManager.registerNetworkCallback(NetworkCallback). Ces deux méthodes ont des objectifs différents.

Toutes les applications Android disposent d'un réseau par défaut, déterminé par le système. Il préfère généralement les réseaux sans compteur à ceux qui sont facturés à l'usage et les plus rapides aux plus lents.

Lorsqu'une application émet une requête réseau, par exemple avec HttpsURLConnection, le système y répond à l'aide du réseau par défaut. Les applications peuvent également envoyer du trafic sur d'autres réseaux. Pour plus d'informations, consultez la section sur les réseaux supplémentaires.

Le réseau défini par défaut peut changer à tout moment pendant la durée de vie d'une application. C'est le cas, par exemple, lorsqu'un appareil est à portée d'un point d'accès Wi-Fi actif connu, plus rapide que le réseau mobile et sans compteur. L'appareil se connecte à ce point d'accès et remplace le réseau par défaut de toutes les applications par le nouveau réseau Wi-Fi.

Lorsqu'un nouveau réseau devient le réseau par défaut, il est utilisé par toutes les nouvelles connexions ouvertes par l'application. Par la suite, toutes les connexions restantes au réseau par défaut précédent sont arrêtées de force. S'il est important que l'application sache quand le réseau par défaut change, elle enregistre un rappel réseau par défaut comme suit :

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);
    }
});

Lorsqu'un nouveau réseau devient le réseau par défaut, l'application reçoit un appel vers onAvailable(Network) pour ce réseau. Implémentez onCapabilitiesChanged(Network,NetworkCapabilities), onLinkPropertiesChanged(Network,LinkProperties) ou les deux pour réagir de manière appropriée aux changements de connectivité.

Pour un rappel enregistré avec registerDefaultNetworkCallback(), onLost() signifie que le réseau a perdu son statut de réseau par défaut. Il est peut-être déconnecté.

Bien que vous puissiez connaître les transports utilisés par le réseau par défaut en interrogeant NetworkCapabilities.hasTransport(int), il s'agit d'un proxy de piètre qualité pour la bande passante ou la facturation à l'usage du réseau. Votre application ne doit pas partir du principe que le Wi-Fi n'est jamais facturé à l'usage et qu'il offre toujours une meilleure bande passante que le réseau mobile.

Utilisez plutôt NetworkCapabilities.getLinkDownstreamBandwidthKbps() pour mesurer la bande passante, et NetworkCapabilites.hasCapability(int) avec les arguments NET_CAPABILITY_NOT_METERED pour déterminer la facturation à l'usage. Pour en savoir plus, consultez la section NetworkCapabilities et LinkProperties.

Par défaut, les méthodes de rappel sont appelées sur le thread de connectivité de votre application, qui est un thread distinct utilisé par ConnectivityManager. Si votre implémentation des rappels doit effectuer une tâche plus longue, appelez-les sur un thread de nœud de calcul distinct en utilisant la variante ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback, Handler).

Annulez l'enregistrement de votre rappel lorsque vous n'en avez plus besoin en appelant ConnectivityManager.unregisterNetworkCallback(NetworkCallback). La méthode onPause() de votre activité principale constitue l'endroit idéal pour cela, en particulier si vous enregistrez le rappel dans onResume().

Réseaux supplémentaires

Bien que le réseau par défaut soit le seul réseau pertinent pour la plupart des applications, certaines peuvent s'intéresser à d'autres réseaux disponibles. Pour les découvrir, les applications créent une NetworkRequest répondant à leurs besoins et appellent ConnectivityManager.registerNetworkCallback(NetworkRequest, NetworkCallback).

Le processus est semblable à l'écoute d'un réseau par défaut. Cependant, bien qu'un seul réseau par défaut puisse s'appliquer à une application à un moment donné, cette version permet à votre application de voir tous les réseaux disponibles simultanément. Un appel à onLost(Network) signifie que le réseau s'est déconnecté définitivement, et non qu'il n'est plus le réseau par défaut.

L'application crée une NetworkRequest pour informer ConnectivityManager du type des réseaux qu'il souhaite écouter. L'exemple suivant montre comment créer une NetworkRequest pour une application qui ne s'intéresse qu'aux connexions Internet non facturées à l'usage :

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);

De cette façon, votre application est informée de toutes les modifications concernant les réseaux sans compteur sur le système.

Comme pour le rappel réseau par défaut, il existe une version de registerNetworkCallback(NetworkRequest, NetworkCallback, Handler) qui accepte un Handler afin de ne pas charger le thread Connectivity de votre application.

Appelez ConnectivityManager.unregisterNetworkCallback(NetworkCallback) lorsque le rappel n'est plus pertinent. Une application peut enregistrer plusieurs rappels réseau simultanément.

Pour des raisons de commodité, l'objet NetworkRequest contient les capacités courantes dont la plupart des applications ont besoin, dont :

Lorsque vous écrivez votre application, vérifiez les valeurs par défaut pour voir si elles correspondent à votre cas d'utilisation, puis supprimez-les si vous souhaitez que votre application soit informée des réseaux qui ne disposent pas de ces capacités. D'autre part, ajoutez des capacités pour éviter à votre application d'être appelée pour un changement de connectivité au niveau des réseaux avec lesquels elle n'interagit pas.

Par exemple, si votre application doit envoyer des MMS, ajoutez NET_CAPABILITY_MMS à NetworkRequest pour ne pas être informés de tous les réseaux qui ne peuvent pas envoyer de MMS. Ajoutez TRANSPORT_WIFI_AWARE si votre application ne s'intéresse qu'à la connectivité Wi-Fi P2P. NET_CAPABILITY_INTERNET et NET_CAPABILITY_VALIDATED sont utiles si vous êtes intéressé par la possibilité de transférer des données avec un serveur sur Internet.

Exemple de séquence de rappel

Cette section décrit la séquence de rappels qu'une application peut recevoir si elle enregistre à la fois un rappel par défaut et un rappel standard sur un appareil disposant d'une connexion mobile. Dans cet exemple, l'appareil se connecte à un point d'accès Wi-Fi valide, puis s'en déconnecte. Dans cette exemple, nous partons également du principe que le paramètre Données mobiles toujours activées est activé sur l'appareil.

La chronologie est la suivante :

  1. Lorsque l'application appelle registerNetworkCallback(), le rappel reçoit immédiatement des appels de onAvailable(), onNetworkCapabilitiesChanged() et onLinkPropertiesChanged() pour le réseau mobile, car il s'agit du seul réseau disponible. Si un autre réseau est disponible, l'application reçoit également des rappels pour l'autre réseau.

    Schéma d'état illustrant l'événement d'enregistrement d'un rappel réseau et les rappels déclenchés par l'événement
    Figure 1 : État de l'application après avoir appelé registerNetworkCallback()

  2. Ensuite, l'application appelle registerDefaultNetworkCallback(). Le rappel réseau par défaut commence à recevoir des appels vers onAvailable(), onNetworkCapabilitiesChanged() et onLinkPropertiesChanged() pour le réseau mobile, car il s'agit du réseau par défaut. Si un réseau autre que celui par défaut est opérationnel, l'application ne peut pas recevoir d'appels pour ce réseau.

    Schéma d'état illustrant l'événement d'enregistrement du rappel réseau par défaut et les rappels déclenchés par l'événement
    Figure 2 : État de l'application après l'enregistrement d'un réseau par défaut

  3. L'appareil se connecte ensuite à un réseau Wi-Fi (sans compteur). Le rappel réseau standard reçoit des appels vers onAvailable(), onNetworkCapabilitiesChanged() et onLinkPropertiesChanged() pour le réseau Wi-Fi.

    Schéma d'état illustrant les rappels déclenchés lorsque l'application se connecte à un nouveau réseau
    Figure 3 : État de l'application après la connexion à un réseau Wi-Fi sans compteur

  4. À ce stade, il se peut que la validation du réseau Wi-Fi prenne un certain temps. Dans ce cas, les appels onNetworkCapabilitiesChanged() concernant le rappel réseau standard n'incluent pas la capacité NET_CAPABILITY_VALIDATED. Après un court laps de temps, il reçoit un appel vers onNetworkCapabilitiesChanged(), où les nouvelles capacités incluent NET_CAPABILITY_VALIDATED. Dans la plupart des cas, la validation est très rapide.

    Une fois le réseau Wi-Fi validé, le système le préfère au réseau mobile, principalement parce qu'il n'est pas facturé à l'usage. Le réseau Wi-Fi devient le réseau par défaut. Par conséquent, le rappel réseau par défaut reçoit un appel vers onAvailable(), onNetworkCapabilitiesChanged() et onLinkPropertiesChanged() pour le réseau Wi-Fi. Le réseau mobile passe en arrière-plan, et le rappel réseau standard reçoit un appel vers onLosing() pour le réseau mobile.

    Dans cet exemple, on part du principe que les données mobiles sont toujours activées pour cet appareil. Aussi, le réseau mobile ne se déconnecte jamais. Si le paramètre est désactivé, après un certain temps, le réseau mobile se déconnecte, et le rappel réseau standard reçoit un appel vers onLost().

    Schéma illustrant les rappels déclenchés lorsqu'une connexion à un réseau Wi-Fi est validée
    Figure 4 : État de l'application après la validation du réseau Wi-Fi

  5. Par la suite, l'appareil se déconnecte soudainement du Wi-Fi, car il est hors de portée. Comme le Wi-Fi se déconnecte, le rappel réseau standard reçoit un appel à onLost() pour le Wi-Fi. Comme le réseau mobile est le nouveau réseau par défaut, le rappel par défaut reçoit des appels à onAvailable(), onNetworkCapabilitiesChanged() et onLinkPropertiesChanged() pour ce réseau.

    Schéma illustrant les rappels déclenchés lors de la perte de connexion d'un réseau Wi-Fi
    Figure 5 : État de l'application après une déconnexion du réseau Wi-Fi

Si le paramètre Données mobiles toujours activées avait été désactivé, l'appareil aurait tenté de se reconnecter au réseau mobile lors de la déconnexion du Wi-Fi. On se trouve dans le même cas de figure, mais avec un court délai supplémentaire pour les appels onAvailable(). Le rappel réseau standard reçoit également des appels vers onAvailable(), onNetworkCapabilitiesChanged() et onLinkPropertiesChanged(), car le réseau mobile est devenu disponible.

Restrictions concernant l'utilisation du réseau pour le transfert de données

Le fait qu'il soit possible de voir un réseau avec un rappel réseau ne signifie pas que votre application peut l'utiliser pour le transfert de données. Certains réseaux ne fournissent pas de connectivité Internet, et d'autres peuvent être limités à des applications privilégiées. Pour vérifier la connectivité Internet, consultez NET_CAPABILITY_INTERNET et NET_CAPABILITY_VALIDATED.

L'utilisation de réseaux en arrière-plan est également soumise à des vérifications d'autorisations. Si votre application souhaite utiliser un réseau en arrière-plan, elle a besoin de l'autorisation CHANGE_NETWORK_STATE.

Les applications disposant de cette autorisation permettent au système d'afficher un réseau qui n'est pas opérationnel, tel que le réseau mobile lorsque l'appareil est connecté à un réseau Wi-Fi. Une telle application appelle ConnectivityManager.requestNetwork(NetworkRequest, NetworkCallback) avec un NetworkCallback à appeler lors de l'activation du réseau.