Une notification push est une alerte livrée par l’OS qui atteint les apps fermées ; une live query diffuse les changements tant que l’app est ouverte. Les présenter comme rivales est l’erreur classique — elles couvrent des états disjoints de l’app, et la vraie question de conception n’est pas « laquelle ? » mais « où se trouve l’utilisateur en ce moment ? ». La plupart des apps qui donnent une vraie impression de temps réel utilisent les deux et aiguillent selon cette réponse.
Points clés
| Question | Réponse |
|---|---|
| Notifications push | Livraison par la passerelle de l’OS (APNs, FCM) — atteint les apps fermées, payload opaque de ~4 Ko, au mieux |
| Live queries | Abonnement WebSocket — objets complets aux permissions vérifiées, temps réel, l’app doit être ouverte |
| La rivalité | Fausse — elles servent des états disjoints de l’app et se combinent au lieu de se concurrencer |
| La règle d’aiguillage | App ouverte → live query · app fermée → push · tap sur le push → ouverture, réabonnement, rattrapage |
| Le mode d’échec | Utiliser le push comme canal de données, ou attendre des sockets qu’ils survivent au processus |
Les deux canaux, en code
Le pattern vers lequel convergent presque toutes les apps de messagerie, de commande et d’alerte :
// JavaScript — Back4app JS SDK: one channel per app state
// While the app is OPEN — the live query delivers the data itself
const messages = new Parse.Query('Message');
messages.equalTo('conversation', conversationId);
const sub = await messages.subscribe();
sub.on('create', (m) => appendBubble(m)); // full object, real time
// While it is CLOSED — push owns delivery: register this device
const installation = await Parse.Installation.currentInstallation();
installation.set('channels', [`user-${currentUser.id}`]);
await installation.save();
// A Cloud Code afterSave trigger sends the push to this channel —
// the OS shows the alert; the tap opens the app, which re-subscribes. // Flutter / Dart — Back4app Flutter SDK: one channel per app state
// While the app is OPEN — the live query delivers the data itself
final liveQuery = LiveQuery();
final messages = QueryBuilder<ParseObject>(ParseObject('Message'))
..whereEqualTo('conversation', conversationId);
final sub = await liveQuery.client.subscribe(messages);
sub.on(LiveQueryEvent.create, (m) => appendBubble(m)); // full object
// While it is CLOSED — push owns delivery: register this device
final installation = await ParseInstallation.currentInstallation();
installation.set('channels', ['user-$userId']);
await installation.save();
// A Cloud Code afterSave trigger sends the push to this channel —
// the OS shows the alert; the tap opens the app, which re-subscribes. // iOS / Swift — Back4app Swift SDK: one channel per app state
// While the app is OPEN — the live query delivers the data itself
let messages = Message.query("conversation" == conversationId)
let subscription = messages.subscribeCallback
subscription?.handleEvent { _, event in
if case .created(let m) = event { appendBubble(m) } // full object
}
// While it is CLOSED — push owns delivery: register this device
var installation = Installation.current
installation?.channels = ["user-\(userId)"]
installation?.save { _ in }
// A Cloud Code afterSave trigger sends the push to this channel —
// the OS shows the alert; the tap opens the app, which re-subscribes. // Android / Kotlin — Back4app Android SDK: one channel per app state
// While the app is OPEN — the live query delivers the data itself
val client = ParseLiveQueryClient.Factory.getClient()
val messages = ParseQuery.getQuery<ParseObject>("Message")
messages.whereEqualTo("conversation", conversationId)
val sub = client.subscribe(messages)
sub.handleEvent(SubscriptionHandling.Event.CREATE) { _, m ->
appendBubble(m) // full object
}
// While it is CLOSED — push owns delivery: register this device
val installation = ParseInstallation.getCurrentInstallation()
installation.put("channels", listOf("user-$userId"))
installation.saveInBackground()
// A Cloud Code afterSave trigger sends the push to this channel. Notez ce que gère chaque moitié : l’abonnement livre des données — objets entiers, événements typés, en temps réel. L’installation s’enregistre pour obtenir de l’attention — le droit d’interrompre l’utilisateur plus tard, via un pipeline que votre app ne contrôle pas.
Deux livraisons, deux propriétaires
Les chemins ne pourraient guère être plus différents, et chaque propriété du tableau comparatif découle de qui possède le dernier kilomètre.
Une notification push quitte votre backend sous forme de requête vers une passerelle exploitée par l’OS — les passerelles push d’iOS et d’Android (APNs, FCM), ou un service push de navigateur parlant RFC 8030 sur le web. La passerelle possède la livraison : elle conserve les messages destinés aux appareils hors ligne, regroupe et limite sous la pression de la batterie, et réveille votre app ou affiche la bannière. Ce pouvoir emprunté est tout l’intérêt — seul l’OS peut atteindre un processus qui ne tourne pas — et toute la contrainte : payloads plafonnés à environ 4 Ko, livraison au mieux, réveils silencieux en arrière-plan rationnés par jour, et un payload hors du modèle de permissions de votre backend.
Une live query ne quitte jamais votre périmètre de confiance : l’app maintient un WebSocket vers le serveur d’abonnements du backend, qui confronte chaque écriture en base à la requête abonnée et pousse des événements typés — create, update, enter, leave, delete — avec des ACL appliquées par abonné. Objets complets, latence temps réel, aucun plafond de payload digne de ce nom. En échange, la dépendance est brutale : l’abonnement est un état à l’intérieur de votre processus, et quand l’OS suspend l’app — ce que les plateformes mobiles font agressivement — le socket, et le canal avec lui, disparaissent.
Notifications push vs. live queries
| Notifications push | Abonnements live query | |
|---|---|---|
| Atteint une app fermée | Oui — le pouvoir qui les définit | Non — l’abonnement meurt avec le processus |
| Payload | ~4 Ko, opaque pour vos ACL | Objets complets, permissions vérifiées par abonné |
| Garantie de livraison | Au mieux ; regroupable, limitable, abandonnable | Fiable tant que connecté ; rattrapage nécessaire après une coupure |
| Latence | De l’ordre de la seconde, selon la passerelle | Temps réel (~RTT) |
| Propriétaire du transport | L’OS et sa passerelle | La flotte de WebSockets de votre backend |
| Consentement de l’utilisateur | Demande d’autorisation ; révocable par l’utilisateur | Aucun — ce ne sont que les données de votre app |
| Coût d’un mauvais usage | Lassitude des notifications, désinstallations | Charge sur la batterie et les sockets en cas de sur-abonnement |
| Conçu pour | L’attention et le réengagement | Les données et l’état dans l’app |
Les lignes se combinent proprement parce que les deux canaux répondent à des questions différentes : le push répond à « comment atteindre l’utilisateur ? », les live queries à « comment l’écran reste-t-il fidèle ? » — c’est pourquoi la comparaison au niveau du transport entre SSE, WebSockets et polling se situe entièrement dans la seconde question.
Le passage de relais : là où les apps cassent vraiment
Les bugs se logent à la jointure entre les canaux. Un utilisateur tape sur un push concernant un message qui a aussi été livré par live query avant la suspension de l’app — dédupliquez par ID d’objet, pas par canal. Un push arrive au sujet de données auxquelles l’utilisateur n’a plus accès — récupérez-les via l’API normale à l’ouverture et laissez les ACL trancher, ne faites jamais confiance au payload. L’app est restée fermée trois jours — l’app rouverte ne peut pas rejouer le trou à partir des push (les notifications ne sont pas un journal), donc le passage de relais consiste toujours à se réabonner, puis relancer la requête de base pour reconstruire la vérité, tout en gardant à jour en arrière-plan l’enregistrement du token push. Concevez la jointure une fois et les deux canaux deviennent ennuyeux — c’est exactement l’objectif.
Cas d’usage courants
- Chat et messagerie — la live query affiche la conversation ouverte ; le push porte le « nouveau message » pendant l’état fermé. L’app à deux canaux par excellence.
- Suivi de commandes et de livraisons — l’écran de suivi ouvert s’abonne ; le passage au statut « livré » app fermée arrive par push.
- Alerting opérationnel — les consoles d’astreinte s’abonnent pour le mur d’écrans ; le chemin d’alerte d’astreinte passe par le push, car personne ne garde l’app ouverte à 3 h du matin.
- Enchères et drops — mouvement des prix en direct dans l’app ; être surenchéri pendant son absence est un push, avec un deep link vers l’écran en direct.
- Engagement social — likes et réponses arrivent en push de réengagement ; le fil ouvert passe en direct via un abonnement.
Quel canal devriez-vous utiliser ? Matrice de décision
| Votre situation | Choisissez |
|---|---|
| L’écran est ouvert et doit rester à jour | Live query |
| L’événement survient app fermée et l’utilisateur doit être prévenu | Notification push |
| Le payload est sensible ou soumis à permissions | Live query — ou push avec identifiants uniquement, récupération à l’ouverture |
| Vous avez besoin d’une livraison de données garantie et ordonnée | Aucun des deux à lui seul — rattrapage par requête à l’ouverture, canaux comme accélérateurs |
| Mettre à jour un badge ou un compteur dans l’app en temps réel | Live query |
| Réengager des utilisateurs qui n’ont pas ouvert l’app depuis des jours | Push — c’est le seul canal qui le peut |
| Borne ou mur d’écrans qui ne dort jamais | Live query uniquement ; le push n’apporte rien |
Limites et trade-offs
- Le push n’est pas un canal de données. Plafonds de payload, routage opaque hors de vos ACL et regroupement le rendent structurellement inadapté au transport d’état — envoyez des références, récupérez la vérité à l’ouverture.
- La livraison push est une probabilité, pas une promesse. Optimiseurs de batterie, permissions révoquées et limitation par la passerelle abandonnent tous des messages en silence ; tout ce qui ne doit pas être manqué exige un chemin de réconciliation par requête.
- Les live queries s’arrêtent à la frontière du processus. Aucun socket ne survit à la suspension ; traiter un abonnement comme un canal toujours actif est l’hypothèse erronée derrière la plupart des bugs du type « nous avons raté des événements ».
- Les deux canaux pèsent sur le client. Des abonnements trop larges consomment la batterie et le matching côté serveur ; un push trop zélé consomme la bonne volonté — la désinstallation est le rate limiting de l’utilisateur.
- La jointure est votre responsabilité. Déduplication, requêtes de rattrapage et rafraîchissement des tokens relèvent de la logique applicative ; aucun des deux canaux ne les fournit gratuitement.
Push et live queries sur Back4app
Back4app est une plateforme open-source de Backend as a Service (BaaS) qui combine une base de données gérée, des API REST et GraphQL générées automatiquement, l’authentification, le stockage de fichiers et des fonctions serverless avec Cloud Code. Les deux canaux sont intégrés et partagent un seul chemin d’écriture : un trigger Cloud Code afterSave sur la même écriture en base peut envoyer le push — via les intégrations de la plateforme avec les passerelles, avec ciblage par appareil et par canal — tandis que Live Query propage automatiquement l’objet complet vers chaque client abonné, permissions vérifiées. Le diagramme d’aiguillage ci-dessus se réduit à un trigger et à un appel d’abonnement, et la logique de jointure — requêtes de rattrapage, enregistrement du token via la classe Installation — passe par les mêmes SDK que ceux des onglets de code.
Questions fréquentes
Quelle est la différence entre notifications push et live queries ?
Le chemin de livraison et l'état de l'app qu'elles servent. Une notification push transite par la passerelle push du système d'exploitation et atteint l'appareil même quand votre app est fermée — mais elle transporte un payload petit et opaque, avec des garanties au mieux (best-effort). Une live query est un abonnement WebSocket que votre app en cours d'exécution garde ouvert : des objets complets, en temps réel, aux permissions vérifiées — et mort à l'instant où l'app l'est.
Les live queries fonctionnent-elles quand l'app est fermée ?
Non, et aucune astuce côté client n'y change rien. Une live query est un état à l'intérieur de votre processus en cours d'exécution — un WebSocket que l'app garde ouvert. Quand l'OS suspend ou tue l'app, le socket meurt avec elle, et les plateformes mobiles suspendent agressivement les apps en arrière-plan pour économiser la batterie. Atteindre une app fermée est précisément le rôle que l'OS réserve à sa propre passerelle push.
Une app de chat doit-elle utiliser les notifications push ou les live queries ?
Les deux, réparties selon l'état de l'app. La conversation ouverte s'abonne à une live query — les messages s'affichent instantanément avec des données complètes, indicateurs de saisie et accusés de lecture compris. L'app fermée compte sur le push pour alerter le destinataire, avec juste assez de payload pour afficher la bannière. Le tap ouvre l'app, qui se réabonne et relance la requête pour rattraper son retard. Toutes les messageries grand public fonctionnent ainsi.
Les notifications push arrivent-elles à coup sûr ?
Non — la livraison est au mieux, par conception. Les passerelles de l'OS regroupent, limitent et abandonnent des messages sous la pression de la batterie, les utilisateurs désactivent carrément les permissions, et les appareils deviennent injoignables. Les push silencieux en arrière-plan sont limités encore plus sévèrement que les notifications visibles. Traitez le push comme une tape sur l'épaule pour réveiller l'app, jamais comme un contrat de transport de données ; l'app doit réconcilier son état en interrogeant le backend une fois ouverte.
Quelle taille peut atteindre le payload d'une notification push ?
Des kilo-octets, pas des données. Les passerelles de l'OS plafonnent les payloads à environ 4 Ko, et le payload est opaque au modèle de permissions de votre backend — tout ce que vous y mettez circule dans le pipeline de notifications, hors de vos ACL. Le pattern robuste n'envoie que des identifiants et des chaînes d'affichage, et laisse l'app ouverte récupérer les vrais objets via l'API normale, aux permissions vérifiées.
Qu'est-ce qu'une notification push silencieuse ?
Un push sans alerte visible qui demande à l'OS de réveiller brièvement votre app en arrière-plan — typiquement pour précharger des données afin que la prochaine ouverture paraisse instantanée. C'est la ressource la plus rationnée du système push : l'OS attribue un budget de réveils par app et par jour et ignore l'excédent, si bien que le push silencieux fonctionne comme une couche d'optimisation, jamais comme un canal de synchronisation fiable.
Ai-je besoin à la fois des notifications push et des live queries ?
Si vos utilisateurs tiennent à des événements qui surviennent pendant que l'app est fermée — messages, commandes, alertes — oui, de façon presque inévitable. Les deux canaux couvrent des états disjoints de l'app : les live queries possèdent l'expérience app ouverte, le push possède le réengagement depuis l'état fermé. Les backends qui intègrent les deux laissent une seule écriture en base se propager vers chaque canal, si bien qu'avoir besoin des deux ne signifie plus construire deux fois.