Perte de connexion — l’un des phénomènes les plus courants et frustrants dans les applications mobiles. L’utilisateur perd l’accès aux données, une opération est interrompue, l’application se fige ou plante. Selon Google Android Developer Blog, 70% des utilisateurs suppriment une application si elle plante ou se fige deux fois. Examinons les causes de la perte de connexion et les moyens de construire des communications tolérantes aux pannes.
Points clés
Perte de connexion — terme utilisateur décrivant une situation où l’application perd la connexion au serveur, cesse de répondre aux actions ou se termine avec une erreur. Techniquement, cela peut être : erreur réseau (timeout, échec DNS), ANR (gel du thread UI), plantage (exception non gérée) ou condition de course (race condition).
Du point de vue de l’utilisateur, tous ces scénarios se ressemblent : l’application cesse de fonctionner. La différence pour les développeurs réside dans l’approche de diagnostic et de correction. Les erreurs réseau sont résolues avec des mécanismes de nouvelles tentatives, les ANR en déplaçant les opérations hors du thread UI, les plantages avec la gestion des exceptions.
Selon Crittercism (maintenant Apteligent), en moyenne une application mobile perd 1 à 2% de ses utilisateurs à chaque plantage. Pour une application avec 1 million d’utilisateurs, cela représente 10 à 20 mille installations perdues pour un seul bug. C’est particulièrement critique pour les applications des secteurs financier et médical.
Réseau instable — les appareils mobiles basculent constamment entre le Wi-Fi et le réseau cellulaire, entrant dans des zones sans couverture (métro, ascenseur, sous-sol). Chaque basculement provoque une perte temporaire de connexion que l’application doit gérer correctement.
Délais d’attente — si le serveur ne répond pas dans le délai imparti (généralement 10 à 30 secondes), le client lève une SocketTimeoutException. Les longs délais d’attente sans retour sont perçus par l’utilisateur comme un gel. Il est recommandé de définir un délai d’attente ne dépassant pas 15 secondes.
val client = OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build()
Condition de course (race condition) — se produit lorsque plusieurs threads lisent et écrivent simultanément les mêmes données sans synchronisation. Par exemple, charger des données depuis le cache dans le thread UI tout en mettant à jour le cache depuis le réseau peut entraîner l’affichage de données obsolètes ou incorrectes.
Offline-first — un modèle architectural où le stockage local (Room, CoreData) est la seule source de vérité. Le réseau est utilisé pour la synchronisation des données en arrière-plan. L’utilisateur voit toujours des données à jour depuis le cache local, même sans connexion réseau.
Modèle Repository — un point d’entrée unique pour les données qui décide d’aller chercher les données depuis le réseau ou le cache. Le repository abstrait la source de données du ViewModel et de l’UI. En cas d’erreur réseau, le repository bascule automatiquement vers la source locale.
class UserRepository(
private val api: UserApi,
private val dao: UserDao
) {
suspend fun getUsers(): Result<List<User>> {
return try {
val remote = api.fetchUsers()
dao.insertAll(remote)
Result.success(remote)
} catch (e: IOException) {
val cached = dao.getAll()
if (cached.isNotEmpty()) {
Result.success(cached) // return cache on network error
} else {
Result.failure(e)
}
}
}
}
Circuit Breaker — un modèle qui protège le serveur d’une avalanche de requêtes lorsqu’il est indisponible. Après N erreurs consécutives, le disjoncteur s’ouvre et toutes les requêtes retournent immédiatement une erreur sans tenter la connexion. Après un délai déterminé, le disjoncteur passe à un état semi-ouvert pour une requête de test.
Backoff exponentiel — un mécanisme de nouvelle tentative standard. Après le premier échec, attendez 1 seconde ; après le deuxième, 2 secondes ; puis 4, 8, 16. Limitez le nombre maximal de tentatives (généralement 3 à 5) pour ne pas surcharger le serveur et la batterie.
Retour utilisateur — en cas d’erreur réseau, affichez un message clair : « Pas de connexion », « Serveur temporairement indisponible », « Vérifiez votre connexion Internet ». Utilisez Snackbar ou Inline State View. Ne montrez jamais d’erreurs techniques (HTTP 500, SocketException) à l’utilisateur.
ConnectivityManager — API Android pour la surveillance du réseau. Permettez à l’application de réagir aux changements : afficher un espace réservé en cas de perte de connexion, actualiser automatiquement les données lors de la restauration. Sous iOS, utilisez NWPathMonitor du framework Network.
class NetworkMonitor(private val context: Context) {
private val manager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
fun isOnline(): Boolean {
val network = manager.activeNetwork ?: return false
val caps = manager.getNetworkCapabilities(network) ?: return false
return caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
}
}
Crashlytics (Firebase) — un outil standard de signalement des plantages pour applications mobiles. Il collecte les stacktraces de toutes les exceptions non gérées, la version de l’OS, le modèle de l’appareil et l’heure du plantage. Il permet de regrouper les erreurs et d’attribuer des responsables pour les corrections.
Sentry — une alternative à Crashlytics avec prise en charge de la surveillance des performances. Il permet de tracer des transactions spécifiques (par exemple, « autorisation utilisateur ») et de voir à quelle étape une erreur s’est produite. Le tracing des performances aide à distinguer les timeouts réseau des bugs dans la logique de l’application.
Timber — une bibliothèque de journalisation pour Android avec ajout automatique de balises par classe. Dans les builds de débogage, enregistrez toutes les requêtes et réponses réseau. Dans les builds de release, enregistrez uniquement les erreurs et avertissements via Crashlytics.setCustomLog.
| Outil | Type | Quand l’utiliser |
|---|---|---|
| Crashlytics | Signalement de plantages | Toujours en release — collecte automatique des plantages |
| Sentry | Plantage + Performance | Lorsque vous devez profiler des scénarios utilisateur spécifiques |
| Timber | Journalisation | Debug : journalisation complète ; Release : erreurs uniquement |
| HTTP Toolkit | Débogage réseau | Interception et analyse locale du trafic HTTP |
Selon Firebase Summit 2023, les applications qui ont implémenté Crashlytics + Performance Monitoring réduisent le temps moyen de détection et de correction des bugs critiques de 3 jours à 4 heures. Il est recommandé de configurer des alertes pour chaque plantage avec une fréquence supérieure à 0,1% des utilisateurs actifs.
Questions fréquentes
Si un plantage n’est pas détecté dans Crashlytics, vérifiez les plantages natifs (SIGSEGV, SIGABRT) — ils ne sont pas traités par le gestionnaire d’exceptions Java/Kotlin. Sous Android, cela pourrait être une fuite de mémoire native du JNI ; sous iOS, EXC_BAD_ACCESS. Utilisez Breakpad (Android) ou PLCrashReporter (iOS) pour collecter les stacktraces de plantages natifs.
Utilisez Network Link Conditioner (intégré dans iOS ; pour Android, utilisez Facebook Network Connection Class ou Developer Options > Network > Select network type). Définissez un délai de 500 à 3000 ms et une perte de paquets de 5 à 30%. Vous pouvez également utiliser Charles Proxy ou mitmproxy pour simuler la latence réseau et les déconnexions.
ANR se produit si le thread UI est bloqué pendant plus de 5 secondes. Les requêtes réseau doivent être exécutées dans un thread d’arrière-plan : coroutines (viewModelScope.launch(Dispatchers.IO)), RxJava (subscribeOn(Schedulers.io)), ou WorkManager pour la synchronisation. Définissez toujours des timeouts sur le client HTTP — l’absence de timeout peut entraîner un blocage permanent.
Condition de course — une situation où le résultat d’une opération dépend de l’ordre d’exécution des threads. Par exemple, un utilisateur appuie rapidement deux fois sur le bouton « Envoyer » et la requête est envoyée deux fois. Solution : utilisez Mutex, des exécuteurs monotâche ou une machine à états (désactivez le bouton après le premier clic). En Kotlin, utilisez Mutex des coroutines ou l’annotation @Synchronized.
Appliquez Chaos Engineering pour les applications mobiles : déconnectez le réseau pendant les opérations, simulez une latence élevée, basculez entre Wi-Fi et réseau cellulaire, tuez le processus via le système. Outils : Facebook Network Connection Class, Charles Proxy, iOS Network Link Conditioner. Dans CI/CD, ajoutez des tests UI avec différentes conditions réseau via AndroidTest Orchestrator.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi