Allez directement au contenu principal
Mobile Guides

Guide de la notification Push Expo 2026

Configurez les notifications push Expo. Ce guide couvre les permissions, les jetons, l'envoi, la gestion et les meilleures pratiques de production pour une livraison fiable.

Guide de la notification Push Expo 2026

Vous êtes probablement à un point où l'application fonctionne, les utilisateurs sont connectés, et le produit souhaite maintenant des flux de réengagement qui ressentent naturellement. Les rappels de panier. Les invitations de révision. Les alertes de nouveaux messages. Les annonces de mise à jour. Le premier réflexe est souvent de « justifier la mise en place de la notification push », puis une semaine plus tard, vous êtes en train de déboguer pourquoi un appareil reçoit des alertes, le simulateur semble s'enregistrer correctement, et personne ne peut expliquer pourquoi les appuis ne lancent pas l'écran approprié.

C'est là que les notifications push Expo sont soit agréablement simples, soit surprenamment fragiles.

Expo offre aux équipes React Native une couche pratique sur APNs et FCM, ce qui est exactement pourquoi tant d'équipes l'utilisent. Mais la différence entre une démo et une mise en production prête à l'emploi est réelle. Le cycle de vie des jetons, le timing des autorisations, la mise en place des écouteurs, la conception des payloads, et la nettoyage du backend comptent tous. Si vous êtes également en train de livrer des changements logiques fréquents dans l'application, le besoin de discipline opérationnelle devient encore plus aigu, surtout si votre travail de rétention dépend de la messagerie fiable et de la vitesse de mise à jour. C'est la même préoccupation plus large derrière le travail de rétention des utilisateurs de l'application mobile: la livraison n'est utile que si l'expérience utilisateur autour d'elle est prévisible.

Table des matières

La Fondation pour engager les utilisateurs avec les notifications push Expo

Un Notification push Expo Une configuration est attrayante pour une raison au-dessus de toutes les autres. Elle supprime une grande partie de la complexité de la messagerie native que les équipes ne veulent pas gérer dès le premier jour. Au lieu de construire directement les canaux APNs et FCM, vous pouvez travailler avec la passerelle d'Expo et vous concentrer sur le comportement du produit, la routage, l'UX des permissions et la logique de message backend.

Cet abstrait n'empêche pas la notification push d'être "réelle". Il change simplement la direction de vos efforts en ingénierie.

The service is also fast enough that performance usually isn’t the first thing to worry about. From March 14, 2023 through June 12, 2023, Expo’s push notification API showed a 42 milliseconde de temps de réponse médian, 273 milliseconde de latence p99et une taux journalier d'erreurs de 0,17% across des dizaines de millions de messages quotidiensl'analyse de benchmark de Knock sur l'envoi de notifications push d'Expo Knock’s Expo push API benchmark analysisCela devrait rassurer tout équipe se demandant si Expo est réservé uniquement aux prototypes.

Qu'est-ce que Expo abstrait réellement

Lorsque les équipes disent « notification push Expo », elles ont souvent plusieurs préoccupations distinctes regroupées ensemble.

  • Routage du fournisseur : Expo transmet les messages à APNs pour iOS et FCM pour Android.
  • Format du jeton : Votre serveur stocke et envoie un jeton de notification Expo au lieu de gérer la gestion de jetons spécifiques aux plateformes en premier.
  • Contrat de demande : Vous envoyez un payload par la méthode POST vers Expo’s push API plutôt que d'intégrer directement les APIs de fournisseur natif.

Cela est utile, mais cela crée également une confusion courante. Les équipes supposent parfois que Expo est responsable de tous les problèmes de livraison. En pratique, de nombreux échecs proviennent de l'application code, de jetons obsolètes, de payloads malformés ou d'une mauvaise gestion des autorisations.

Règle pratique : Traitez Expo comme un couche de transport fiable, et non comme un substitut à une conception client et serveur solide.

Ce que signifie vraiment la maturité de production

Une démo fonctionnelle prouve uniquement que l'un des appareils a accepté un lot une seule fois. La maturité de production signifie autre chose :

