| Sélectionnez une plate-forme : | iOS+ Android Web Flutter Unity C++ |
Selon l'état d'un appareil, les messages entrants sont gérés différemment. Pour comprendre ces scénarios et intégrer FCM à votre propre application, il est important de commencer par définir les différents états dans lesquels un appareil peut se trouver :
| État | Description |
|---|---|
| Premier plan | L'application est ouverte, visible et en cours d'utilisation. |
| Contexte | L'application est ouverte, mais en arrière-plan (réduite). Cela se produit généralement lorsque l'utilisateur a appuyé sur le bouton d'accueil de l'appareil, a basculé vers une autre application à l'aide du sélecteur d'applications ou a ouvert l'application dans un autre onglet (Web). |
| Résilié : | L'appareil est verrouillé ou l'application n'est pas en cours d'exécution. |
Vous devez remplir quelques conditions préalables pour que l'application puisse recevoir des charges utiles de messages à l'aide de FCM :
- L'application doit avoir été ouverte au moins une fois (pour permettre l'enregistrement auprès de FCM).
- Sur iOS, si l'utilisateur fait glisser l'application hors du sélecteur d'applications, il doit la rouvrir manuellement pour que les messages en arrière-plan recommencent à fonctionner.
- Sur Android, si l'utilisateur force l'arrêt de l'application à partir des paramètres de l'appareil, il doit la rouvrir manuellement pour que les messages recommencent à fonctionner.
- Sur le Web, vous devez avoir demandé un jeton (à l'aide de
getToken()) avec votre certificat de notification push Web.
Demander l'autorisation de recevoir des messages
Sur iOS, macOS, le Web et Android 13 (ou version ultérieure), avant de pouvoir recevoir des charges utiles FCM sur votre appareil, vous devez d'abord demander l'autorisation de l'utilisateur.
Le package firebase_messaging fournit une API pour demander l'autorisation à l'aide
de la
requestPermission
méthode. Cette API accepte un certain nombre d'arguments nommés qui définissent le type d'autorisations que vous souhaitez demander, par exemple si la messagerie contenant des charges utiles de notification peut déclencher un son ou lire des messages à l'aide de Siri. Par défaut, la méthode demande des autorisations par défaut raisonnables. L'API de référence fournit une documentation complète sur l'objectif de chaque autorisation.
Pour commencer, appelez la méthode à partir de votre application (sur iOS, une fenêtre modale intégrée s'affiche ; sur le Web, le flux de l'API du navigateur est déclenché) :
FirebaseMessaging messaging = FirebaseMessaging.instance;
NotificationSettings settings = await messaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
print('User granted permission: ${settings.authorizationStatus}');
La propriété authorizationStatus de l'objet NotificationSettings renvoyé par la requête peut être utilisée pour déterminer la décision globale de l'utilisateur :
authorized: l'utilisateur a accordé l'autorisation.denied: l'utilisateur a refusé l'autorisation.notDetermined: l'utilisateur n'a pas encore choisi d'accorder ou non l'autorisation.provisional: l'utilisateur a accordé une autorisation provisoire.
Les autres propriétés de NotificationSettings indiquent si une autorisation spécifique est activée, désactivée ou non prise en charge sur l'appareil actuel.
Une fois l'autorisation accordée et les différents types d'état de l'appareil compris, votre application peut commencer à gérer les charges utiles FCM entrantes.
Gestion des messages
En fonction de l'état actuel de votre application, les charges utiles entrantes de différents types de messages nécessitent des implémentations différentes pour les gérer :
Messages au premier plan
Pour gérer les messages lorsque votre application est au premier plan, écoutez le flux onMessage.
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('Got a message whilst in the foreground!');
print('Message data: ${message.data}');
if (message.notification != null) {
print('Message also contained a notification: ${message.notification}');
}
});
Le flux contient un RemoteMessage, qui fournit diverses informations sur la charge utile, telles que sa provenance, son ID unique, son heure d'envoi, si elle contenait une notification, etc. Étant donné que le message a été récupéré lorsque votre application est au premier plan, vous pouvez accéder directement à l'état et au contexte de votre application Flutter.
Messages au premier plan et de notification
Par défaut, les messages de notification qui arrivent lorsque l'application est au premier plan n'affichent pas de notification visible, à la fois sur Android et iOS. Il est toutefois possible de remplacer ce comportement :
- Sur Android, vous devez créer un canal de notification "Haute priorité".
- Sur iOS, vous pouvez modifier les options de présentation de l'application.
Messages en arrière-plan
Le processus de gestion des messages en arrière-plan est différent sur les plates-formes Android, Apple et Web.
Plates-formes Apple et Android
Gérez les messages en arrière-plan en enregistrant un gestionnaire onBackgroundMessage. Lorsque des messages sont reçus, un isolat est généré (Android uniquement, iOS/macOS ne nécessite pas d'isolat distinct), ce qui vous permet de gérer les messages même lorsque votre application n'est pas en cours d'exécution.
Voici quelques points à garder à l'esprit concernant votre gestionnaire de messages en arrière-plan :
- Il ne doit pas s'agir d'une fonction anonyme.
- Il doit s'agir d'une fonction de niveau supérieur (par exemple, pas une méthode de classe qui nécessite une initialisation).
- Lorsque vous utilisez Flutter version 3.3.0 ou ultérieure, le gestionnaire de messages doit être
annoté avec
@pragma('vm:entry-point')juste au-dessus de la déclaration de fonction (sinon, il peut être supprimé lors de l’élagage de l’arborescence pour le mode de publication ).
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
await Firebase.initializeApp();
print("Handling a background message: ${message.messageId}");
}
void main() {
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
runApp(MyApp());
}
Étant donné que le gestionnaire s'exécute dans son propre isolat en dehors du contexte de vos applications, il n'est pas possible de mettre à jour l'état de l'application ni d'exécuter une logique ayant un impact sur l'interface utilisateur. Vous pouvez toutefois effectuer des opérations logiques telles que des requêtes HTTP, des opérations d'E/S (par exemple, la mise à jour du stockage local), communiquer avec d'autres plug-ins, etc.
Il est également recommandé de terminer votre logique dès que possible. L'exécution de tâches longues et intensives a un impact sur les performances de l'appareil et peut entraîner l'arrêt du processus par le système d'exploitation. Si les tâches s'exécutent pendant plus de 30 secondes, l'appareil peut automatiquement arrêter le processus.
Web
Sur le Web, écrivez un service worker JavaScript qui s'exécute en arrière-plan. Utilisez le service worker pour gérer les messages en arrière-plan.
Pour commencer, créez un fichier dans votre répertoire web et appelez-le firebase-messaging-sw.js :
// See this file for the latest firebase-js-sdk version:
// https://github.com/firebase/flutterfire/blob/main/packages/firebase_core/firebase_core_web/lib/src/firebase_sdk_version.dart
importScripts("https://www.gstatic.com/firebasejs/10.7.0/firebase-app-compat.js");
importScripts("https://www.gstatic.com/firebasejs/10.7.0/firebase-messaging-compat.js");
firebase.initializeApp({
apiKey: "...",
authDomain: "...",
databaseURL: "...",
projectId: "...",
storageBucket: "...",
messagingSenderId: "...",
appId: "...",
});
const messaging = firebase.messaging();
// Optional:
messaging.onBackgroundMessage((message) => {
console.log("onBackgroundMessage", message);
});
Le fichier doit importer les SDK d'application et de messagerie, initialiser Firebase et exposer la variable messaging.
Ensuite, le worker doit être enregistré. Dans le fichier index.html, enregistrez le
worker en modifiant la balise <script> qui amorce Flutter :
<script src="flutter_bootstrap.js" async>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('firebase-messaging-sw.js', {
scope: '/firebase-cloud-messaging-push-scope',
});
});
}
</script>
Si vous utilisez toujours l'ancien système de modèles, vous pouvez enregistrer le worker en
modifiant la balise <script> qui amorce Flutter comme suit :
<html>
<body>
<script>
var serviceWorkerVersion = null;
var scriptLoaded = false;
function loadMainDartJs() {
if (scriptLoaded) {
return;
}
scriptLoaded = true;
var scriptTag = document.createElement('script');
scriptTag.src = 'main.dart.js';
scriptTag.type = 'application/javascript';
document.body.append(scriptTag);
}
if ('serviceWorker' in navigator) {
// Service workers are supported. Use them.
window.addEventListener('load', function () {
// Register Firebase Messaging service worker.
navigator.serviceWorker.register('firebase-messaging-sw.js', {
scope: '/firebase-cloud-messaging-push-scope',
});
// Wait for registration to finish before dropping the <script> tag.
// Otherwise, the browser will load the script multiple times,
// potentially different versions.
var serviceWorkerUrl =
'flutter_service_worker.js?v=' + serviceWorkerVersion;
navigator.serviceWorker.register(serviceWorkerUrl).then((reg) => {
function waitForActivation(serviceWorker) {
serviceWorker.addEventListener('statechange', () => {
if (serviceWorker.state == 'activated') {
console.log('Installed new service worker.');
loadMainDartJs();
}
});
}
if (!reg.active && (reg.installing || reg.waiting)) {
// No active web worker and we have installed or are installing
// one for the first time. Simply wait for it to activate.
waitForActivation(reg.installing ?? reg.waiting);
} else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
// When the app updates the serviceWorkerVersion changes, so we
// need to ask the service worker to update.
console.log('New service worker available.');
reg.update();
waitForActivation(reg.installing);
} else {
// Existing service worker is still good.
console.log('Loading app from service worker.');
loadMainDartJs();
}
});
// If service worker doesn't succeed in a reasonable amount of time,
// fallback to plaint <script> tag.
setTimeout(() => {
if (!scriptLoaded) {
console.warn(
'Failed to load app from service worker. Falling back to plain <script> tag.'
);
loadMainDartJs();
}
}, 4000);
});
} else {
// Service workers not supported. Just drop the <script> tag.
loadMainDartJs();
}
</script>
</body>
Redémarrez ensuite votre application Flutter. Le worker sera enregistré et tous les messages en arrière-plan seront gérés à l'aide de ce fichier.
Gérer les interactions
Étant donné que les notifications sont un indice visible, il est courant que les utilisateurs interagissent avec elles (en appuyant dessus). Le comportement par défaut sur Android et iOS consiste à ouvrir l'application. Si l'application est arrêtée, elle est démarrée ; si elle est en arrière-plan, elle est affichée au premier plan.
En fonction du contenu d'une notification, vous pouvez gérer l'interaction de l'utilisateur lorsque l'application s'ouvre. Par exemple, si un nouveau message de chat est envoyé à l'aide d'une notification et que l'utilisateur appuie dessus, vous pouvez ouvrir la conversation spécifique lorsque l'application s'ouvre.
Le package firebase-messaging offre deux façons de gérer cette interaction :
getInitialMessage(): si l'application est ouverte à partir d'un état arrêté, unFuturecontenant unRemoteMessageest renvoyé. Une fois consommé, leRemoteMessageest supprimé.onMessageOpenedApp: unStreamqui publie unRemoteMessagelorsque l'application est ouverte à partir d'un état en arrière-plan.
Il est recommandé de gérer les deux scénarios pour garantir une expérience utilisateur fluide. L'exemple de code suivant explique comment procéder :
class Application extends StatefulWidget {
@override
State<StatefulWidget> createState() => _Application();
}
class _Application extends State<Application> {
// It is assumed that all messages contain a data field with the key 'type'
Future<void> setupInteractedMessage() async {
// Get any messages which caused the application to open from
// a terminated state.
RemoteMessage? initialMessage =
await FirebaseMessaging.instance.getInitialMessage();
// If the message also contains a data property with a "type" of "chat",
// navigate to a chat screen
if (initialMessage != null) {
_handleMessage(initialMessage);
}
// Also handle any interaction when the app is in the background using a
// Stream listener
FirebaseMessaging.onMessageOpenedApp.listen(_handleMessage);
}
void _handleMessage(RemoteMessage message) {
if (message.data['type'] == 'chat') {
Navigator.pushNamed(context, '/chat',
arguments: ChatArguments(message),
);
}
}
@override
void initState() {
super.initState();
// Run code required to handle interacted messages in an async function
// as initState() must not be async
setupInteractedMessage();
}
@override
Widget build(BuildContext context) {
return Text("...");
}
}
La façon dont vous gérez l'interaction dépend de la configuration de votre application. L'exemple précédent montre une illustration de base à l'aide d'un StatefulWidget.
Localiser les messages
Vous pouvez envoyer des chaînes localisées de deux manières différentes :
- Stockez la langue préférée de chacun de vos utilisateurs sur votre serveur et envoyez des notifications personnalisées pour chaque langue.
- Intégrez des chaînes localisées dans votre application et utilisez les paramètres régionaux intégrés du système d'exploitation.
Voici comment utiliser la deuxième méthode :
Android
Spécifiez les messages dans votre langue par défaut dans
resources/values/strings.xml:<string name="notification_title">Hello world</string> <string name="notification_message">This is a message</string>Spécifiez les messages traduits dans le répertoire
values-language. Par exemple, spécifiez les messages en français dansresources/values-fr/strings.xml:<string name="notification_title">Bonjour le monde</string> <string name="notification_message">C'est un message</string>Dans la charge utile du serveur, au lieu d'utiliser les clés
title,messageetbody, utiliseztitle_loc_keyetbody_loc_keypour votre message localisé, et définissez les sur l'attributnamedu message que vous souhaitez afficher.La charge utile du message se présente comme suit :
{ "android": { "notification": { "title_loc_key": "notification_title", "body_loc_key": "notification_message" } } }
iOS
Spécifiez les messages dans votre langue par défaut dans
Base.lproj/Localizable.strings:"NOTIFICATION_TITLE" = "Hello World"; "NOTIFICATION_MESSAGE" = "This is a message";Spécifiez les messages traduits dans le
language.lprojrépertoire. Par exemple, spécifiez les messages en français dansfr.lproj/Localizable.strings:"NOTIFICATION_TITLE" = "Bonjour le monde"; "NOTIFICATION_MESSAGE" = "C'est un message";La charge utile du message se présente comme suit :
{ "apns": { "payload": { "alert": { "title-loc-key": "NOTIFICATION_TITLE", "loc-key": "NOTIFICATION_MESSAGE" } } } }
Activer l'exportation des données de diffusion des messages
Vous pouvez exporter les données de vos messages vers BigQuery pour une analyse plus approfondie. BigQuery vous permet d'analyser les données à l'aide de BigQuery SQL, de les exporter vers un autre fournisseur cloud ou de les utiliser pour vos modèles ML personnalisés. Une exportation vers BigQuery inclut toutes les données disponibles pour les messages, quel que soit le type de message ou que le message soit envoyé à l'aide de l'API ou du compositeur de notifications.
Pour activer l'exportation, suivez d'abord les étapes décrites dans le document sur l'exportation de données BigQuery. L'activation par programmation au niveau de l'instance d'application vous permet de demander aux utilisateurs finaux l'autorisation d'analyser leurs données de diffusion des messages (recommandé). Suivez ces instructions pour activer l'exportation par programmation :
Android
Vous pouvez utiliser le code suivant :
await FirebaseMessaging.instance.setDeliveryMetricsExportToBigQuery(true);
iOS
Pour iOS, vous devez modifier le AppDelegate.m avec le contenu suivant.
#import "AppDelegate.h"
#import "GeneratedPluginRegistrant.h"
#import <Firebase/Firebase.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
[[FIRMessaging extensionHelper] exportDeliveryMetricsToBigQueryWithMessageInfo:userInfo];
}
@end
Web
Pour le Web, vous devez modifier votre service worker afin d'utiliser la version 9 du SDK. La version 9 doit être regroupée. Vous devez donc utiliser un bundler tel que esbuild pour que le service worker fonctionne. Consultez l'exemple
d'application
pour découvrir comment procéder.
Une fois que vous avez migré vers le SDK v9, vous pouvez utiliser le code suivant :
import {
experimentalSetDeliveryMetricsExportedToBigQueryEnabled,
getMessaging,
} from 'firebase/messaging/sw';
...
const messaging = getMessaging(app);
experimentalSetDeliveryMetricsExportedToBigQueryEnabled(messaging, true);
N'oubliez pas d'exécuter yarn build afin d'exporter la nouvelle version de votre service worker vers le dossier web.
Afficher des images dans les notifications sur iOS
Sur les appareils Apple, pour que les notifications FCM entrantes affichent des images à partir de la charge utile FCM, vous devez ajouter une extension de service de notification supplémentaire et configurer votre application pour l'utiliser.
Si vous utilisez l'authentification Firebase par téléphone, vous devez ajouter le pod Firebase Auth à votre Podfile.
Étape 1 : Ajouter une extension de service de notification
- Dans Xcode, cliquez sur File > New > Target... (Fichier > Nouveau > Cible...).
- Une fenêtre modale présente une liste de cibles possibles. Faites défiler la liste ou utilisez le filtre pour sélectionner Notification Service Extension (Extension de service de notification). Cliquez sur Next (Suivant).
- Ajoutez un nom de produit (utilisez "ImageNotification" pour suivre ce tutoriel), sélectionnez
SwiftouObjective-C, puis cliquez sur Finish (Terminer). - Activez le schéma en cliquant sur Activate (Activer).
Étape 2 : Ajouter une cible au Podfile
Swift
Assurez-vous que votre nouvelle extension a accès au package Swift FirebaseMessaging en l'ajoutant à votre cible Runner :
Dans le navigateur, ajoutez le SDK des plates-formes Firebase pour Apple : File > Add Package Dependencies... (Fichier > Ajouter des dépendances de package...).
Recherchez ou saisissez l'URL du package :
none https://github.com/firebase/firebase-ios-sdkAjoutez au projet
Runner: Add Package (Ajouter un package).Choisissez FirebaseMessaging et ajoutez-le à la cible ImageNotification : Add Package (Ajouter un package).
Objective-C
Assurez-vous que votre nouvelle extension a accès au pod Firebase/Messaging en l'ajoutant au Podfile :
Dans le navigateur, ouvrez le Podfile : Pods > Podfile.
Allez en bas du fichier et ajoutez :
target 'ImageNotification' do use_frameworks! pod 'Firebase/Auth' # Add this line if you are using FirebaseAuth phone authentication pod 'Firebase/Messaging' endInstallez ou mettez à jour vos pods à l'aide de
pod installà partir du répertoireiosoumacos.
Étape 3 : Utiliser l'assistant d'extension
À ce stade, tout devrait encore fonctionner normalement. La dernière étape consiste à appeler l'assistant d'extension.
Swift
Dans le navigateur, sélectionnez votre extension ImageNotification.
Ouvrez le fichier
NotificationService.swift.Remplacez le contenu de
NotificationService.swiftpar :import UserNotifications import FirebaseMessaging class NotificationService: UNNotificationServiceExtension { var contentHandler: ((UNNotificationContent) -> Void)? var bestAttemptContent: UNMutableNotificationContent? override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) Messaging.serviceExtension().populateNotificationContent(bestAttemptContent!, withContentHandler: contentHandler) } override func serviceExtensionTimeWillExpire() { if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { contentHandler(bestAttemptContent) } } }
Objective-C
Dans le navigateur, sélectionnez votre extension ImageNotification.
Ouvrez le fichier
NotificationService.m.En haut du fichier, importez
FirebaseMessaging.hjuste aprèsNotificationService.h.Remplacez le contenu de
NotificationService.mpar :#import "NotificationService.h" #import "FirebaseMessaging.h" #import <FirebaseAuth/FirebaseAuth-Swift.h> // Add this line if you are using FirebaseAuth phone authentication #import <UIKit/UIKit.h> // Add this line if you are using FirebaseAuth phone authentication @interface NotificationService () <NSURLSessionDelegate> @property(nonatomic) void (^contentHandler)(UNNotificationContent *contentToDeliver); @property(nonatomic) UNMutableNotificationContent *bestAttemptContent; @end @implementation NotificationService /* Uncomment this if you are using Firebase Auth - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options { if ([[FIRAuth auth] canHandleURL:url]) { return YES; } return NO; } - (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts { for (UIOpenURLContext *urlContext in URLContexts) { [FIRAuth.auth canHandleURL:urlContext.URL]; } } */ - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler { self.contentHandler = contentHandler; self.bestAttemptContent = [request.content mutableCopy]; // Modify the notification content here... [[FIRMessaging extensionHelper] populateNotificationContent:self.bestAttemptContent withContentHandler:contentHandler]; } - (void)serviceExtensionTimeWillExpire { // Called just before the extension will be terminated by the system. // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. self.contentHandler(self.bestAttemptContent); } @end
Étape 4 : Ajouter l'image à la charge utile
Dans la charge utile de votre notification, vous pouvez désormais ajouter une image. Pour en savoir plus, découvrez comment créer une requête d'envoi.