Sync Engine — est un composant d’application responsable de la mise à jour cohérente des données entre le stockage local de l’appareil et un serveur distant. Dans les applications mobiles, Sync Engine assure le fonctionnement hors ligne, la synchronisation en arrière-plan et la résolution des conflits. Selon Google Firebase (2025), les applications avec Sync Engine intégré montrent une rétention 25% supérieure dans les régions avec une connexion instable.
Points clés
Sync Engine — est une couche architecturale entre la base de données locale et une API distante qui gère le flux de données dans les deux sens. Ses tâches : suivre les modifications, les envoyer au serveur, recevoir les modifications du serveur et résoudre les conflits. L’utilisateur interagit avec les données locales, tandis que Sync Engine les synchronise de manière transparente avec le serveur.
Sync Engine peut être intégré (Firebase Firestore, Couchbase Lite, Realm) ou personnalisé — écrit pour une logique métier spécifique. Les moteurs intégrés offrent des fonctionnalités offline-first et une résolution des conflits prêtes à l’emploi. Les moteurs personnalisés offrent un contrôle total sur le format des données, le protocole de synchronisation et la politique de conflit.
Selon Sravana Karthik (2024), auteur de « Mobile Sync Engine Design Patterns », un Sync Engine personnalisé est justifié pour les applications avec une logique métier complexe (finance, santé, IoT) où les règles de fusion personnalisées sont critiques. Pour les scénarios typiques (notes, chats, fils d’actualité), un Firestore ou Realm intégré suffit.
interface SyncEngine {
suspend fun pull(lastSyncTimestamp: Long): SyncResult
suspend fun push(operations: List<QueuedOperation>): PushResult
suspend fun resolve(conflicts: List<Conflict>): ResolutionResult
fun observeSyncState(): Flow<SyncState>
}
Cette interface décrit le contrat minimal de Sync Engine : pull (chargement des modifications du serveur), push (envoi des modifications locales), resolve (gestion des conflits) et observe (surveillance de l’état de synchronisation). Cette abstraction permet de changer l’implémentation sans modifier la couche de présentation.
Synchronisation complète (Full sync) — chaque session charge l’ensemble complet des données du serveur. Simple à implémenter, mais inacceptable pour les grands volumes : télécharger 10 000 enregistrements à chaque ouverture de l’application consomme du trafic et de la batterie. La synchronisation complète est justifiée pour les données de référence (liste des pays) avec des mises à jour rares.
Synchronisation incrémentale — seuls les enregistrements modifiés depuis la dernière synchronisation sont transférés. Le serveur stocke l’horodatage de la dernière modification pour chaque enregistrement ou pour l’ensemble complet. Le client envoie lastSyncTimestamp et reçoit uniquement les enregistrements avec updated_at > cette valeur. Selon Instagram Engineering (2024), la synchronisation incrémentale réduit le volume de données transférées de 97% par rapport à la synchronisation complète.
Synchronisation push (initiée par le serveur) — le serveur lui-même notifie le client de la nécessité de synchroniser via FCM (Firebase Cloud Messaging), WebSocket ou SSE (Server-Sent Events). Le client ne gaspille pas de ressources en polling périodique. La synchronisation push est le choix optimal pour les applications en temps réel : chats, notifications, likes. Google Firebase Firestore utilise WebSocket pour la synchronisation en temps réel avec basculement automatique vers HTTP polling.
| Type | Trafic | Latence | Complexité | Application |
|---|---|---|---|---|
| Complète | Élevé | Élevée | Faible | Répertoires, configurations |
| Incrémentale | Faible | Faible | Moyenne | Flux, catalogues, profils |
| Push | Minimal | Minimale | Élevée | Chats, notifications, collaboration |
Approche hybride — une combinaison des types : synchronisation complète pour les données de base au démarrage de l’application, puis synchronisation incrémentale pour les mises à jour, et pour les événements critiques — synchronisation push via FCM. Cela offre à la fois rapidité et économie de ressources.
Point de contrôle (Checkpoint) — une valeur que le client stocke entre les sessions de synchronisation. C’est généralement le updated_at du dernier enregistrement synchronisé avec succès. À la synchronisation suivante, le client envoie le point de contrôle au serveur, et le serveur retourne tous les enregistrements avec updated_at postérieur au point de contrôle. Pagination basée sur curseur — une version avancée où le serveur retourne un curseur (pointeur vers la page suivante) avec les données.
Synchronisation delta — le serveur calcule la différence entre l’état actuel des données et l’instantané que le client a vu pour la dernière fois. Au lieu d’envoyer tous les enregistrements, seules les opérations (insert, update, delete) sont transférées. C’est particulièrement efficace pour les grands ensembles de données où seuls quelques enregistrements ont été modifiés. API Google Drive (2025) utilise changes.list avec pageToken pour la synchronisation delta des fichiers.
Stratégie des « deltas différés » — sur le client mobile, les modifications ne sont pas envoyées immédiatement mais mises en mémoire tampon dans la file d’attente hors ligne. Lorsque le seuil est atteint (10 opérations ou 30 secondes), un paquet delta est formé et envoyé au serveur. Selon Dropbox Mobile Engineering (2024), le traitement par lots des deltas a réduit le nombre de requêtes HTTP de 65% et la consommation de batterie de 12%.
data class SyncCheckpoint(
val lastUpdated: Long,
val pageToken: String?,
val version: Int
)
suspend fun syncIncremental(checkpoint: SyncCheckpoint): SyncResult =
api.pullChanges(
since = checkpoint.lastUpdated,
token = checkpoint.pageToken
)
SyncCheckpoint stocke à la fois l’horodatage et le curseur de pagination pour les longues listes. Point de contrôle à deux paramètres garantit qu’aucun enregistrement n’est sauté ou dupliqué lors de la synchronisation de grands ensembles de données.
WebSocket — une connexion bidirectionnelle persistante entre le client et le serveur. Le serveur envoie les mises à jour immédiatement lorsque les données changent. WebSocket est optimal pour les applications en temps réel : chats, streaming, travail collaboratif. Inconvénient : consommation de batterie et de trafic pour maintenir la connexion (heartbeat). OkHttp WebSocket sur Android et URLSessionWebSocketTask sur iOS — implémentations intégrées.
Firebase Cloud Messaging (FCM) — des notifications push que le serveur envoie non pas pour les afficher à l’utilisateur, mais pour déclencher la synchronisation. À la réception d’un silent push (message de données), l’application se réveille et démarre Sync Engine. FCM ne nécessite pas de connexion permanente et est plus économique que WebSocket pour les notifications rares.
SSE (Server-Sent Events) — un canal unidirectionnel par lequel le serveur envoie des événements au client. Plus simple à implémenter que WebSocket, mais ne prend pas en charge la communication bidirectionnelle. EventSource API (JavaScript) et OkHttp SSE (Android) — des bibliothèques populaires. SSE convient aux notifications concernant de nouvelles données lorsque le client n’a pas besoin de renvoyer des données via le même canal.
Selon WhatsApp Engineering (2024), leur Sync Engine utilise une combinaison de WebSocket pour les sessions actives et de FCM pour réveiller l’application en arrière-plan : WebSocket se déconnecte après 5 minutes d’inactivité, et les mises à jour ultérieures sont livrées via silent push.
Synchronisation basée sur les instantanés — le serveur crée périodiquement un instantané complet des données et lui attribue une version. Le client stocke le numéro de version actuel. S’il est obsolète — il télécharge un nouvel instantané. C’est une stratégie simple et fiable, mais inefficace pour les changements fréquents — chaque fois l’ensemble complet des données est téléchargé.
Versionnage par enregistrement — chaque enregistrement a un champ version. Lors de la synchronisation, le client envoie les versions de tous les enregistrements, et le serveur retourne uniquement ceux dont la version a changé. C’est plus efficace que la synchronisation par instantanés, mais nécessite le stockage des versions sur le client. Horloges vectorielles (Vector Clocks) — une technique avancée pour les systèmes distribués où chaque nœud attribue sa propre version et les conflits sont résolus par ordre partiel.
Instantané avec diff incrémental — une approche hybride : des instantanés complets rares (une fois par jour) + synchronisation incrémentale entre eux. Au démarrage après une longue absence, le client charge un instantané, et lors de synchronisations fréquentes — uniquement des deltas. Approche de type Git — chaque commit de données a un hachage, et le client sait de quel commit partir. Ceci est implémenté dans Couchbase Lite Sync Gateway (2024) et est la référence en matière de fiabilité.
data class VersionedEntryT(
val id: String,
val data: T,
val version: Long,
val deleted: Boolean
)
fun SyncEngine.resolveVersion(local: VersionedEntry*, remote: VersionedEntry*): VersionedEntry* =
when {
local.version > remote.version -> local
remote.version > local.version -> remote
else -> resolveConflict(local, remote)
}
Règle de résolution de version : si les versions correspondent — aucun changement. Si la version locale est plus récente — la locale gagne. Si la version du serveur est plus récente — le serveur gagne. Ce n’est que lorsque les versions sont égales mais les données différentes — que le résolveur de conflits est appelé. Last Write Wins avec un indicateur de version — la stratégie la plus simple mais fiable.
Étape 1 : Définir le modèle de données — quelles entités sont synchronisées, leur fréquence de modification et leur volume. Pour chaque entité, définir la stratégie (incrémentale / complète / push) et le délai de synchronisation acceptable.
Étape 2 : Choisir un protocole — REST avec points de contrôle, GraphQL avec Subscriptions ou gRPC avec flux bidirectionnel. GraphQL Subscriptions — un choix populaire pour les applications modernes : un seul protocole pour le pull et le push. Apollo Client (2025) prend en charge la synchronisation hors ligne via le cache de l’appareil.
Étape 3 : Implémenter une file d’attente hors ligne — stockage local des modifications avec clés d’idempotence (voir l’article « Offline Queue »). La file d’attente est le fondement d’un Sync Engine fiable : sans elle, la synchronisation ne garantit pas la livraison des modifications.
Étape 4 : Choisir un résolveur de conflits — LWW pour les cas simples, CRDT pour l’édition collaborative, fusion personnalisée pour la logique métier. Règle : le résolveur doit être idempotent — la réapplication de la même opération doit produire le même résultat.
Étape 5 : Surveillance et métriques — journaliser chaque synchronisation : nombre d’enregistrements, temps d’exécution, nombre de conflits, erreurs. Firebase Crashlytics ou Sentry (2025) permettent de suivre les erreurs de synchronisation en temps réel.
Selon Realm Team (2024), un Sync Engine typique pour application mobile traite 100–500 synchronisations par jour par appareil, transférant en moyenne 50–200 Ko de données par session. Optimisation du protocole — utiliser la compression Protobuf au lieu de JSON — réduit le volume de données transférées de 40–60% supplémentaires.
Questions fréquentes
Client API exécute des requêtes uniques et retourne un résultat. Sync Engine gère l’état des données : suit les modifications, les met en mémoire tampon hors ligne, synchronise en arrière-plan et résout les conflits. Sync Engine = Client API + base de données locale + gestionnaire de file d’attente + résolveur de conflits.
Fréquence optimale dépend du type de données : critiques (messages, commandes) — via push sync en temps réel ; non critiques (flux, notifications) — synchronisation incrémentale toutes les 15–30 minutes. WorkManager PeriodicWorkRequest permet de configurer l’intervalle sur Android en tenant compte du mode Doze.
Stratégie automatique — Last Write Wins (selon l’horodatage du serveur). Si cela est inacceptable — CRDT ou fusion personnalisée sur le serveur. En dernier recours — conserver les deux versions et proposer le choix à l’utilisateur. Règle principale : ne jamais perdre les données de l’utilisateur lors de la résolution d’un conflit.
Firebase Firestore — le meilleur choix pour les applications typiques (chats, flux, réseaux sociaux). Il fournit offline-first, synchronisation en temps réel et résolution des conflits prêts à l’emploi. Sync Engine personnalisé est justifié pour une logique métier spécifique, des exigences de confidentialité des données ou une intégration avec un serveur existant.
Tests unitaires — serveur mock avec réponses prévisibles, test de la file d’attente hors ligne et du résolveur de conflits. Tests d’intégration — serveur réel dans un environnement de test, simulation des retards réseau avec Network Link Conditioner. Tests E2E — deux appareils se synchronisant via un compte, vérification de la cohérence des données après une série d’opérations.
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