Préoccupation Mentality de démo Mentality de production
Autorisations Demandez dès maintenant Ask in context, after user value is clear
Jetons Save once Rafraîchir, dédupliquer, expirer et réconcilier
Payloads Mettez tout dans data Conservez les payloads petits et axés sur l'action
Comportement de l'application Afficher un avertissement Se comporter correctement et gérer l'état en avant-plan
Opérations Tests manuels Réceptions, nettoyage, journaux et gestion d'incidents

C'est la différence entre « notifications envoyées » et « notifications supportent un flux de workflow de produit réel. »

Initialiser la configuration du projet

Un grand nombre de douleurs d'envoi de notifications Expo commencent avant la première invitation de permission. Si votre configuration de projet est négligée, le client code peut paraître correct tout en faisant que l'application se comporte de manière incohérente entre les builds.

Une moderne tablette sur un bureau en bois affichant des fichiers de configuration code pour un projet de mise en place.

Start with the right libraries installed and a development environment that matches your build path. If you’re working beyond Expo Go, it helps to align your local workflow with a custom Expo development client setupPuisque le comportement des notifications doit souvent être validé dans une build qui ressemble plus à la production qu'à une rapide exécution de sandbox.

Au minimum, vous aurez besoin de:

Au minimum, vous aurez généralement besoin :

  • expo-notifications pour les demandes d'autorisation, la récupération de jetons, les écouteurs et la présentation des notifications.
  • expo-device car vous devriez protéger la récupération de jeton avec Device.isDevice.

Typical install commands depend on your package manager, but the key is version alignment with your Expo SDK. Don’t mix arbitrary package versions. Let Expo resolve compatible ones.

Gardez votre config explicite. Un minimum

Conservez votre config explicite. Un minimal app.json or app.config.js Les notifications doivent refléter le fait qu'elles font partie de votre contrat d'application, et non une pensée secondaire.

{
  "expo": {
    "name": "MyApp",
    "slug": "my-app",
    "plugins": ["expo-notifications"],
    "ios": {
      "bundleIdentifier": "com.example.myapp"
    },
    "android": {
      "package": "com.example.myapp"
    },
    "extra": {
      "eas": {
        "projectId": "your-project-id"
      }
    }
  }
}

Un ou deux détails comptent ici :

  • Identifiants de bundle et noms de packages need to match the app you actually ship.
  • Le plugin de notifications s'assure que le projet natif obtient la configuration requise lors de la construction.
  • L'ID du projet EAS a de l'importance lorsque votre récupération de jeton s'attend à ce que l'application soit associée au projet Expo correct.

Configurez un gestionnaire de notification dès le début

Attendez-vous trop longtemps pour définir le comportement des notifications. N'y allez pas. Placez-le près du démarrage de l'application afin que le comportement en avant-plan soit prévisible.

import * as Notifications from 'expo-notifications';

Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowAlert: true,
    shouldPlaySound: false,
    shouldSetBadge: true,
  }),
});

Les équipes décident si les notifications en arrière-plan doivent afficher une alerte, jouer un son ou affecter les badges. Le comportement exact dépend de votre produit. Une application de messagerie et une application de paiement ne feront pas les mêmes choix.

Si vous ne définissez pas intentionnellement le comportement en arrière-plan, votre équipe finira par déboguer les « notifications manquantes » qui ont été effectivement reçues mais n'ont jamais été présentées de la manière attendue par le produit.

Android nécessite une configuration de canal

Les canaux de notification Android ne sont pas facultatifs en pratique. Si vous les ignorez, vos alertes peuvent paraître incohérentes ou ne pas correspondre aux attentes des utilisateurs.

import { Platform } from 'react-native';
import * as Notifications from 'expo-notifications';

export async function configureAndroidNotifications() {
  if (Platform.OS !== 'android') return;

  await Notifications.setNotificationChannelAsync('default', {
    name: 'Default',
    importance: Notifications.AndroidImportance.MAX,
  });
}

Configurez cela lors de l'initialisation de l'application. Ensuite, maintenez les identifiants de canal stables. Les modifier fréquemment rend le comportement des notifications plus difficile à raisonner.

Demande de permission et capture de jetons de push

