Se connecter au réseau

Pour effectuer des opérations réseau dans votre application, le fichier manifeste doit inclure les autorisations suivantes :

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

Bonnes pratiques pour une communication réseau sécurisée

Avant d'ajouter une fonctionnalité de mise en réseau à votre application, vous devez vous assurer que les données et les informations qu'elle contient sont protégées lors de leur transmission via un réseau. Pour ce faire, suivez ces bonnes pratiques de sécurité réseau :

  • Réduisez au minimum la quantité de données utilisateur sensibles ou personnelles que vous transmettez sur le réseau.
  • Envoyez tout le trafic réseau de votre application via SSL.
  • Envisagez de créer une configuration de sécurité réseau qui permet à votre application d'approuver les autorités de certification personnalisées (CA) ou de limiter l'ensemble d'autorités de certification système approuvées pour une communication sécurisée.

Pour découvrir comment mettre en application les principes de mise en réseau sécurisée, consultez les conseils de sécurité pour la mise en réseau.

Choisir un client HTTP

La plupart des applications connectées au réseau utilisent le protocole HTTP pour envoyer et recevoir des données. La plate-forme Android inclut le client HttpsURLConnection, qui est compatible avec le protocole TLS, les importations et les téléchargements en streaming, les délais d'inactivité configurables, le protocole IPv6 et le pooling de connexion.

Des bibliothèques tierces proposant des API de niveau supérieur pour les opérations de mise en réseau sont également disponibles. Elles sont compatibles avec diverses fonctionnalités pratiques, telles que la sérialisation des corps de requête et la désérialisation des corps de réponse.

  • Retrofit : client HTTP de Square pour la JVM. Retrofit assure la sûreté du typage et est basé sur OkHttp. Retrofit vous permet de créer une interface cliente de manière déclarative et est compatible avec plusieurs bibliothèques de sérialisation.
  • Ktor : client HTTP de JetBrains, entièrement conçu pour Kotlin et alimenté par des coroutines. Ktor est compatible avec divers moteurs, sérialiseurs et plates-formes.

Résoudre les requêtes DNS

Les appareils équipés d'Android 10 (niveau d'API 29) ou version ultérieure intègrent la prise en charge des résolutions DNS spécialisées, à la fois en texte clair et en mode DNS sur TLS. L'API DnsResolver fournit une résolution générique et asynchrone qui vous permet de rechercher SRV, NAPTR et d'autres types d'enregistrements. L'analyse de la réponse revient à l'application.

Sur les appareils équipés d'Android 9 (niveau d'API 28) ou version antérieure, le résolveur DNS de la plate-forme n'accepte que les enregistrements A et AAAA. De cette manière, vous pouvez rechercher les adresses IP associées à un nom, mais aucun autre type d'enregistrement n'est compatible.

Pour les applications basées sur NDK, consultez android_res_nsend.

Encapsuler les opérations réseau avec un dépôt

Pour simplifier le processus d'exécution des opérations réseau et réduire la duplication de code dans différentes parties de votre application, vous pouvez utiliser le modèle de conception de dépôt. Un dépôt est une classe qui gère les opérations de données et fournit une abstraction d'API propre par rapport à des données ou des ressources spécifiques.

Vous pouvez utiliser Retrofit pour déclarer une interface spécifiant la méthode HTTP, l'URL, les arguments et le type de réponse pour les opérations réseau, comme dans l'exemple suivant :

Kotlin

interface UserService {
    @GET("/users/{id}")
    suspend fun getUser(@Path("id") id: String): User
}

Java

public interface UserService {
    @GET("/user/{id}")
    Call<User> getUserById(@Path("id") String id);
}

Dans une classe de dépôt, les fonctions peuvent encapsuler les opérations réseau et exposer leurs résultats. Cette encapsulation garantit que les composants qui appellent le dépôt n'ont pas besoin de savoir comment les données sont stockées. Toute modification future du mode de stockage des données est également isolée dans la classe du dépôt. Par exemple, vous pouvez appliquer un changement à distance, tel qu'une mise à jour des points de terminaison de l'API, ou avoir besoin d'implémenter la mise en cache locale.

Kotlin

class UserRepository constructor(
    private val userService: UserService
) {
    suspend fun getUserById(id: String): User {
        return userService.getUser(id)
    }
}

Java

class UserRepository {
    private UserService userService;

    public UserRepository(
            UserService userService
    ) {
        this.userService = userService;
    }

    public Call<User> getUserById(String id) {
        return userService.getUser(id);
    }
}

Pour éviter de créer une UI qui ne répond pas, n'effectuez pas d'opérations réseau sur le thread principal. Par défaut, Android vous demande d'effectuer les opérations réseau sur un thread autre que le thread principal. Si vous essayez d'effectuer des opérations réseau sur le thread principal, une erreur NetworkOnMainThreadException est générée.

Dans l'exemple de code précédent, l'opération réseau n'est pas réellement déclenchée. L'appelant de UserRepository doit implémenter le thread à l'aide de coroutines ou de la fonction enqueue(). Pour en savoir plus, consultez l'atelier de programmation Récupérer des données sur Internet, qui montre comment implémenter un thread à l'aide de coroutines Kotlin.

Résister aux changements de configuration

Lorsqu'un changement de configuration se produit, par exemple une rotation de l'écran, votre fragment ou votre activité est détruit, puis recréé. Toutes les données qui ne sont pas enregistrées dans l'état d'instance de votre fragment ou de votre activité, qui ne peut contenir que de petites quantités de données, sont perdues. Vous devrez donc peut-être effectuer à nouveau vos requêtes réseau.

Vous pouvez utiliser un ViewModel pour que les données résistent aux modifications de configuration. La classe ViewModel est conçue pour stocker et gérer les données liées à l'interface utilisateur tout en tenant compte du cycle de vie. À l'aide de l'élément UserRepository créé plus haut, ViewModel peut effectuer les requêtes réseau nécessaires et fournir le résultat à votre fragment ou à votre activité à l'aide de LiveData :

Kotlin

class MainViewModel constructor(
    savedStateHandle: SavedStateHandle,
    userRepository: UserRepository
) : ViewModel() {
    private val userId: String = savedStateHandle["uid"] ?:
        throw IllegalArgumentException("Missing user ID")

    private val _user = MutableLiveData<User>()
    val user = _user as LiveData<User>

    init {
        viewModelScope.launch {
            try {
                // Calling the repository is safe as it moves execution off
                // the main thread
                val user = userRepository.getUserById(userId)
                _user.value = user
            } catch (error: Exception) {
                // Show error message to user
            }

        }
    }
}

Java

class MainViewModel extends ViewModel {

    private final MutableLiveData<User> _user = new MutableLiveData<>();
    LiveData<User> user = (LiveData<User>) _user;

    public MainViewModel(
            SavedStateHandle savedStateHandle,
            UserRepository userRepository
    ) {
        String userId = savedStateHandle.get("uid");
        Call<User> userCall = userRepository.getUserById(userId);
        userCall.enqueue(new Callback<User>() {
            @Override
            public void onResponse(Call<User> call, Response<User> response) {
                if (response.isSuccessful()) {
                    _user.setValue(response.body());
                }
            }

            @Override
            public void onFailure(Call<User> call, Throwable t) {
                // Show error message to user
            }
        });
    }
}

Pour en savoir plus à ce sujet, consultez les guides associés suivants :