C'est là où de nombreuses équipes copient un snippet, puis finissent par regretter.

Les demandes de permission nécessitent un timing, une prise en compte de la plateforme et un traitement asynchrone discipliné. La capture de jetons doit se produire uniquement sur un appareil physique, uniquement après la résolution des permissions, et uniquement si vous êtes prêt à stocker le résultat sur votre serveur backend immédiatement.

Un diagramme étape par étape montrant le processus d'obtention et de stockage des jetons de notification push Expo.

La fonction client qui devrait être votre point de départ

Utilisez une fonction comme celle-ci comme point de départ

import * as Device from 'expo-device';
import * as Notifications from 'expo-notifications';
import Constants from 'expo-constants';
import { Platform } from 'react-native';

type RegisterResult =
  | { ok: true; token: string }
  | { ok: false; reason: string };

export async function registerForExpoPushNotificationsAsync(): Promise<RegisterResult> {
  if (!Device.isDevice) {
    return { ok: false, reason: 'Push notifications require a physical device.' };
  }

  if (Platform.OS === 'android') {
    await Notifications.setNotificationChannelAsync('default', {
      name: 'Default',
      importance: Notifications.AndroidImportance.MAX,
    });
  }

  const permissions = await Notifications.getPermissionsAsync();
  let finalStatus = permissions.status;

  if (finalStatus !== 'granted') {
    const request = await Notifications.requestPermissionsAsync();
    finalStatus = request.status;
  }

  if (finalStatus !== 'granted') {
    return { ok: false, reason: 'Notification permission was not granted.' };
  }

  const projectId =
    Constants.expoConfig?.extra?.eas?.projectId ??
    Constants.easConfig?.projectId;

  if (!projectId) {
    return { ok: false, reason: 'Missing EAS project ID configuration.' };
  }

  const tokenResponse = await Notifications.getExpoPushTokenAsync({ projectId });

  return { ok: true, token: tokenResponse.data };
}

L'ordre compte. Vous vérifiez le type d'appareil en premier, configurez le comportement du canal Android, résolvez les permissions, validez la configuration du projet, puis demandez le jeton Expo.

Pourquoi Device.isDevice n'est pas facultatif

C'est l'une des rares erreurs qui génère beaucoup de bruit tout en paraissant innocente. Les équipes d'experts ne demandent la permission que conditionnellement lorsque Device.isDevice est vrai, et une faute courante est de passer sous silence ce garde-fou, ce qui pousse les développeurs à envoyer des notifications à des jetons de simulateur invalides et à blâmer Expo lorsque le problème est vraiment la configuration de l'application, comme décrit dans les notes d'implémentation de notifications Expo d'Eagerworks.

C'est pourquoi le contrôle se trouve en haut de la fonction. Ne le cachez pas derrière un helper. Faites-l’évident.

Les résultats de simulateur sont utiles pour les tests de l'interface utilisateur. Ils ne sont pas fiables pour valider l'enregistrement du jeton de notification.

Demandez la permission au bon moment

N'interrogez pas sur l'écran de démarrage. N'interrogez pas avant que l'utilisateur comprenne la valeur. Le meilleur moment est généralement après une action de l'utilisateur qui rend les avantages des notifications concrètes, comme l'activation des mises à jour de livraison, la participation à une conversation ou la sauvegarde d'un élément surveillé.

Une bonne implémentation suit généralement ce flux :

  1. L'utilisateur atteint une limite fonctionnelle significative.
  2. App explains the value of notifications in your own UI.
  3. L'application demande la permission système.
  4. App stores the token on the backend immediately if permission is granted.

Cette dernière étape est là où de nombreuses applications échouent. Elles récupèrent le jeton, le logent localement et reportent l'enregistrement backend. Plus tard, le support ne peut pas déterminer quel appareil avait quel jeton à quel moment.

Voici un exemple simple de stockage du jeton après l'enregistrement :

export async function enablePushForCurrentUser(userId: string) {
  const result = await registerForExpoPushNotificationsAsync();

  if (!result.ok) {
    return result;
  }

  await fetch('https://api.example.com/push-tokens', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: 'Bearer user-session-token',
    },
    body: JSON.stringify({
      userId,
      token: result.token,
      platform: Platform.OS,
    }),
  });

  return result;
}

Plus tard dans le flux de travail, ce guide est une référence visuelle utile :

For teams building release-heavy apps, it also helps to think of token registration as part of the app’s operational state, not just part of onboarding. That mindset fits well with broader Flux de travail de livraison d'applications Expooù le comportement de l'application peut changer fréquemment et où l'état du serveur doit rester synchronisé.

Envoi de Notifications à Partir de Votre Serveur

Once your backend has a valid Expo Push Token, sending a notification is straightforward. The hard part isn’t the request itself. It’s deciding what belongs in the payload and how much trust you place in client state.

Ce que chaque champ de payload doit faire fetch:

type ExpoPushMessage = {
  to: string;
  title: string;
  body: string;
  sound?: 'default' | null;
  data?: Record<string, unknown>;
};

export async function sendExpoPushNotification(token: string) {
  const message: ExpoPushMessage = {
    to: token,
    title: 'New review received',
    body: 'Tap to open the order details.',
    sound: 'default',
    data: {
      type: 'new_review',
      orderId: 'ord_123',
      screen: 'OrderDetails',
    },
  };

  const response = await fetch('https://exp.host/--/api/v2/push/send', {
    method: 'POST',
    headers: {
      Accept: 'application/json',
      'Accept-encoding': 'gzip, deflate',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(message),
  });

  const result = await response.json();
  return result;
}

Quels sont les champs du payload à utiliser

N'employez pas le payload comme un simple dépotoir. Assurez-vous que chaque champ ait un sens.

Champ Objectif Conseils pratiques
to Ciblez le jeton de notification Expo Vérifiez qu'il appartient au dossier actuel du dispositif
title Titre de la notification Gardez-le court et lisible
body Texte principal visible Faites clair l'action
sound Comportement du son du système Use sparingly for high-value alerts
data Meta-données spécifiques à l'application Préférez les IDs et les indices de route aux contenus riches.

Le data l'objet est où les flux de travail des produits deviennent utiles. Vous pouvez passer un type et un ID de document, puis laisser l'application récupérer les données les plus récentes lorsque l'utilisateur clique. C'est plus sûr que d'insérer des gros ou des blobs sensibles directement dans le payload.

Considérez les payloads comme étant petites et ennuyeuses

According to le guide de Courier sur les notifications ExpoLes jetons d'Expo Push devraient être considérés comme éphémères, les payloads qui dépassent les limites de taille d'environ 4 Ko peuvent être supprimés, et un modèle fiable est d'envoyer des payloads de métadonnées petites telles que { "type": "new_review", "id": 123 } au lieu de gros JSON ou de médias intégrés. Ce conseil correspond à ce qui fonctionne dans les systèmes réels. Les payloads petites échouent moins souvent et vieillissent mieux lorsque les logiques de l'application changent.

Send enough data to route the user. Fetch the rest after the app opens.

Les habitudes côté serveur utiles

A une fonction d'envoi de base est suffisante pour les tests. Une production ajoute généralement quelques responsabilités supplémentaires:

  • Enregistrer les tentatives d'envoi : Save the notification intent with user ID, token, payload type, and timestamp.
  • Separez la génération du contenu de la transmission : Construire le texte du message dans une couche et la demande d'Expo API dans une autre.
  • Gérer les retours d'informations d'invalidation : Si Expo signale ultérieurement DeviceNotRegisteredArrêtez la tentative et marquez ce jeton obsolète.
  • Utiliser un design compatible avec les webhooks : Si votre système émet déjà des événements, dirigez les déclencheurs de notification à travers le même type de Enregistrer les erreurs d'envoi : utilisez-les ailleurs.

Avant de déboguer les écouteurs du client, envoyez d'abord un test de push manuel. Si un jeton reçoit une notification plane avec un petit payload, votre chemin de transport est probablement en bonne santé. Si ce n'est pas le cas, ne commencez pas par modifier la navigation code. Commencez par valider le jeton, la forme du payload et l'état de permission.

Manipulation des Notifications d'Arrivée dans Votre Application

La livraison n'est qu'une moitié de la fonctionnalité. L'application doit faire quelque chose de cohérent lorsque la notification arrive et lorsque l'utilisateur la clique.

Cela signifie gérer deux moments séparés :

  • la notification arrive tandis que l'application est ouverte
  • l'utilisateur interagit avec la notification depuis la zone de notification ou l'écran de verrouillage

Un diagramme de flux illustrant le cycle de notification push pour les applications mobiles en mode avant-plan et arrière-plan.

Événements de réception de fond et de réponse de l'utilisateur sont différents

Un setup fiable comprend généralement les deux écouteurs :

import { useEffect } from 'react';
import * as Notifications from 'expo-notifications';

export function useNotificationObservers(
  onForegroundMessage: (notification: Notifications.Notification) => void,
  onNotificationTap: (response: Notifications.NotificationResponse) => void
) {
  useEffect(() => {
    const receivedSub = Notifications.addNotificationReceivedListener(
      (notification) => {
        onForegroundMessage(notification);
      }
    );

    const responseSub = Notifications.addNotificationResponseReceivedListener(
      (response) => {
        onNotificationTap(response);
      }
    );

    return () => {
      receivedSub.remove();
      responseSub.remove();
    };
  }, [onForegroundMessage, onNotificationTap]);
}

addNotificationReceivedListener exécuté lorsque l'application est active. addNotificationResponseReceivedListener exécuté lorsque l'utilisateur clique sur une notification livrée. N'y combinez pas mentalement. Ils servent des chemins UX différents.

Lisez le payload de données et naviguez intentionnellement

Voici un modèle pratique pour la gestion des clics :

type NotificationData = {
  type?: string;
  orderId?: string;
  screen?: string;
};

export function handleNotificationTap(
  response: Notifications.NotificationResponse,
  navigation: any
) {
  const data =
    response.notification.request.content.data as NotificationData;

  if (data.screen === 'OrderDetails' && data.orderId) {
    navigation.navigate('OrderDetails', { orderId: data.orderId });
    return;
  }

  if (data.type === 'new_review') {
    navigation.navigate('Inbox');
    return;
  }

  navigation.navigate('Home');
}

Ce modèle reste résilient car le payload contient des indices de routage, pas des documents complets. Si l'ordre a changé depuis que la notification a été envoyée, l'application peut récupérer l'état serveur actuel après la navigation.

Une notification cliquée devrait conduire à un destin évident. Si votre chemin de secours est vague, les utilisateurs le remarquent immédiatement.

Foreground behavior should match user context

When the app is already open, blindly showing a system-style alert can feel clumsy. Sometimes the right move is an in-app banner, badge update, or silent refresh. A support inbox screen might not need a visible alert when the user is already reading that conversation.

Votre écouteur de premier plan doit donc se diviser en fonction de la route et du type de notification. Par exemple :

  • Écran de chat ouvert : ajoutez le message et évitez un bandeau redondant
  • Dashboard ouvert: affichez un toast léger dans l'application
  • Événement critique de compte : faites apparaître un traitement UI plus fort

A une approche simple, cela ressemble à ceci :

export function handleForegroundNotification(
  notification: Notifications.Notification,
  currentRouteName: string
) {
  const data = notification.request.content.data as { type?: string };

  if (currentRouteName === 'ChatThread' && data.type === 'new_message') {
    // refresh local thread state
    return;
  }

  // otherwise show your own in-app UI or update badges
}

Si votre application ne distingue pas ces contextes, les utilisateurs ressentiront une fatigue des notifications plus rapidement, même si la livraison est correcte techniquement.

Meilleures Pratiques et Pièges de Production

Most broken Expo push notification setups don’t fail because Expo is too limited. They fail because teams assume the token is permanent, payloads can carry anything, and app updates won’t affect notification logic.

Cette supposition ne survit pas en production.

Un infographique de checklist décrivant huit meilleures pratiques pour gérer les notifications push de production pour les applications mobiles.

Les jetons sont éphémères, pas des enregistrements d'identité

Un jeton de notification Expo est mieux traité comme un bail, et non comme un identifiant de dispositif à vie. Les jetons peuvent tourner après réinstallation, changement d'OS ou autres événements de cycle de vie. Si un jeton revient finalement DeviceNotRegisteredVotre serveur backend devrait cesser de le traiter comme actif.

Un modèle de serveur backend pratique stocke :

  • user ID
  • Plateforme
  • installer les métadonnées scoping
  • token actuel
  • timestamp de dernière vue
  • statut comme actif, obsolète ou révoqué

Ne stockez pas un champ de jeton sur la table utilisateur et croyez que c'est terminé. Les utilisateurs ont plusieurs appareils, et les appareils changent d'état.

Refresh strategy matters more than most tutorials admit

La documentation officielle de l'écosystème laisse un véritable écart opérationnel ici. Le contenu de notification push Expo existant n'explique souvent pas comment maintenir la validité du jeton. Cycles de révision de l'App Store et mises à jour OTACela affecte la façon dont vous conçez les déclencheurs de mise à jour. Les bonnes occasions pour réconcilier l'état du jeton incluent : Documentation des notifications Expo.

L'actualisation de l'application est une bonne occasion de réconcilier l'état du jeton

  • Lancement de l'application après une mise à jour
  • Connexion de l'utilisateur
  • Modification des paramètres d'autorisation
  • La rotation des clés sur votre processus de publication
  • Flux de récupération après les tickets de support liés aux notifications

La sécurité et la conformité ne doivent pas être traitées en fin de sprint

Beaucoup de tutoriels Expo se concentrent sur les mécanismes et ignorent le risque opérationnel. C'est acceptable pour les applications de loisirs. Ce n'est pas acceptable pour les produits de commerce réglementé, adjacents à la santé ou au financement.

La discussion de Courier sur les lacunes de notification Expo axée sur les entreprises highlète un manque de conseils pratiques autour de la gestion du consentement, des traçages d'audit et de la minimisation de l'exposition des données sensibles. Le retour d'expérience technique est simple :

  • Don’t put sensitive business data in notification text or payload metadata.
  • Enregistrez les modifications de consentement côté serveur.
  • Enregistrez les notifications envoyées à quelles jetons.
  • Use IDs in payloads and fetch protected content after app open.

Pour les équipes alignant les opérations de mise à jour avec Conformité à l'App Store et pratiques de sécurité APIpush devrait être inclus dans le même cadre de revue que l'authentification, l'analytique et la journalisation d'événements backend.

Les notifications push sont des messages destinés aux utilisateurs, mais elles constituent également un problème de systèmes distribués. Traitez-les avec la même attention que vous accordez à l'état d'authentification et aux événements de paiement.

Ce qui fonctionne généralement et ce qui casse généralement

Ce qui fonctionne généralement Ce qui fonctionne généralement
Demander la permission après une explication claire de la valeur Demander la permission à la première frame
Tester sur des appareils réels Se fier à l'enregistrement du simulateur
Stocker les jetons avec le contexte de l'appareil Un jeton par enregistrement d'utilisateur
Envoi de petites payloads de métadonnées Intégration de gros ou de blobs sensibles
Gestionner les événements de fond et de tap séparément Assuming all notifications follow one path
Expiration agressive des jetons obsolètes Réessai des jetons morts à l'infini

Une bonne configuration de notification Expo n'est pas compliquée. C'est une discipline.


If your team ships frequent app logic changes and needs tighter control over release behavior, rollbacks, and delivery visibility, Capgo vaut le coup d'œil. Elle aide les équipes mobiles à envoyer des mises à jour rapidement sans attendre la revue des magasins, ce qui est particulièrement utile lorsque les flux de notification, la logique de routage ou les corrections côté client doivent atteindre les utilisateurs rapidement.

Mises à jour instantanées pour les applications Capacitor

When a web-layer bug is live, ship the fix through Capgo instead of waiting days for app store approval. Users get the update in the background while native changes stay in the normal review path.

Soutien humain de Martin

Commencez Maintenant

Support humain de Martin

Capgo vous offre les meilleures informations nécessaires pour créer une application mobile véritablement professionnelle.