Tutoriel : Envoyer des notifications Push aux applications Flutter à l’aide d’Azure Notification Hubs via un service principal
- Xamarin.Forms
- Flutter
- React Native
Dans ce tutoriel, vous utilisez Azure Notification Hubs pour envoyer des notifications à une application Flutter ciblant Android et iOS.
Un serveur principal d’API web ASP.NET Core est utilisé pour gérer d’inscription d’appareil pour le client à l’aide de la dernière approche installation. Le service envoie également des notifications Push de manière multiplateforme.
Ces opérations sont gérées à l’aide du Kit de développement logiciel (SDK) notification Hubs de
Ce didacticiel vous guide tout au long des étapes suivantes :
- configurer Push Notification Services et Azure Notification Hubs.
- Créer une application principale d’API web core ASP.NET.
- Créer une application Flutter multiplateforme.
- configurer le projet Android natif pour les notifications Push.
- Configurer le projet iOS natif pour les notifications Push.
- Tester la solution.
Conditions préalables
Pour suivre le suivi, vous avez besoin des informations suivantes :
- Un abonnement Azure où vous pouvez créer et gérer des ressources.
- Le kit de ressources Flutter (ainsi que ses prérequis).
Visual Studio Code avec les plug-ins Flutter et Dartinstallés. - CocoaPods installé pour la gestion des dépendances de bibliothèque.
- Possibilité d’exécuter l’application sur Android (appareils physiques ou émulateurs) ou iOS (appareils physiques uniquement).
Pour Android, vous devez avoir :
- Un appareil physique déverrouillé ou un émulateur (exécutant l’API 26 et versions ultérieures avec Google Play Services installé).
Pour iOS, vous devez avoir :
- Un compte développeur Apple actif .
- Un appareil iOS physique inscrit à votre compte de développeur(exécutant iOS 13.0 et versions ultérieures).
- Un certificat de développement
.p12 installé dans votre trousseau vous permettant d' exécuter une application sur un appareil physique .
Note
Le simulateur iOS ne prend pas en charge les notifications à distance et un appareil physique est donc nécessaire lors de l’exploration de cet exemple sur iOS. Toutefois, vous n’avez pas besoin d’exécuter l’application sur Android et iOS pour suivre ce didacticiel.
Vous pouvez suivre les étapes décrites dans cet exemple de premier principe sans expérience préalable. Toutefois, vous bénéficiez d’une connaissance des aspects suivants.
- Portail des développeurs Apple.
- ASP.NET Core.
- console Google Firebase.
- Microsoft Azure et envoyer des notifications Push aux applications iOS à l’aide d’Azure Notification Hubs.
- Flutter et Dart pour le développement multiplateforme.
- Kotlin et Swift pour le développement natif Android et iOS.
Les étapes fournies sont spécifiques à macOS. Il est possible de suivre les étapes de
Configurer Push Notification Services et Azure Notification Hub
Dans cette section, vous configurez Firebase Cloud Messaging (FCM) et Apple Push Notification Services (APNS). Vous créez et configurez ensuite un hub de notification pour qu’il fonctionne avec ces services.
Créer un projet Firebase et activer Firebase Cloud Messaging pour Android
Connectez-vous à la console Firebase. Créez un projet Firebase entrant PushDemo en tant que nom de projet .
Note
Un nom unique sera généré pour vous. Par défaut, il s’agit d’une variante minuscule du nom que vous avez fourni et d’un nombre généré séparé par un tiret. Vous pouvez modifier ce paramètre si vous le souhaitez, car il est toujours unique à l’échelle mondiale.
Après avoir créé votre projet, sélectionnez Ajouter Firebase à votre application Android.
Dans la page Ajouter Firebase à votre application Android, procédez comme suit.
Pour le nom du package Android, entrez un nom pour votre package. Par exemple :
com.<organization_identifier>.<package_name>
.Sélectionnez Inscrire l’application.
Sélectionnez Télécharger google-services.json. Enregistrez ensuite le fichier dans un dossier local à utiliser ultérieurement, puis sélectionnez suivant .
Sélectionnez suivant.
Sélectionnez continuer vers la console
Note
Si le bouton Continuer à la console n’est pas activé, en raison du vérifier l’installation vérifier, choisissez Ignorer cette étape.
Dans la console Firebase, sélectionnez la roue dentée de votre projet. Sélectionnez ensuite paramètres du projet.
Note
Si vous n’avez pas téléchargé le fichier google-services.json, vous pouvez le télécharger sur cette page.
Basculez vers l’onglet Cloud Messaging en haut. Copiez et enregistrez la clé de serveur pour une utilisation ultérieure. Vous utilisez cette valeur pour configurer votre hub de notification.
Inscrire votre application iOS pour les notifications Push
Pour envoyer des notifications Push à une application iOS, inscrivez votre application auprès d’Apple et inscrivez-vous également aux notifications Push.
Si vous n’avez pas déjà inscrit votre application, accédez au portail d’approvisionnement iOS au Centre de développement Apple. Connectez-vous au portail avec votre ID Apple, accédez à Certificats, Identificateurs & Profils, puis sélectionnez Identificateurs. Cliquez sur + pour inscrire une nouvelle application.
Dans l’écran Inscrire un nouvel identificateur, sélectionnez les ID d’application case d’option. Sélectionnez ensuite Continuer.
Mettez à jour les trois valeurs suivantes pour votre nouvelle application, puis sélectionnez Continuer:
Description: tapez un nom descriptif pour votre application.
ID d’offre groupée: entrez un ID groupé du formulaire com.<organization_identifier>.<product_name> comme mentionné dans le guide de distribution des applications . Dans la capture d’écran suivante, la valeur
mobcat
est utilisée comme identificateur d’organisation et la valeur PushDemo est utilisée comme nom de produit.notifications Push : cochez l’option notifications Pushdans la section Fonctionnalités .Cette action génère votre ID d’application et vos demandes que vous confirmez les informations. Sélectionnez Continuer, puis sélectionnez Inscrire pour confirmer le nouvel ID d’application.
d’ID d’application
Une fois que vous avez sélectionné Inscrire, vous voyez le nouvel ID d’application en tant qu’élément de ligne dans la page Certificats, Identificateurs & Profils.
Dans la page Certificats, identificateurs & profils, sous Identificateurs, recherchez l’élément de ligne ID d’application que vous avez créé. Sélectionnez ensuite sa ligne pour afficher l’écran Modifier votre configuration d’ID d’application.
Création d’un certificat pour Notification Hubs
Un certificat est nécessaire pour permettre au hub de notification d’utiliser Apple Push Notification Services (APNS) et peut être fourni de deux façons :
Création d’un certificat push p12 qui peut être chargé directement dans notification Hub (l’approche d’origine)
Création d’un certificat p8 qui peut être utilisé pour l’authentification basée sur des jetons (l’approche plus récente et recommandée)
L’approche la plus récente présente un certain nombre d’avantages, comme indiqué dans authentification basée sur un jeton (HTTP/2) pour APNS. Moins d’étapes sont requises, mais elles sont également imposées pour des scénarios spécifiques. Toutefois, les étapes ont été fournies pour les deux approches, car l’une ou l’autre fonctionne à des fins de ce didacticiel.
OPTION 1 : Création d’un certificat Push p12 qui peut être chargé directement sur Notification Hub
Sur votre Mac, exécutez l’outil Keychain Access. Il peut être ouvert à partir du dossier Utilitaires de
ou du dossier Autre sur Launchpad.Sélectionnez d’accès au trousseau, développez Assistant Certificat, puis sélectionnez Demander un certificat auprès d’une autorité de certification.
de certificat
Note
Par défaut, Keychain Access sélectionne le premier élément de la liste. Cela peut être un problème si vous êtes dans la catégorie certificats
et Apple Worldwide Developer Relations Certification Authority n’est pas le premier élément de la liste. Assurez-vous que vous disposez d’un élément non clé ou que l’autorité de certification des relations des développeurs Apple Dans le monde est sélectionnée, avant de générer la demande de signature de certificat(CSR).Sélectionnez votre adresse e-mail
utilisateur , entrez votre valeur nom commun, vérifiez que vous spécifiez enregistré sur le disque , puis sélectionnezContinuer . Laissez adresse e-mail de l’autorité de certification vide, car elle n’est pas requise.Entrez un nom pour le fichier demande de signature de certificat (CSR) dans Enregistrer sous, sélectionnez l’emplacement dans Où, puis sélectionnez Enregistrer.
Cette action enregistre le fichier CSR à l’emplacement sélectionné. L’emplacement par défaut est Desktop. N’oubliez pas l’emplacement choisi pour le fichier.
De retour sur la page Certificats, Identificateurs & Profils dans le portail d’approvisionnement iOS , faites défiler jusqu’à l’option Notifications Push activée, puis sélectionnez Configurer pour créer le certificat.
La fenêtre certificats TLS/SSL du service de notification Push Apple s’affiche. Sélectionnez le bouton
Créer un certificat sous la section de certificat TLS/SSL de développement. L’écran Créer un nouveau certificat s’affiche.
Note
Ce tutoriel utilise un certificat de développement. Le même processus est utilisé lors de l’inscription d’un certificat de production. Veillez simplement à utiliser le même type de certificat lors de l’envoi de notifications.
Sélectionnez Choisir un fichier, accédez à l’emplacement où vous avez enregistré le fichier CSR , puis double-cliquez sur le nom du certificat pour le charger. Sélectionnez ensuite Continuer.
Une fois le portail créé le certificat, sélectionnez le bouton Télécharger. Enregistrez le certificat et n’oubliez pas l’emplacement dans lequel il est enregistré.
page de téléchargement de certificat généré
Le certificat est téléchargé et enregistré sur votre ordinateur dans votre dossier Téléchargements.
Note
Par défaut, le certificat de développement téléchargé est nommé aps_development.cer.
Double-cliquez sur le certificat Push téléchargé aps_development.cer. Cette action installe le nouveau certificat dans le trousseau, comme illustré dans l’image suivante :
de certificat
Note
Bien que le nom de votre certificat soit différent, le nom est préfixé par Apple Development iOS Push Services et disposez de l’identificateur de bundle approprié associé à celui-ci.
Dans Keychain Access, Control + Cliquez sur sur le nouveau certificat Push que vous avez créé dans la catégorie Certificats. Sélectionnez Exporter, nommez le fichier, sélectionnez le format p12, puis sélectionnez Enregistrer.
Vous pouvez choisir de protéger le certificat avec un mot de passe, mais un mot de passe est facultatif. Cliquez sur OK si vous souhaitez contourner la création du mot de passe. Notez le nom de fichier et l’emplacement du certificat p12 exporté. Ils sont utilisés pour activer l’authentification avec des API.
Note
Le nom et l’emplacement de votre fichier p12 peuvent être différents de ce qui est illustré dans ce tutoriel.
OPTION 2 : Création d’un certificat p8 qui peut être utilisé pour l’authentification basée sur des jetons
Notez les détails suivants :
- préfixe d’ID d’application (ID d’équipe)
- ID de bundle
De retour dans Certificats, identificateurs & profils, cliquez sur clés.
Note
Si vous disposez déjà d’une clé configurée pour APNS, vous pouvez réutiliser le certificat p8 que vous avez téléchargé juste après sa création. Si c’est le cas, vous pouvez ignorer les étapes 3 via 5.
Cliquez sur le bouton + (ou sur le bouton Créer une clé) pour créer une clé.
Fournissez une valeur de de nom de clé
appropriée, puis cochez l’option de du service de notifications Push Apple (APNS), puis cliquez sur Continuer , suivi deInscrire sur l’écran suivant.Cliquez sur
Télécharger , puis déplacez le fichier p8(préfixé par AuthKey_ ) vers un répertoire local sécurisé, puis cliquez surTerminé .Note
Veillez à conserver votre fichier p8 dans un emplacement sécurisé (et enregistrez une sauvegarde). Après avoir téléchargé votre clé, elle ne peut pas être téléchargée à nouveau, car la copie du serveur est supprimée.
Sur clés, cliquez sur la clé que vous avez créée (ou une clé existante si vous avez choisi de l’utiliser à la place).
Notez la valeur de l’ID de clé
. Ouvrez votre certificat p8 dans une application appropriée de votre choix, par exemple Visual Studio Code. Notez la valeur de clé (entre -----BEGIN PRIVATE KEY----- et -----END PRIVATE KEY-----).
-----BEGIN PRIVATE KEY-----
<key_value>
-----END PRIVATE KEY-----Note
Il s’agit de la valeur de jeton qui sera utilisée ultérieurement pour configurer notification Hub.
À la fin de ces étapes, vous devez disposer des informations suivantes pour une utilisation ultérieure dans Configurer votre hub de notification avec des informations APNS:
- ID d’équipe (voir l’étape 1)
- ID de bundle (voir l’étape 1)
- ID de clé (voir l’étape 7)
- valeur de jeton (valeur de clé p8 obtenue à l’étape 8)
Créer un profil d’approvisionnement pour l’application
Revenez au portail d’approvisionnement iOS , sélectionnez Certificats, Identificateurs & Profils, sélectionnez Profils dans le menu de gauche, puis sélectionnez + pour créer un profil. L’écran Inscrire un nouveau profil d’approvisionnement s’affiche.
Sélectionnez de développement d’applications iOS sous de développement comme type de profil d’approvisionnement, puis sélectionnez Continuer.
Ensuite, sélectionnez l’ID d’application que vous avez créé dans la liste déroulante ID d’application, puis sélectionnez Continuer.
Dans la fenêtre Sélectionner des certificats, sélectionnez le certificat de développement que vous utilisez pour la signature de code, puis sélectionnez Continuer.
Note
Ce certificat n’est pas le certificat Push que vous avez créé à l’étape précédente. Il s’agit de votre certificat de développement. S’il n’existe pas, vous devez le créer, car il s’agit d’un prérequis pour ce didacticiel. Les certificats de développeur peuvent être créés dans ledu portail des développeurs Apple
, via Xcode ou dans Visual Studio .Revenez à la page Certificats, Identificateurs & Profils, sélectionnez Profils dans le menu de gauche, puis sélectionnez + pour créer un profil. L’écran Inscrire un nouveau profil d’approvisionnement s’affiche.
Dans la fenêtre Sélectionner des certificats, sélectionnez le certificat de développement que vous avez créé. Sélectionnez ensuite Continuer.
Ensuite, sélectionnez les appareils à utiliser pour les tests, puis sélectionnez Continuer.
Enfin, choisissez un nom pour le profil dans Nom du profil d’approvisionnement, puis sélectionnez Générer.
Lorsque le nouveau profil d’approvisionnement est créé, sélectionnez Télécharger. N’oubliez pas l’emplacement dans lequel il est enregistré.
Accédez à l’emplacement du profil d’approvisionnement, puis double-cliquez dessus pour l’installer sur votre ordinateur de développement.
Créer un hub de notification
Dans cette section, vous allez créer un hub de notification et configurer l’authentification avec APNS. Vous pouvez utiliser un certificat push p12 ou une authentification basée sur un jeton. Si vous souhaitez utiliser un hub de notification que vous avez déjà créé, vous pouvez passer à l’étape 5.
Cliquez sur Créer une ressource, puis recherchez et choisissez notification Hub, puis cliquez sur Créer.
Mettez à jour les champs suivants, puis cliquez sur Créer:
DÉTAILS DE BASE
abonnement
: Choisir l' d’abonnementcible dans la liste déroulante
groupe de ressources : Créer un nouveau groupe de ressources (ou choisir un groupe de ressources existant)détails de l’espace de noms
notification Hub Namespace : entrez un nom global unique pour l’espace de nomsNotification Hub Note
Vérifiez que l’option Créer une nouvelle est sélectionnée pour ce champ.
DÉTAILS NOTIFICATION HUB
Notification Hub : entrez un nom pour le du hub de notification gratuite par défaut
Emplacement : Choisir un emplacement approprié dans la liste déroulante
niveau tarifaire: conserver l’option deNote
Sauf si vous avez atteint le nombre maximal de hubs sur le niveau gratuit.
Une fois que le Notification Hub a été approvisionné, accédez à cette ressource.
Accédez à votre nouveau hub de notification .
Sélectionnez stratégies d’accès dans la liste (sous MANAGE).
Notez les valeurs nom de la stratégie
ainsi que leurs valeurs de chaîne de connexion correspondantes .
Configurer votre Hub de notification avec des informations APNS
Sous Notification Services, sélectionnez Apple puis suivez les étapes appropriées en fonction de l’approche que vous avez choisie précédemment dans la section Création d’un certificat pour Notification Hubs.
Note
Utilisez le de production
OPTION 1 : Utilisation d’un certificat Push .p12
Sélectionnez certificat.
Sélectionnez l’icône de fichier.
Sélectionnez le fichier .p12 que vous avez exporté précédemment, puis sélectionnez Ouvrir.
Si nécessaire, spécifiez le mot de passe correct.
Sélectionnez mode sandbox.
Sélectionnez Enregistrer.
OPTION 2 : Utilisation de l’authentification basée sur les jetons
Sélectionnez jeton.
Entrez les valeurs suivantes que vous avez acquises précédemment :
- id de clé
- ID de bundle
- id d’équipe
- jeton
Choisissez bac à sable.
Sélectionnez Enregistrer.
Configurer votre hub de notification avec des informations FCM
- Sélectionnez google (GCM/FCM) dans la section paramètres dans le menu de gauche.
- Entrez la clé de serveur vous avez notée à partir de la console Google Firebase.
- Sélectionnez Enregistrer dans la barre d’outils.
Créer une application principale d’API web ASP.NET Core
Dans cette section, vous allez créer l’API web ASP.NET Core back-end pour gérer d’inscription des appareils et l’envoi de notifications à l’application mobile Flutter.
Créer un projet web
Dans Visual Studio, sélectionnez fichier>nouvelle solution.
Sélectionnez 'API .NET Core>App>ASP.NET Core>>suivante.
Dans la boîte de dialogue Configurer votre nouvelle API web ASP.NET Core, sélectionnez Framework cible de .NET Core 3.1.
Entrez
PushDemoApi pour le nom du projet , puis sélectionnez Créer .Démarrez le débogage (Commande + Entrer) pour tester l’application modèle.
Note
L’application modélisée est configurée pour utiliser le WeatherForecastController
commelaunchUrl . Cette valeur est définie dans Propriétés>launchSettings.json. Si vous êtes invité à utiliser un certificat de développement non valide trouvé message :
Cliquez sur Oui pour accepter d’exécuter l’outil « dotnet dev-certs https » pour résoudre ce problème. L’outil « dotnet dev-certs https » vous invite ensuite à entrer un mot de passe pour le certificat et le mot de passe de votre trousseau.
Cliquez sur Oui lorsque vous êtes invité à Installer et approuver le nouveau certificat, puis entrez le mot de passe de votre trousseau.
Développez le dossier contrôleurs
, puis supprimez WeatherForecastController.cs .Supprimer WeatherForecast.cs.
Configurez les valeurs de configuration locales à l’aide de l’outil Secret Manager. Découpler les secrets de la solution garantit qu’ils ne se retrouvent pas dans le contrôle de code source. Ouvrez Terminal puis accédez au répertoire du fichier projet et exécutez les commandes suivantes :
dotnet user-secrets init dotnet user-secrets set "NotificationHub:Name" <value> dotnet user-secrets set "NotificationHub:ConnectionString" <value>
Remplacez les valeurs d’espace réservé par votre propre nom de hub de notification et vos propres valeurs de chaîne de connexion. Vous avez noté ces informations dans la créer un hub de notification section. Sinon, vous pouvez les rechercher dans Azure.
NotificationHub :Name:
Consulteznom dans le résumé Essentials en haut de Vue d’ensemble .NotificationHub :ConnectionString:
Consultez DefaultFullSharedAccessSignature dans stratégies d’accèsNote
Pour les scénarios de production, vous pouvez examiner des options telles que Azure KeyVault pour stocker en toute sécurité la chaîne de connexion. Par souci de simplicité, les secrets seront ajoutés aux paramètres d’application Azure App Service.
Authentifier des clients à l’aide d’une clé API (facultatif)
Les clés API ne sont pas aussi sécurisées que les jetons, mais suffiront pour les besoins de ce didacticiel. Une clé API peut être configurée facilement via le ASP.NET middleware.
Ajoutez la clé API aux valeurs de configuration locales.
dotnet user-secrets set "Authentication:ApiKey" <value>
Note
Vous devez remplacer la valeur de l’espace réservé par votre propre et prendre note de celle-ci.
Control Cliquez sur dans le projetPushDemoApi , choisisseznouveau dossier dans le menuAjouter , puis cliquez surAjouter à l’aide du d’authentificationen tant que nom de dossier . Control Cliquez sur dans le dossier d’authentification, puis choisissez Nouveau fichier... dans le menu Ajouter. Sélectionnez
classe vide , entrez ApiKeyAuthOptions.cs pour l'nom du, puis cliquez sur Nouveau ajout de l’implémentation suivante.using Microsoft.AspNetCore.Authentication; namespace PushDemoApi.Authentication { public class ApiKeyAuthOptions : AuthenticationSchemeOptions { public const string DefaultScheme = "ApiKey"; public string Scheme => DefaultScheme; public string ApiKey { get; set; } } }
Ajoutez un autre classe vide au dossier Authentication appelé ApiKeyAuthHandler.cs, puis ajoutez l’implémentation suivante.
using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Text.Encodings.Web; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace PushDemoApi.Authentication { public class ApiKeyAuthHandler : AuthenticationHandler<ApiKeyAuthOptions> { const string ApiKeyIdentifier = "apikey"; public ApiKeyAuthHandler( IOptionsMonitor<ApiKeyAuthOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) {} protected override Task<AuthenticateResult> HandleAuthenticateAsync() { string key = string.Empty; if (Request.Headers[ApiKeyIdentifier].Any()) { key = Request.Headers[ApiKeyIdentifier].FirstOrDefault(); } else if (Request.Query.ContainsKey(ApiKeyIdentifier)) { if (Request.Query.TryGetValue(ApiKeyIdentifier, out var queryKey)) key = queryKey; } if (string.IsNullOrWhiteSpace(key)) return Task.FromResult(AuthenticateResult.Fail("No api key provided")); if (!string.Equals(key, Options.ApiKey, StringComparison.Ordinal)) return Task.FromResult(AuthenticateResult.Fail("Invalid api key.")); var identities = new List<ClaimsIdentity> { new ClaimsIdentity("ApiKeyIdentity") }; var ticket = new AuthenticationTicket( new ClaimsPrincipal(identities), Options.Scheme); return Task.FromResult(AuthenticateResult.Success(ticket)); } } }
Ajoutez une autre classe vide au dossier Authentication appelé ApiKeyAuthenticationBuilderExtensions.cs, puis ajoutez l’implémentation suivante.
using System; using Microsoft.AspNetCore.Authentication; namespace PushDemoApi.Authentication { public static class AuthenticationBuilderExtensions { public static AuthenticationBuilder AddApiKeyAuth( this AuthenticationBuilder builder, Action<ApiKeyAuthOptions> configureOptions) { return builder .AddScheme<ApiKeyAuthOptions, ApiKeyAuthHandler>( ApiKeyAuthOptions.DefaultScheme, configureOptions); } } }
Note
Cette méthode d’extension simplifie le code de configuration de l’intergiciel dans Startup.cs ce qui facilite la lecture et facilite généralement le suivi.
Dans Startup.cs, mettez à jour la méthode ConfigureServices pour configurer l’authentification par clé API sous l’appel aux services . AddControllers méthode.
using PushDemoApi.Authentication; using PushDemoApi.Models; using PushDemoApi.Services; public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddAuthentication(options => { options.DefaultAuthenticateScheme = ApiKeyAuthOptions.DefaultScheme; options.DefaultChallengeScheme = ApiKeyAuthOptions.DefaultScheme; }).AddApiKeyAuth(Configuration.GetSection("Authentication").Bind); }
Toujours dans
Startup.cs , mettez à jour la méthodeConfigurer pour appeler les méthodes d’extension UseAuthentication etUseAuthorization sur lesIApplicationBuilder de l’application. Vérifiez que ces méthodes sont appelées après UseRouting et avant application. UseEndpoints. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
Note
L’appel UseAuthentication inscrit le middleware qui utilise les schémas d’authentification précédemment inscrits (à partir de ConfigureServices). Cela doit être appelé avant tout intergiciel qui dépend de l’authentification des utilisateurs.
Ajouter des dépendances et configurer des services
ASP.NET Core prend en charge le modèle de conception logicielle d’injection de dépendances
L’utilisation du hub de notification et du Kit de développement logiciel (SDK) notification Hubs pour les opérations principales est encapsulée dans un service. Le service est inscrit et mis à disposition via une abstraction appropriée.
Control Cliquez sur dans le dossier dépendances, puis choisissez Gérer les packages NuGet... .Recherchez Microsoft.Azure.NotificationHubs et vérifiez qu’elle est cochée.
Cliquez sur Ajouter des packages, puis cliquez sur Accepter lorsque vous êtes invité à accepter les termes du contrat de licence.
Control Cliquez sur dans le projetPushDemoApi , choisisseznouveau dossier dans le menuAjouter , puis cliquez surAjouter à l’aide deModèles commenom du dossier. Control + Cliquez sur dans le dossier Models, puis choisissez Nouveau fichier... dans le menu Ajouter.
Sélectionnez
classe vide générale , entrezPushTemplates.cs pour l'nom de, puis cliquez sur nouveau ajout de l’implémentation suivante.namespace PushDemoApi.Models { public class PushTemplates { public class Generic { public const string Android = "{ \"notification\": { \"title\" : \"PushDemo\", \"body\" : \"$(alertMessage)\"}, \"data\" : { \"action\" : \"$(alertAction)\" } }"; public const string iOS = "{ \"aps\" : {\"alert\" : \"$(alertMessage)\"}, \"action\" : \"$(alertAction)\" }"; } public class Silent { public const string Android = "{ \"data\" : {\"message\" : \"$(alertMessage)\", \"action\" : \"$(alertAction)\"} }"; public const string iOS = "{ \"aps\" : {\"content-available\" : 1, \"apns-priority\": 5, \"sound\" : \"\", \"badge\" : 0}, \"message\" : \"$(alertMessage)\", \"action\" : \"$(alertAction)\" }"; } } }
Note
Cette classe contient les charges utiles de notification par jeton pour les notifications génériques et silencieuses requises par ce scénario. Les charges utiles sont définies en dehors du Installation pour permettre l’expérimentation sans avoir à mettre à jour les installations existantes via le service. La gestion des modifications apportées aux installations de cette façon est hors de portée pour ce didacticiel. Pour la production, envisagez de modèles personnalisés.
Ajoutez un autre
classe vide au dossier Modelsappelé DeviceInstallation.cs , puis ajoutez l’implémentation suivante.using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace PushDemoApi.Models { public class DeviceInstallation { [Required] public string InstallationId { get; set; } [Required] public string Platform { get; set; } [Required] public string PushChannel { get; set; } public IList<string> Tags { get; set; } = Array.Empty<string>(); } }
Ajoutez un autre classe vide au dossier Models appelé NotificationRequest.cs, puis ajoutez l’implémentation suivante.
using System; namespace PushDemoApi.Models { public class NotificationRequest { public string Text { get; set; } public string Action { get; set; } public string[] Tags { get; set; } = Array.Empty<string>(); public bool Silent { get; set; } } }
Ajoutez un autre
classe vide au dossier Modelsappelé NotificationHubOptions.cs , puis ajoutez l’implémentation suivante.using System.ComponentModel.DataAnnotations; namespace PushDemoApi.Models { public class NotificationHubOptions { [Required] public string Name { get; set; } [Required] public string ConnectionString { get; set; } } }
Ajoutez un nouveau dossier au projet PushDemoApi appelé Services.
Ajoutez une
interface vide au dossier servicesappelé INotificationService.cs , puis ajoutez l’implémentation suivante.using System.Threading; using System.Threading.Tasks; using PushDemoApi.Models; namespace PushDemoApi.Services { public interface INotificationService { Task<bool> CreateOrUpdateInstallationAsync(DeviceInstallation deviceInstallation, CancellationToken token); Task<bool> DeleteInstallationByIdAsync(string installationId, CancellationToken token); Task<bool> RequestNotificationAsync(NotificationRequest notificationRequest, CancellationToken token); } }
Ajoutez un de classe vide
au dossier services appelé NotificationHubsService.cs , puis ajoutez le code suivant pour implémenter l’interfaceINotificationService :using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Azure.NotificationHubs; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using PushDemoApi.Models; namespace PushDemoApi.Services { public class NotificationHubService : INotificationService { readonly NotificationHubClient _hub; readonly Dictionary<string, NotificationPlatform> _installationPlatform; readonly ILogger<NotificationHubService> _logger; public NotificationHubService(IOptions<NotificationHubOptions> options, ILogger<NotificationHubService> logger) { _logger = logger; _hub = NotificationHubClient.CreateClientFromConnectionString( options.Value.ConnectionString, options.Value.Name); _installationPlatform = new Dictionary<string, NotificationPlatform> { { nameof(NotificationPlatform.Apns).ToLower(), NotificationPlatform.Apns }, { nameof(NotificationPlatform.Fcm).ToLower(), NotificationPlatform.Fcm } }; } public async Task<bool> CreateOrUpdateInstallationAsync(DeviceInstallation deviceInstallation, CancellationToken token) { if (string.IsNullOrWhiteSpace(deviceInstallation?.InstallationId) || string.IsNullOrWhiteSpace(deviceInstallation?.Platform) || string.IsNullOrWhiteSpace(deviceInstallation?.PushChannel)) return false; var installation = new Installation() { InstallationId = deviceInstallation.InstallationId, PushChannel = deviceInstallation.PushChannel, Tags = deviceInstallation.Tags }; if (_installationPlatform.TryGetValue(deviceInstallation.Platform, out var platform)) installation.Platform = platform; else return false; try { await _hub.CreateOrUpdateInstallationAsync(installation, token); } catch { return false; } return true; } public async Task<bool> DeleteInstallationByIdAsync(string installationId, CancellationToken token) { if (string.IsNullOrWhiteSpace(installationId)) return false; try { await _hub.DeleteInstallationAsync(installationId, token); } catch { return false; } return true; } public async Task<bool> RequestNotificationAsync(NotificationRequest notificationRequest, CancellationToken token) { if ((notificationRequest.Silent && string.IsNullOrWhiteSpace(notificationRequest?.Action)) || (!notificationRequest.Silent && (string.IsNullOrWhiteSpace(notificationRequest?.Text)) || string.IsNullOrWhiteSpace(notificationRequest?.Action))) return false; var androidPushTemplate = notificationRequest.Silent ? PushTemplates.Silent.Android : PushTemplates.Generic.Android; var iOSPushTemplate = notificationRequest.Silent ? PushTemplates.Silent.iOS : PushTemplates.Generic.iOS; var androidPayload = PrepareNotificationPayload( androidPushTemplate, notificationRequest.Text, notificationRequest.Action); var iOSPayload = PrepareNotificationPayload( iOSPushTemplate, notificationRequest.Text, notificationRequest.Action); try { if (notificationRequest.Tags.Length == 0) { // This will broadcast to all users registered in the notification hub await SendPlatformNotificationsAsync(androidPayload, iOSPayload, token); } else if (notificationRequest.Tags.Length <= 20) { await SendPlatformNotificationsAsync(androidPayload, iOSPayload, notificationRequest.Tags, token); } else { var notificationTasks = notificationRequest.Tags .Select((value, index) => (value, index)) .GroupBy(g => g.index / 20, i => i.value) .Select(tags => SendPlatformNotificationsAsync(androidPayload, iOSPayload, tags, token)); await Task.WhenAll(notificationTasks); } return true; } catch (Exception e) { _logger.LogError(e, "Unexpected error sending notification"); return false; } } string PrepareNotificationPayload(string template, string text, string action) => template .Replace("$(alertMessage)", text, StringComparison.InvariantCulture) .Replace("$(alertAction)", action, StringComparison.InvariantCulture); Task SendPlatformNotificationsAsync(string androidPayload, string iOSPayload, CancellationToken token) { var sendTasks = new Task[] { _hub.SendFcmNativeNotificationAsync(androidPayload, token), _hub.SendAppleNativeNotificationAsync(iOSPayload, token) }; return Task.WhenAll(sendTasks); } Task SendPlatformNotificationsAsync(string androidPayload, string iOSPayload, IEnumerable<string> tags, CancellationToken token) { var sendTasks = new Task[] { _hub.SendFcmNativeNotificationAsync(androidPayload, tags, token), _hub.SendAppleNativeNotificationAsync(iOSPayload, tags, token) }; return Task.WhenAll(sendTasks); } } }
Note
L’expression de balise fournie à SendTemplateNotificationAsync est limitée à 20 balises. Il est limité à 6 pour la plupart des opérateurs, mais l’expression contient uniquement des OR (||) dans ce cas. S’il existe plus de 20 balises dans la demande, elles doivent être divisées en plusieurs requêtes. Pour plus d’informations, consultez la documentation routage et expressions de balise.
Dans
Startup.cs , mettez à jour la méthode ConfigureServicespour ajouter le NotificationHubsService en tant qu’implémentation singleton de INotificationService .using PushDemoApi.Models; using PushDemoApi.Services; public void ConfigureServices(IServiceCollection services) { ... services.AddSingleton<INotificationService, NotificationHubService>(); services.AddOptions<NotificationHubOptions>() .Configure(Configuration.GetSection("NotificationHub").Bind) .ValidateDataAnnotations(); }
Créer l’API de notifications
Control Cliquez sur dans le dossier contrôleurs de, puis choisissez Nouveau fichier... dans le menuAjouter .Sélectionnez
ASP.NET classe de contrôleur d’API web core , entrez notificationsController pour lenom de, puis cliquez sur Nouveau .Ajoutez les espaces de noms suivants en haut du fichier.
using System.ComponentModel.DataAnnotations; using System.Net; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using PushDemoApi.Models; using PushDemoApi.Services;
Mettez à jour le contrôleur modé afin qu’il dérive de ControllerBase et soit décoré avec l’attribut ApiController.
[ApiController] [Route("api/[controller]")] public class NotificationsController : ControllerBase { // Templated methods here }
Note
La classe de base Controller fournit la prise en charge des vues, mais cela n’est pas nécessaire dans ce cas et ControllerBase peut être utilisé à la place. Si vous suivez visual Studio 2019, vous pouvez ignorer cette étape.
Si vous avez choisi de terminer la section
Authentifier les clients à l’aide d’une clé API , vous devez également décorer l' notificationsControlleravec l’attribut Autoriser . [Authorize]
Mettez à jour le constructeur pour accepter l’instance inscrite de INotificationService en tant qu’argument et l’affecter à un membre en lecture seule.
readonly INotificationService _notificationService; public NotificationsController(INotificationService notificationService) { _notificationService = notificationService; }
Dans
launchSettings.json (dans le dossier propriétés de), remplacez le launchUrl de par api/notifications pour qu’il corresponde à l’URL spécifiée dans l’attributRegistrationsController Route .Démarrez le débogage (
Commande Entrer ) pour valider que l’application fonctionne avec le nouveau NotificationsControlleret retourne un état 401 Non autorisé .Sous un nouvel onglet Postman, définissez la requête sur GET. Entrez l’adresse ci-dessous en remplaçant l’espace réservé
par le applicationUrl httpsapplicationUrl trouvé dans Propriétés launchSettings.json .<applicationUrl>/api/notifications
Note
Le applicationurl
doit être ' pour le profil par défaut. Si vous utilisez IIS (par défaut dans Visual Studio 2019 sur Windows), vous devez utiliser l’applicationUr lspécifiée dans l’élément iisSettings à la place. Vous recevrez une réponse 404 si l’adresse est incorrecte.Si vous avez choisi de terminer la section Authentifier les clients à l’aide d’une clé API section, veillez à configurer les en-têtes de requête pour inclure votre valeur apikey.
Clé Valeur apikey <your_api_key> Cliquez sur le bouton Envoyer.
Note
Vous devez recevoir un état 200 OK avec un contenu JSON.
Si vous recevez un avertissement
de vérification de certificat SSL , vous pouvez basculer la vérification du certificat SSL de la demande désactivé dans leparamètres dePostman . Remplacez les méthodes de classe modèle dans NotificationsController.cs par le code suivant.
[HttpPut] [Route("installations")] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)] public async Task<IActionResult> UpdateInstallation( [Required]DeviceInstallation deviceInstallation) { var success = await _notificationService .CreateOrUpdateInstallationAsync(deviceInstallation, HttpContext.RequestAborted); if (!success) return new UnprocessableEntityResult(); return new OkResult(); } [HttpDelete()] [Route("installations/{installationId}")] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)] public async Task<ActionResult> DeleteInstallation( [Required][FromRoute]string installationId) { var success = await _notificationService .DeleteInstallationByIdAsync(installationId, CancellationToken.None); if (!success) return new UnprocessableEntityResult(); return new OkResult(); } [HttpPost] [Route("requests")] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest)] [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)] public async Task<IActionResult> RequestPush( [Required]NotificationRequest notificationRequest) { if ((notificationRequest.Silent && string.IsNullOrWhiteSpace(notificationRequest?.Action)) || (!notificationRequest.Silent && string.IsNullOrWhiteSpace(notificationRequest?.Text))) return new BadRequestResult(); var success = await _notificationService .RequestNotificationAsync(notificationRequest, HttpContext.RequestAborted); if (!success) return new UnprocessableEntityResult(); return new OkResult(); }
Créer l’application API
Vous créez maintenant une application API dans Azure App Service pour héberger le service principal.
Cliquez sur Créer une ressource, puis recherchez et choisissez application API, puis cliquez sur Créer.
Mettez à jour les champs suivants, puis cliquez sur Créer.
nom de l’application :
Entrez un nom global unique pour l’application APIAbonnement :
Choisissez la même cible abonnement vous avez créé le hub de notification.groupe de ressources :
Choisissez le même groupe de ressources dans lequel vous avez créé le hub de notification.plan/emplacement App Service :
Créer un plan App ServiceNote
Passez de l’option par défaut à un plan qui inclut prise en charge des SSL. Dans le cas contraire, vous devez prendre les mesures appropriées lors de l’utilisation de l’application mobile pour empêcher requêtes http d’être bloquées.
Application Insights :
Conservez l’option suggérée (une nouvelle ressource sera créée à l’aide de ce nom) ou choisissez une ressource existante.Une fois que l’application API a été provisionnée, accédez à cette ressource.
Notez l’URL
propriété dans le résumé Essentials en haut de la Vue d’ensemble . Cette URL est votre point de terminaison principal qui sera utilisé plus loin dans ce didacticiel.Note
L’URL utilise le nom de l’application API que vous avez spécifié précédemment, avec le format
https://<app_name>.azurewebsites.net
.Sélectionnez configuration dans la liste (sous Paramètres).
Pour chacun des paramètres ci-dessous, cliquez sur
nouveau paramètre d’application pour entrer le nom deet une valeur , puis cliquez surOK .Nom Valeur Authentication:ApiKey
<api_key_value> NotificationHub:Name
<hub_name_value> NotificationHub:ConnectionString
<hub_connection_string_value> Note
Il s’agit des mêmes paramètres que ceux que vous avez définis précédemment dans les paramètres utilisateur. Vous devriez être en mesure de les copier. Le paramètre Authentication :ApiKey n’est nécessaire que si vous avez choisi de terminer la section Authentifier les clients à l’aide d’une clé API. Pour les scénarios de production, vous pouvez examiner des options telles que Azure KeyVault. Ces paramètres ont été ajoutés en tant que paramètres d’application par souci de simplicité dans ce cas.
Une fois que tous les paramètres d’application ont été ajoutés, cliquez sur Enregistrer, puis Continuer.
Publier le service principal
Ensuite, vous déployez l’application sur l’application API pour la rendre accessible à partir de tous les appareils.
Note
Les étapes suivantes sont spécifiques à Visual Studio pour Mac. Si vous suivez Visual Studio 2019 sur Windows, le flux de publication sera différent. Consultez Publier sur Azure App Service sur Windows.
Modifiez votre configuration de de débogage en Version si vous ne l’avez pas déjà fait.
Control Cliquez le projet PushDemoApi, puis choisissez Publier sur Azure... dans le menuPublier .Suivez le flux d’authentification si vous y êtes invité. Utilisez le compte que vous avez utilisé dans la section créer l’application API section.
Sélectionnez l’application d’API Azure App Service que vous avez créée précédemment dans la liste en tant que cible de publication, puis cliquez sur Publier.
Une fois l’Assistant terminé, il publie l’application sur Azure, puis ouvre l’application. Notez l’URL si vous ne l’avez pas déjà fait. Cette URL est votre point de terminaison principal qui est utilisé plus loin dans ce didacticiel.
Validation de l’API publiée
Dans Postman ouvrir un nouvel onglet, définissez la demande sur put et entrez l’adresse ci-dessous. Remplacez l’espace réservé par l’adresse de base que vous avez notée dans la section précédente publier le service principal section.
https://<app_name>.azurewebsites.net/api/notifications/installations
Note
L’adresse de base doit être au format
https://<app_name>.azurewebsites.net/
Si vous avez choisi de terminer la section Authentifier les clients à l’aide d’une clé API section, veillez à configurer les en-têtes de requête pour inclure votre valeur apikey.
Clé Valeur apikey <your_api_key> Choisissez l’option brute pour le corps , puis choisissez JSON dans la liste des options de format, puis incluez un espace réservé contenu json :
{}
Cliquez sur envoyer.
Note
Vous devez recevoir un état 422 UnprocessableEntity du service.
Effectuez à nouveau les étapes 1 à 4, mais cette fois en spécifiant le point de terminaison des requêtes pour valider que vous recevez une réponse 400 requêtes incorrectes.
https://<app_name>.azurewebsites.net/api/notifications/requests
Note
Il n’est pas encore possible de tester l’API à l’aide de données de requête valides, car cela nécessite des informations spécifiques à la plateforme de l’application mobile cliente.
Créer une application Flutter multiplateforme
Dans cette section, vous créez un Flutter application mobile implémentant des notifications Push de manière multiplateforme.
Il vous permet d’inscrire et de désinscrire à partir d’un hub de notification via le service principal que vous avez créé.
Une alerte s’affiche lorsqu’une action est spécifiée et que l’application est au premier plan. Sinon, les notifications s’affichent dans le centre de notification.
Note
Vous devez généralement effectuer les actions d’inscription (et de désinscription) pendant le point approprié dans le cycle de vie de l’application (ou dans le cadre de votre expérience de première exécution peut-être) sans entrées explicites d’inscription/de désinscription d’utilisateurs. Toutefois, cet exemple nécessite une entrée utilisateur explicite pour permettre à cette fonctionnalité d’être explorée et testée plus facilement.
Créer la solution Flutter
Ouvrez une nouvelle instance de Visual Studio Code.
Ouvrez la palette de commandes (Maj + Commande + P).
Sélectionnez la commande Flutter : Nouveau projet, puis appuyez sur Entrée.
Entrez push_demo pour le nom du projet , puis sélectionnez un emplacement Projet.
Lorsque vous y êtes invité, choisissez Obtenir des packages.
Control Cliquez sur dans le dossier kotlin(sous 'application principale), puis choisissez Révéler dans le Finder . Ensuite, renommez les dossiers enfants (sous le dossier kotlin) encom
,<your_organization>
etpushdemo
respectivement.Note
Lorsque vous utilisez le modèle Visual Studio Code
, ces dossiers sont par défaut com ,exemple , . En supposant queproject_name mobcat est utilisé pour l'de l’organisation , la structure de dossiers doit apparaître de manière indicative comme suit : - kotlin
- Com
- mobcat
- pushdemo
- mobcat
- Com
- kotlin
De retour dans
Visual Studio Code , mettez à jour la valeur applicationdans application android build.gradle sur. Note
Vous devez utiliser votre propre nom d’organisation pour l’espace réservé <your_organization>. Par exemple, l’utilisation de mobcat, car l’organisation entraîne un nom de package valeur de com.mobcat.pushdemo.
Mettez à jour l’attribut de package
dans les fichiers AndroidManifest.xml , sousde débogage ,src principal et profil src respectivement. Vérifiez que les valeurs correspondent à l’id d’application que vous avez utilisé à l’étape précédente.<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.<your_organization>.pushdemo>"> ... </manifest>
Mettez à jour l’attribut
dans le fichier AndroidManifest.xml sousprincipale pour PushDemo. Ensuite, ajoutez l’attribut android:allowBackup
, directement sousandroid:label
, en définissant sa valeur sur false.<application android:name="io.flutter.app.FlutterApplication" android:label="PushDemo" android:allowBackup="false" android:icon="@mipmap/ic_launcher"> ... </application>
Ouvrez le fichier
build.gradle au niveau de l’application au niveau de l’application ( application defaultConfigandroid build.gradle ), puis mettez à jour lecompileSdkVersion (à partir de la section android) pour utiliser l’API 29 . Ensuite, mettez à jour les valeursminSdkVersion ettargetSdkVersion (de la section) à 26 et29 respectivement.Note
Seuls les appareils exécutant niveau d’API 26 et versions ultérieures sont pris en charge pour les besoins de ce didacticiel. Toutefois, vous pouvez l’étendre pour prendre en charge les appareils exécutant des versions antérieures.
Control + Click sur le dossier ios, puis choisissez Ouvrir dans Xcode.
Dans Xcode, cliquez sur Runner ( xcodeproj en haut, et non sur le dossier). Sélectionnez ensuite la cible
Runner, puis sélectionnez l’onglet général . Une fois la configuration de build toutes les sélectionnée, mettez à jour l’identificateur de bundlesur . Note
Vous devez utiliser votre propre nom d’organisation pour l’espace réservé <your_organization>. Par exemple, l’utilisation de mobcat, car l’organisation entraîne une valeur d’identificateur de bundle de com.mobcat.PushDemo.
Cliquez sur
Info.plist , puis mettez à jour la valeur nomBundle pour PushDemo Fermez Xcode et revenez à Visual Studio Code.
De retour dans Visual Studio Code, ouvrez pubspec.yaml, ajoutez les des packages d' http et flutter_secure_storagedes en tant que dépendances. Ensuite, enregistrez le fichier et cliquez sur Obtenir des packages lorsque vous y êtes invité.
dependencies: flutter: sdk: flutter http: ^0.12.1 flutter_secure_storage: ^3.3.3
Dans
terminal , remplacez le répertoire par le dossier ios(pour votre projet Flutter). Ensuite, exécutez la commande pod install pour installer de nouveaux pods (requis par le package flutter_secure_storage). Control Cliquez sur dans le dossier lib, puis choisissez nouveau fichier dans le menu à l’aide demain_page.dart comme nom de fichier. Ensuite, ajoutez le code suivant. import 'package:flutter/material.dart'; class MainPage extends StatefulWidget { @override _MainPageState createState() => _MainPageState(); } class _MainPageState extends State<MainPage> { @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: <Widget>[], ) ) ); } }
Dans main.dart, remplacez le code modèle par ce qui suit.
import 'package:flutter/material.dart'; import 'package:push_demo/main_page.dart'; final navigatorKey = GlobalKey<NavigatorState>(); void main() => runApp(MaterialApp(home: MainPage(), navigatorKey: navigatorKey));
Dans Terminal, générez et exécutez l’application sur chaque plateforme cible pour tester l’application modèle s’exécute sur votre ou vos appareils. Vérifiez que les appareils pris en charge sont connectés.
flutter run
Implémenter les composants multiplateformes
Control + Cliquez sur dans le dossier lib, puis choisissez nouveau dossier dans le menu à l’aide de modèles comme nom de dossier .
Control Cliquez sur dans le dossier modèles, puis choisissez nouveau fichier dans le menu à l’aide dedevice_installation.dart comme nom de fichier. Ensuite, ajoutez le code suivant.class DeviceInstallation { final String deviceId; final String platform; final String token; final List<String> tags; DeviceInstallation(this.deviceId, this.platform, this.token, this.tags); DeviceInstallation.fromJson(Map<String, dynamic> json) : deviceId = json['installationId'], platform = json['platform'], token = json['pushChannel'], tags = json['tags']; Map<String, dynamic> toJson() => { 'installationId': deviceId, 'platform': platform, 'pushChannel': token, 'tags': tags, }; }
Ajoutez un nouveau fichier aux modèles dossier appelé push_demo_action.dart définissant l’énumération des actions prises en charge dans cet exemple.
enum PushDemoAction { actionA, actionB, }
Ajoutez un nouveau dossier au projet appelé services puis ajoutez un nouveau fichier à ce dossier appelé device_installation_service.dart avec l’implémentation suivante.
import 'package:flutter/services.dart'; class DeviceInstallationService { static const deviceInstallation = const MethodChannel('com.<your_organization>.pushdemo/deviceinstallation'); static const String getDeviceIdChannelMethod = "getDeviceId"; static const String getDeviceTokenChannelMethod = "getDeviceToken"; static const String getDevicePlatformChannelMethod = "getDevicePlatform"; Future<String> getDeviceId() { return deviceInstallation.invokeMethod(getDeviceIdChannelMethod); } Future<String> getDeviceToken() { return deviceInstallation.invokeMethod(getDeviceTokenChannelMethod); } Future<String> getDevicePlatform() { return deviceInstallation.invokeMethod(getDevicePlatformChannelMethod); } }
Note
Vous devez utiliser votre propre nom d’organisation pour l’espace réservé <your_organization>. Par exemple, l’utilisation d' mobcat
, car l’organisation entraîne un nom methodChannel de com.mobcat.pushdemo/deviceinstallation .Cette classe encapsule l’utilisation de la plateforme native sous-jacente pour acquérir les détails requis de l’installation de l’appareil. Un MethodChannel facilite la communication asynchrone bidirectionnelle avec les plateformes natives sous-jacentes. L’équivalent spécifique à la plateforme pour ce canal sera créé dans les étapes ultérieures.
Ajoutez un autre fichier à ce dossier appelé notification_action_service.dart avec l’implémentation suivante.
import 'package:flutter/services.dart'; import 'dart:async'; import 'package:push_demo/models/push_demo_action.dart'; class NotificationActionService { static const notificationAction = const MethodChannel('com.<your_organization>.pushdemo/notificationaction'); static const String triggerActionChannelMethod = "triggerAction"; static const String getLaunchActionChannelMethod = "getLaunchAction"; final actionMappings = { 'action_a' : PushDemoAction.actionA, 'action_b' : PushDemoAction.actionB }; final actionTriggeredController = StreamController.broadcast(); NotificationActionService() { notificationAction .setMethodCallHandler(handleNotificationActionCall); } Stream get actionTriggered => actionTriggeredController.stream; Future<void> triggerAction({action: String}) async { if (!actionMappings.containsKey(action)) { return; } actionTriggeredController.add(actionMappings[action]); } Future<void> checkLaunchAction() async { final launchAction = await notificationAction.invokeMethod(getLaunchActionChannelMethod) as String; if (launchAction != null) { triggerAction(action: launchAction); } } Future<void> handleNotificationActionCall(MethodCall call) async { switch (call.method) { case triggerActionChannelMethod: return triggerAction(action: call.arguments as String); default: throw MissingPluginException(); break; } } }
Note
Cela est utilisé comme mécanisme simple pour centraliser la gestion des actions de notification afin qu’elles puissent être gérées de manière multiplateforme à l’aide d’une énumération fortement typée. Le service permet à la plateforme native sous-jacente de déclencher une action, lorsqu’une action est spécifiée dans la charge utile de notification. Il permet également au code commun de vérifier rétrospectivement si une action a été spécifiée lors du lancement de l’application une fois Flutter prête à le traiter. Par exemple, lorsque l’application est lancée en appuyant sur une notification du centre de notification.
Ajoutez un nouveau fichier au dossier
services appelé notification_registration_service.dart avec l’implémentation suivante.import 'dart:convert'; import 'package:flutter/services.dart'; import 'package:http/http.dart' as http; import 'package:push_demo/services/device_installation_service.dart'; import 'package:push_demo/models/device_installation.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; class NotificationRegistrationService { static const notificationRegistration = const MethodChannel('com.<your_organization>.pushdemo/notificationregistration'); static const String refreshRegistrationChannelMethod = "refreshRegistration"; static const String installationsEndpoint = "api/notifications/installations"; static const String cachedDeviceTokenKey = "cached_device_token"; static const String cachedTagsKey = "cached_tags"; final deviceInstallationService = DeviceInstallationService(); final secureStorage = FlutterSecureStorage(); String baseApiUrl; String apikey; NotificationRegistrationService(this.baseApiUrl, this.apikey) { notificationRegistration .setMethodCallHandler(handleNotificationRegistrationCall); } String get installationsUrl => "$baseApiUrl$installationsEndpoint"; Future<void> deregisterDevice() async { final cachedToken = await secureStorage.read(key: cachedDeviceTokenKey); final serializedTags = await secureStorage.read(key: cachedTagsKey); if (cachedToken == null || serializedTags == null) { return; } var deviceId = await deviceInstallationService.getDeviceId(); if (deviceId.isEmpty) { throw "Unable to resolve an ID for the device."; } var response = await http .delete("$installationsUrl/$deviceId", headers: {"apikey": apikey}); if (response.statusCode != 200) { throw "Deregister request failed: ${response.reasonPhrase}"; } await secureStorage.delete(key: cachedDeviceTokenKey); await secureStorage.delete(key: cachedTagsKey); } Future<void> registerDevice(List<String> tags) async { try { final deviceId = await deviceInstallationService.getDeviceId(); final platform = await deviceInstallationService.getDevicePlatform(); final token = await deviceInstallationService.getDeviceToken(); final deviceInstallation = DeviceInstallation(deviceId, platform, token, tags); final response = await http.put(installationsUrl, body: jsonEncode(deviceInstallation), headers: {"apikey": apikey, "Content-Type": "application/json"}); if (response.statusCode != 200) { throw "Register request failed: ${response.reasonPhrase}"; } final serializedTags = jsonEncode(tags); await secureStorage.write(key: cachedDeviceTokenKey, value: token); await secureStorage.write(key: cachedTagsKey, value: serializedTags); } on PlatformException catch (e) { throw e.message; } catch (e) { throw "Unable to register device: $e"; } } Future<void> refreshRegistration() async { final currentToken = await deviceInstallationService.getDeviceToken(); final cachedToken = await secureStorage.read(key: cachedDeviceTokenKey); final serializedTags = await secureStorage.read(key: cachedTagsKey); if (currentToken == null || cachedToken == null || serializedTags == null || currentToken == cachedToken) { return; } final tags = jsonDecode(serializedTags); return registerDevice(tags); } Future<void> handleNotificationRegistrationCall(MethodCall call) async { switch (call.method) { case refreshRegistrationChannelMethod: return refreshRegistration(); default: throw MissingPluginException(); break; } } }
Note
Cette classe encapsule l’utilisation de l' DeviceInstallationService
et les demandes adressées au service principal pour effectuer les actions d’inscription, de désinscription et d’actualisation requises. L’argument apiKey n’est nécessaire que si vous avez choisi de terminer la section Authentifier les clients à l’aide d’une clé API .Ajoutez un nouveau fichier au dossier lib appelé config.dart avec l’implémentation suivante.
class Config { static String apiKey = "API_KEY"; static String backendServiceEndpoint = "BACKEND_SERVICE_ENDPOINT"; }
Note
Il s’agit d’un moyen simple de définir des secrets d’application. Remplacez les valeurs d’espace réservé par vos propres valeurs. Vous devez avoir noté ces informations lorsque vous avez créé le service back-end. L’URL de l’application API doit être
https://<api_app_name>.azurewebsites.net/
. Le membre apiKeyn’est nécessaire que si vous avez choisi de terminer la section Authentifier les clients à l’aide d’une clé API .Veillez à l’ajouter à votre fichier gitignore pour éviter de valider ces secrets dans le contrôle de code source.
Implémenter l’interface utilisateur multiplateforme
Dans
main_page.dart , remplacez la fonction buildpar la commande suivante. @override Widget build(BuildContext context) { return Scaffold( body: Padding( padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 40.0), child: Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.stretch, children: <Widget>[ FlatButton( child: Text("Register"), onPressed: registerButtonClicked, ), FlatButton( child: Text("Deregister"), onPressed: deregisterButtonClicked, ), ], ), ), ); }
Ajoutez les importations requises en haut du fichier main_page.dart.
import 'package:push_demo/services/notification_registration_service.dart'; import 'config.dart';
Ajoutez un champ à la classe
_MainPageState pour stocker une référence auNotificationRegistrationService. final notificationRegistrationService = NotificationRegistrationService(Config.backendServiceEndpoint, Config.apiKey);
Dans la classe _MainPageState, implémentez les gestionnaires d’événements pour les Inscrire et annuler l’inscription des boutonssur les événements compressés. Appelez les méthodes de Register/Deregister correspondantes, puis affichez une alerte pour indiquer le résultat.
void registerButtonClicked() async { try { await notificationRegistrationService.registerDevice(List<String>()); await showAlert(message: "Device registered"); } catch (e) { await showAlert(message: e); } } void deregisterButtonClicked() async { try { await notificationRegistrationService.deregisterDevice(); await showAlert(message: "Device deregistered"); } catch (e) { await showAlert(message: e); } } Future<void> showAlert({ message: String }) async { return showDialog<void>( context: context, barrierDismissible: false, builder: (BuildContext context) { return AlertDialog( title: Text('PushDemo'), content: SingleChildScrollView( child: ListBody( children: <Widget>[ Text(message), ], ), ), actions: <Widget>[ FlatButton( child: Text('OK'), onPressed: () { Navigator.of(context).pop(); }, ), ], ); }, ); }
Maintenant, dans main.dart, vérifiez que les importations suivantes sont présentes en haut du fichier.
import 'package:flutter/material.dart'; import 'package:push_demo/models/push_demo_action.dart'; import 'package:push_demo/services/notification_action_service.dart'; import 'package:push_demo/main_page.dart';
Déclarez une variable pour stocker la référence à une instance de NotificationActionService et initialisez-la.
final notificationActionService = NotificationActionService();
Ajoutez des fonctions pour gérer l’affichage d’une alerte lorsqu’une action est déclenchée.
void notificationActionTriggered(PushDemoAction action) { showActionAlert(message: "${action.toString().split(".")[1]} action received"); } Future<void> showActionAlert({ message: String }) async { return showDialog<void>( context: navigatorKey.currentState.overlay.context, barrierDismissible: false, builder: (BuildContext context) { return AlertDialog( title: Text('PushDemo'), content: SingleChildScrollView( child: ListBody( children: <Widget>[ Text(message), ], ), ), actions: <Widget>[ FlatButton( child: Text('OK'), onPressed: () { Navigator.of(context).pop(); }, ), ], ); }, ); }
Mettez à jour la fonction principale
pour observer le flux d’actions NotificationActionService actionTriggered et rechercher les actions capturées pendant le lancement de l’application.void main() async { runApp(MaterialApp(home: MainPage(), navigatorKey: navigatorKey,)); notificationActionService.actionTriggered.listen((event) { notificationActionTriggered(event as PushDemoAction); }); await notificationActionService.checkLaunchAction(); }
Note
Il s’agit simplement de démontrer la réception et la propagation des actions de notification Push. En règle générale, celles-ci sont gérées en mode silencieux, par exemple en accédant à une vue spécifique ou en actualisant certaines données plutôt que d’afficher une alerte dans ce cas.
Configurer le projet Android natif pour les notifications Push
Ajouter le fichier JSON Google Services
Control Cliquez sur dans le dossier android, puis choisissez Ouvrir dans Android Studio . Ensuite, basculez vers la vue Project (si ce n’est pas déjà fait).Recherchez le fichier
google-services.json que vous avez téléchargé précédemment lorsque vous configurez le projet PushDemodans la console Firebase . Ensuite, faites-le glisser dans l’application répertoire racine du module (android>application android>).
Configurer les paramètres de génération et les autorisations
Basculez l’affichage project
sur Android. Ouvrez
AndroidManifest.xml , puis ajoutez le INTERNETet les autorisations de READ_PHONE_STATE après l’élément de l’applicationavant la balise de fermante. <manifest> <application>...</application> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> </manifest>
Ajouter les kits SDK Firebase
Dans Android Studio, ouvrez le fichier build.gradle au niveau du projet (scripts Gradle>build.gradle (Projet : android)). et vérifiez que vous disposez du chemin de classe « com.google.gms :google-services » dans le chemin de classe
buildscript
>dépendances nœud.buildscript { repositories { // Check that you have the following line (if not, add it): google() // Google's Maven repository } dependencies { // ... // Add the following line: classpath 'com.google.gms:google-services:4.3.3' // Google Services plugin } } allprojects { // ... repositories { // Check that you have the following line (if not, add it): google() // Google's Maven repository // ... } }
Note
Vérifiez que vous référencez la dernière version en fonction des instructions fournies dans la console Firebase lorsque vous avez créé le projet Android .
Dans le fichier
build.gradle au niveau de l’application (Scripts Gradle build.gradle (Module : application ), appliquez le plug-inGoogle Services Gradle. Appliquez le plug-in au-dessus du nœud android. // ... // Add the following line: apply plugin: 'com.google.gms.google-services' // Google Services plugin android { // ... }
Dans le même fichier, dans les dépendances nœud, ajoutez la dépendance pour la bibliothèque Cloud Messaging Android.
dependencies { // ... implementation 'com.google.firebase:firebase-messaging:20.2.0' }
Note
Veillez à référencer la dernière version en fonction de la documentation du client Android Cloud Messaging.
Enregistrez les modifications, puis cliquez sur le bouton Synchroniser maintenant (à partir de l’invite de barre d’outils) ou Synchroniser le projet avec Gradle Files.
Gérer les notifications Push pour Android
Dans
Android Studio, Control Cliquez sur sur lacom. (your_organization dossier de package .pushdemo application kotlin ), choisissezpackage dans le menuNouveau . Entrez services comme nom, puis appuyez sur Retour.Control Cliquez sur dans le dossier des services, choisissez fichier kotlin/classe dans le menuNouveau . Entrez DeviceInstallationService comme nom, puis appuyez sur Retour.Implémentez le DeviceInstallationService
à l’aide du code suivant. package com.<your_organization>.pushdemo.services import android.annotation.SuppressLint import android.content.Context import android.provider.Settings.Secure import com.google.android.gms.common.ConnectionResult import com.google.android.gms.common.GoogleApiAvailability import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel @SuppressLint("HardwareIds") class DeviceInstallationService { companion object { const val DEVICE_INSTALLATION_CHANNEL = "com.<your_organization>.pushdemo/deviceinstallation" const val GET_DEVICE_ID = "getDeviceId" const val GET_DEVICE_TOKEN = "getDeviceToken" const val GET_DEVICE_PLATFORM = "getDevicePlatform" } private var context: Context private var deviceInstallationChannel : MethodChannel val playServicesAvailable get() = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS constructor(context: Context, flutterEngine: FlutterEngine) { this.context = context deviceInstallationChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, DEVICE_INSTALLATION_CHANNEL) deviceInstallationChannel.setMethodCallHandler { call, result -> handleDeviceInstallationCall(call, result) } } fun getDeviceId() : String = Secure.getString(context.applicationContext.contentResolver, Secure.ANDROID_ID) fun getDeviceToken() : String { if(!playServicesAvailable) { throw Exception(getPlayServicesError()) } // TODO: Revisit once we have created the PushNotificationsFirebaseMessagingService val token = "Placeholder_Get_Value_From_FirebaseMessagingService_Implementation" if (token.isNullOrBlank()) { throw Exception("Unable to resolve token for FCM.") } return token } fun getDevicePlatform() : String = "fcm" private fun handleDeviceInstallationCall(call: MethodCall, result: MethodChannel.Result) { when (call.method) { GET_DEVICE_ID -> { result.success(getDeviceId()) } GET_DEVICE_TOKEN -> { getDeviceToken(result) } GET_DEVICE_PLATFORM -> { result.success(getDevicePlatform()) } else -> { result.notImplemented() } } } private fun getDeviceToken(result: MethodChannel.Result) { try { val token = getDeviceToken() result.success(token) } catch (e: Exception) { result.error("ERROR", e.message, e) } } private fun getPlayServicesError(): String { val resultCode = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) if (resultCode != ConnectionResult.SUCCESS) { return if (GoogleApiAvailability.getInstance().isUserResolvableError(resultCode)){ GoogleApiAvailability.getInstance().getErrorString(resultCode) } else { "This device is not supported" } } return "An error occurred preventing the use of push notifications" } }
Note
Cette classe implémente l’équivalent spécifique à la plateforme pour le canal
com.<your_organization>.pushdemo/deviceinstallation
. Cela a été défini dans la partie Flutter de l’application dans DeviceInstallationService.dart. Dans ce cas, les appels sont effectués à partir du code commun vers l’hôte natif. Veillez à remplacer <your_organization> par votre propre organisation où cela est utilisé.Cette classe fournit un ID unique (à l’aide de Secure.AndroidId) dans le cadre de la charge utile d’inscription du hub de notification.
Ajoutez un autre
fichier/classe Kotlin au dossier servicesappelé NotificationRegistrationService , puis ajoutez le code suivant.package com.<your_organization>.pushdemo.services import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel class NotificationRegistrationService { companion object { const val NOTIFICATION_REGISTRATION_CHANNEL = "com.<your_organization>.pushdemo/notificationregistration" const val REFRESH_REGISTRATION = "refreshRegistration" } private var notificationRegistrationChannel : MethodChannel constructor(flutterEngine: FlutterEngine) { notificationRegistrationChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, NotificationRegistrationService.NOTIFICATION_REGISTRATION_CHANNEL) } fun refreshRegistration() { notificationRegistrationChannel.invokeMethod(REFRESH_REGISTRATION, null) } }
Note
Cette classe implémente l’équivalent spécifique à la plateforme pour le canal
com.<your_organization>.pushdemo/notificationregistration
. Cela a été défini dans la partie Flutter de l’application dans NotificationRegistrationService.dart. Dans ce cas, les appels sont effectués de l’hôte natif vers le code commun. Là encore, veillez à remplacer <your_organization> par votre propre organisation où cela est utilisé.Ajoutez un autre fichier/classe Kotlin au dossier services appelé NotificationActionService, puis ajoutez le code suivant.
package com.<your_organization>.pushdemo.services import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel class NotificationActionService { companion object { const val NOTIFICATION_ACTION_CHANNEL = "com.<your_organization>.pushdemo/notificationaction" const val TRIGGER_ACTION = "triggerAction" const val GET_LAUNCH_ACTION = "getLaunchAction" } private var notificationActionChannel : MethodChannel var launchAction : String? = null constructor(flutterEngine: FlutterEngine) { notificationActionChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, NotificationActionService.NOTIFICATION_ACTION_CHANNEL) notificationActionChannel.setMethodCallHandler { call, result -> handleNotificationActionCall(call, result) } } fun triggerAction(action: String) { notificationActionChannel.invokeMethod(NotificationActionService.TRIGGER_ACTION, action) } private fun handleNotificationActionCall(call: MethodCall, result: MethodChannel.Result) { when (call.method) { NotificationActionService.GET_LAUNCH_ACTION -> { result.success(launchAction) } else -> { result.notImplemented() } } } }
Note
Cette classe implémente l’équivalent spécifique à la plateforme pour le canal
com.<your_organization>.pushdemo/notificationaction
. Cela a été défini dans la partie Flutter de l’application dans NotificationActionService.dart. Les appels peuvent être effectués dans les deux sens dans ce cas. Veillez à remplacer <your_organization> par votre propre organisation où cela est utilisé.Ajoutez un nouveau fichier/classe Kotlin au com.<your_organization>package .pushdemo appelé PushNotificationsFirebaseMessagingService, puis implémentez l’utilisation du code suivant.
package com.<your_organization>.pushdemo import android.os.Handler import android.os.Looper import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.RemoteMessage import com.<your_organization>.pushdemo.services.NotificationActionService import com.<your_organization>.pushdemo.services.NotificationRegistrationService class PushNotificationsFirebaseMessagingService : FirebaseMessagingService() { companion object { var token : String? = null var notificationRegistrationService : NotificationRegistrationService? = null var notificationActionService : NotificationActionService? = null } override fun onNewToken(token: String) { PushNotificationsFirebaseMessagingService.token = token notificationRegistrationService?.refreshRegistration() } override fun onMessageReceived(message: RemoteMessage) { message.data.let { Handler(Looper.getMainLooper()).post { notificationActionService?.triggerAction(it.getOrDefault("action", null)) } } } }
Note
Cette classe est responsable de la gestion des notifications lorsque l’application est en cours d’exécution au premier plan. Il appelle de manière conditionnelle le triggerAction
sur le NotificationActionService si une action est incluse dans la charge utile de notification reçue dansonMessageReceived . Cela appelle égalementrefreshRegistration sur le NotificationRegistrationService lorsque le jeton Firebase est régénéré en remplaçant la fonction onNewToken .Une fois de plus, veillez à remplacer <your_organization> par votre propre organisation où qu’elle soit utilisée.
Dans AndroidManifest.xml (application>src>principale), ajoutez le PushNotificationsFirebaseMessagingService au bas de l’élément application avec le filtre d’intention
com.google.firebase.MESSAGING_EVENT
.<manifest> <application> <!-- EXISTING MANIFEST CONTENT --> <service android:name="com.<your_organization>.pushdemo.PushNotificationsFirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service> </application> </manifest>
De retour dans DeviceInstallationService, vérifiez que les importations suivantes sont présentes en haut du fichier.
package com.<your_organization>.pushdemo import com.<your_organization>.pushdemo.services.PushNotificationsFirebaseMessagingService
Note
Remplacez <your_organization> par votre propre valeur d’organisation.
Mettez à jour le texte de l’espace réservé Placeholder_Get_Value_From_FirebaseMessagingService_Implementation pour obtenir la valeur du jeton à partir de la PushNotificationFirebaseMessagingService.
fun getDeviceToken() : String { if(!playServicesAvailable) { throw Exception(getPlayServicesError()) } // Get token from the PushNotificationsFirebaseMessagingService.token field. val token = PushNotificationsFirebaseMessagingService.token if (token.isNullOrBlank()) { throw Exception("Unable to resolve token for FCM.") } return token }
Dans MainActivity, vérifiez que les importations suivantes sont présentes en haut du fichier.
package com.<your_organization>.pushdemo import android.content.Intent import android.os.Bundle import com.google.android.gms.tasks.OnCompleteListener import com.google.firebase.iid.FirebaseInstanceId import com.<your_organization>.pushdemo.services.DeviceInstallationService import com.<your_organization>.pushdemo.services.NotificationActionService import com.<your_organization>.pushdemo.services.NotificationRegistrationService import io.flutter.embedding.android.FlutterActivity
Note
Remplacez <your_organization> par votre propre valeur d’organisation.
Ajoutez une variable pour stocker une référence au DeviceInstallationService.
private lateinit var deviceInstallationService: DeviceInstallationService
Ajoutez une fonction appelée
processNotificationActions pour vérifier si un intentiona une valeur supplémentaire nommée action . Déclenchez conditionnellement cette action ou stockez-la pour une utilisation ultérieure si l’action est traitée pendant le lancement de l’application.private fun processNotificationActions(intent: Intent, launchAction: Boolean = false) { if (intent.hasExtra("action")) { var action = intent.getStringExtra("action"); if (action.isNotEmpty()) { if (launchAction) { PushNotificationsFirebaseMessagingService.notificationActionService?.launchAction = action } else { PushNotificationsFirebaseMessagingService.notificationActionService?.triggerAction(action) } } } }
Remplacez la fonction onNewIntent pour appeler processNotificationActions.
override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) processNotificationActions(intent) }
Note
Étant donné que le LaunchMode de
MainActivity est défini surSingleTop , un intention desera envoyé à l’instance d’activité existante via le sur Fonction NewIntent plutôt que la fonctiononCreate . Vous devez donc gérer uned’intention entrante dans les fonctionsonCreate etonNewIntent .Substituez la fonction
onCreate , définissez le deviceInstallationServicesur une nouvelle instance de DeviceInstallationService .override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) flutterEngine?.let { deviceInstallationService = DeviceInstallationService(context, it) } }
Définissez les propriétés notificationActionService et notificationRegistrationService sur PushNotificationFirebaseMessagingServices.
flutterEngine?.let { deviceInstallationService = DeviceInstallationService(context, it) PushNotificationsFirebaseMessagingService.notificationActionService = NotificationActionService(it) PushNotificationsFirebaseMessagingService.notificationRegistrationService = NotificationRegistrationService(it) }
Dans la même fonction, appelez conditionnellement FirebaseInstanceId.getInstance().instanceId. Implémentez le OnCompleteListener
pour définir la valeur de jeton obtenue sur PushNotificationFirebaseMessagingService avant d’appelerrefreshRegistration .if(deviceInstallationService?.playServicesAvailable) { FirebaseInstanceId.getInstance().instanceId .addOnCompleteListener(OnCompleteListener { task -> if (!task.isSuccessful) return@OnCompleteListener PushNotificationsFirebaseMessagingService.token = task.result?.token PushNotificationsFirebaseMessagingService.notificationRegistrationService?.refreshRegistration() }) }
Toujours dans onCreate, appelez processNotificationActions à la fin de la fonction. Utilisez
true pour l’argument launchActionpour indiquer que cette action est en cours de traitement pendant le lancement de l’application. processNotificationActions(this.intent, true)
Note
Vous devez réinscrire l’application chaque fois que vous l’exécutez et l’arrêter d’une session de débogage pour continuer à recevoir des notifications Push.
Configurer le projet iOS natif pour les notifications Push
Configurer la cible d’exécuteur et Info.plist
Dans visual Studio Code, Control + Cliquez sur dans le dossier ios, puis choisissez Ouvrir dans Xcode.
Dans
Xcode, cliquez sur Runner ( xcodeproj en haut, et non sur le dossier), puis sélectionnez la cible Runner, puis Signature & Fonctionnalités . Une fois la configuration de buildsélectionnée, choisissez votre compte développeur pour l'de l’équipe . Vérifiez que l’option « Gérer automatiquement la signature » est cochée et que votre certificat de signature et votre profil d’approvisionnement sont automatiquement sélectionnés. Note
Si vous ne voyez pas la nouvelle valeur de profil d’approvisionnement, essayez d’actualiser les profils de l’identité de signature en sélectionnant Xcode>Préférences>Compte, puis sélectionnez le bouton Télécharger les profils manuels pour télécharger les profils.
Cliquez sur +de fonctionnalité, puis recherchez notifications Push. double-cliquez sur sur notifications Push pour ajouter cette fonctionnalité.
Ouvrez Info.plist et définissez version minimale du système sur 13.0.
Note
Seuls les appareils exécutant iOS 13.0 et versions ultérieures sont pris en charge pour les besoins de ce didacticiel, mais vous pouvez l’étendre pour prendre en charge les appareils exécutant des versions antérieures.
Ouvrez Runner.entitlements et vérifiez que le paramètre environnement APS est défini sur de développement.
Gérer les notifications Push pour iOS
Control Cliquez sur dans le dossier Runner(dans le projet Runner), puis choisissez nouveau groupe à l’aide deServices comme nom.Control Cliquez sur dans le dossier services de, puis choisissez Nouveau fichier... . Ensuite, choisissezSwift File, puis cliquez sur suivant. Spécifiez deviceInstallationService pour le nom, puis cliquez sur Créer. Implémentez DeviceInstallationService.swift à l’aide du code suivant.
import Foundation class DeviceInstallationService { enum DeviceRegistrationError: Error { case notificationSupport(message: String) } var token : Data? = nil let DEVICE_INSTALLATION_CHANNEL = "com.<your_organization>.pushdemo/deviceinstallation" let GET_DEVICE_ID = "getDeviceId" let GET_DEVICE_TOKEN = "getDeviceToken" let GET_DEVICE_PLATFORM = "getDevicePlatform" private let deviceInstallationChannel : FlutterMethodChannel var notificationsSupported : Bool { get { if #available(iOS 13.0, *) { return true } else { return false } } } init(withBinaryMessenger binaryMessenger : FlutterBinaryMessenger) { deviceInstallationChannel = FlutterMethodChannel(name: DEVICE_INSTALLATION_CHANNEL, binaryMessenger: binaryMessenger) deviceInstallationChannel.setMethodCallHandler(handleDeviceInstallationCall) } func getDeviceId() -> String { return UIDevice.current.identifierForVendor!.description } func getDeviceToken() throws -> String { if(!notificationsSupported) { let notificationSupportError = getNotificationsSupportError() throw DeviceRegistrationError.notificationSupport(message: notificationSupportError) } if (token == nil) { throw DeviceRegistrationError.notificationSupport(message: "Unable to resolve token for APNS.") } return token!.reduce("", {$0 + String(format: "%02X", $1)}) } func getDevicePlatform() -> String { return "apns" } private func handleDeviceInstallationCall(call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case GET_DEVICE_ID: result(getDeviceId()) case GET_DEVICE_TOKEN: getDeviceToken(result: result) case GET_DEVICE_PLATFORM: result(getDevicePlatform()) default: result(FlutterMethodNotImplemented) } } private func getDeviceToken(result: @escaping FlutterResult) { do { let token = try getDeviceToken() result(token) } catch let error { result(FlutterError(code: "UNAVAILABLE", message: error.localizedDescription, details: nil)) } } private func getNotificationsSupportError() -> String { if (!notificationsSupported) { return "This app only supports notifications on iOS 13.0 and above. You are running \(UIDevice.current.systemVersion)" } return "An error occurred preventing the use of push notifications." } }
Note
Cette classe implémente l’équivalent spécifique à la plateforme pour le canal
com.<your_organization>.pushdemo/deviceinstallation
. Cela a été défini dans la partie Flutter de l’application dans DeviceInstallationService.dart. Dans ce cas, les appels sont effectués à partir du code commun vers l’hôte natif. Veillez à remplacer <your_organization> par votre propre organisation où cela est utilisé.Cette classe fournit un ID unique (à l’aide de la valeur UIDevice.identifierForVendor) dans le cadre de la charge utile d’inscription du hub de notification.
Ajoutez un autre
fichier Swift au dossier servicesappelé NotificationRegistrationService , puis ajoutez le code suivant.import Foundation class NotificationRegistrationService { let NOTIFICATION_REGISTRATION_CHANNEL = "com.<your_organization>.pushdemo/notificationregistration" let REFRESH_REGISTRATION = "refreshRegistration" private let notificationRegistrationChannel : FlutterMethodChannel init(withBinaryMessenger binaryMessenger : FlutterBinaryMessenger) { notificationRegistrationChannel = FlutterMethodChannel(name: NOTIFICATION_REGISTRATION_CHANNEL, binaryMessenger: binaryMessenger) } func refreshRegistration() { notificationRegistrationChannel.invokeMethod(REFRESH_REGISTRATION, arguments: nil) } }
Note
Cette classe implémente l’équivalent spécifique à la plateforme pour le canal
com.<your_organization>.pushdemo/notificationregistration
. Cela a été défini dans la partie Flutter de l’application dans NotificationRegistrationService.dart. Dans ce cas, les appels sont effectués de l’hôte natif vers le code commun. Là encore, veillez à remplacer <your_organization> par votre propre organisation où cela est utilisé.Ajoutez un autre
fichier Swift au dossier servicesappelé NotificationActionService , puis ajoutez le code suivant.import Foundation class NotificationActionService { let NOTIFICATION_ACTION_CHANNEL = "com.<your_organization>.pushdemo/notificationaction" let TRIGGER_ACTION = "triggerAction" let GET_LAUNCH_ACTION = "getLaunchAction" private let notificationActionChannel: FlutterMethodChannel var launchAction: String? = nil init(withBinaryMessenger binaryMessenger: FlutterBinaryMessenger) { notificationActionChannel = FlutterMethodChannel(name: NOTIFICATION_ACTION_CHANNEL, binaryMessenger: binaryMessenger) notificationActionChannel.setMethodCallHandler(handleNotificationActionCall) } func triggerAction(action: String) { notificationActionChannel.invokeMethod(TRIGGER_ACTION, arguments: action) } private func handleNotificationActionCall(call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case GET_LAUNCH_ACTION: result(launchAction) default: result(FlutterMethodNotImplemented) } } }
Note
Cette classe implémente l’équivalent spécifique à la plateforme pour le canal
com.<your_organization>.pushdemo/notificationaction
. Cela a été défini dans la partie Flutter de l’application dans NotificationActionService.dart. Les appels peuvent être effectués dans les deux sens dans ce cas. Veillez à remplacer <your_organization> par votre propre organisation où cela est utilisé.Dans appDelegate.swift, ajoutez des variables pour stocker une référence aux services que vous avez créés précédemment.
var deviceInstallationService : DeviceInstallationService? var notificationRegistrationService : NotificationRegistrationService? var notificationActionService : NotificationActionService?
Ajoutez une fonction appelée processNotificationActions pour le traitement des données de notification. Déclenchez conditionnellement cette action ou stockez-la pour une utilisation ultérieure si l’action est traitée pendant le lancement de l’application.
func processNotificationActions(userInfo: [AnyHashable : Any], launchAction: Bool = false) { if let action = userInfo["action"] as? String { if (launchAction) { notificationActionService?.launchAction = action } else { notificationActionService?.triggerAction(action: action) } } }
Remplacez la fonction
didRegisterForRemoteNotificationsWithDeviceToken définissant la valeur du jetonpour leDeviceInstallationService notificationRegistrationService. Ensuite, appelez refreshRegistration sur le. override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { deviceInstallationService?.token = deviceToken notificationRegistrationService?.refreshRegistration() }
Substituez la fonction
didReceiveRemoteNotification en passant l’argument userInfoà la fonction processNotificationActions . override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) { processNotificationActions(userInfo: userInfo) }
Remplacez la fonction didFailToRegisterForRemoteNotificationsWithError pour consigner l’erreur.
override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { print(error); }
Note
Il s’agit d’un espace réservé. Vous souhaiterez implémenter la journalisation et la gestion des erreurs appropriées pour les scénarios de production.
Dans
didFinishLaunchingWithOptions , instanciez les variablesdeviceInstallationService, notificationRegistrationService etnotificationActionService .let controller : FlutterViewController = window?.rootViewController as! FlutterViewController deviceInstallationService = DeviceInstallationService(withBinaryMessenger: controller.binaryMessenger) notificationRegistrationService = NotificationRegistrationService(withBinaryMessenger: controller.binaryMessenger) notificationActionService = NotificationActionService(withBinaryMessenger: controller.binaryMessenger)
Dans la même fonction, demandez de manière conditionnelle l’autorisation et inscrivez-vous aux notifications à distance.
if #available(iOS 13.0, *) { UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in if (granted) { DispatchQueue.main.async { let pushSettings = UIUserNotificationSettings(types: [.alert, .sound, .badge], categories: nil) application.registerUserNotificationSettings(pushSettings) application.registerForRemoteNotifications() } } } }
Si le launchOptions
contient la clé userInforemoteNotification, appelez processNotificationActions à la fin de la fonctiondidFinishLaunchingWithOptions . Transmettez l’objetrésultant et utilisez true pour l’argumentlaunchAction . Une valeur true indique que l’action est en cours de traitement pendant le lancement de l’application.if let userInfo = launchOptions?[.remoteNotification] as? [AnyHashable : Any] { processNotificationActions(userInfo: userInfo, launchAction: true) }
Tester la solution
Vous pouvez maintenant tester l’envoi de notifications via le service principal.
Envoyer une notification de test
Ouvrez un nouvel onglet dans Postman.
Définissez la requête sur POST, puis entrez l’adresse suivante :
https://<app_name>.azurewebsites.net/api/notifications/requests
Si vous avez choisi de terminer la section Authentifier les clients à l’aide d’une clé API section, veillez à configurer les en-têtes de requête pour inclure votre valeur apikey.
Clé Valeur apikey <your_api_key> Choisissez l’option brute pour le corps , puis choisissez JSON dans la liste des options de format, puis incluez un espace réservé contenu json :
{ "text": "Message from Postman!", "action": "action_a" }
Sélectionnez le bouton Code, qui se trouve sous le bouton Enregistrer en haut à droite de la fenêtre. La requête doit ressembler à l’exemple suivant lorsqu’elle s’affiche pour HTML (selon que vous avez inclus un apikey en-tête) :
POST /api/notifications/requests HTTP/1.1 Host: https://<app_name>.azurewebsites.net apikey: <your_api_key> Content-Type: application/json { "text": "Message from backend service", "action": "action_a" }
Exécutez l’application PushDemo
sur une ou les deux plateformes cibles ( Android et iOS). Note
Si vous effectuez des tests sur Android assurez-vous que vous n’êtes pas en cours d’exécution dans déboguer, ou si l’application a été déployée en exécutant l’application, forcez la fermeture de l’application et redémarrez-la à partir du lanceur.
Dans l’application PushDemo, appuyez sur le bouton Inscrire.
De retour dans Postman, fermez la fenêtre Générer des extraits de code (si vous ne l’avez pas déjà fait), puis cliquez sur le bouton Envoyer.
Vérifiez que vous obtenez une réponse 200 OK dans Postman et que l’alerte s’affiche dans l’application montrant action ActionA reçue.
Fermez l’application PushDemo
, puis cliquez à nouveau sur le bouton Envoyer dans Postman.Vérifiez que vous obtenez à nouveau une réponse 200 OK dans Postman. Vérifiez qu’une notification s’affiche dans la zone de notification de l’application PushDemo
avec le message correct. Appuyez sur la notification pour confirmer qu’elle ouvre l’application et affiche l’action ActionA reçue alerte.
De retour dans Postman, modifiez le corps de la demande précédente pour envoyer une notification silencieuse spécifiant action_b au lieu de action_a pour l’action de valeur.
{ "action": "action_b", "silent": true }
Une fois l’application toujours ouverte, cliquez sur le bouton Envoyer dans Postman.
Vérifiez que vous obtenez une réponse 200 OK dans Postman et que l’alerte apparaît dans l’application montrant action ActionB reçue au lieu d'action ActionA reçue.
Fermez l’application PushDemo
, puis cliquez à nouveau sur le bouton Envoyer dans Postman.Vérifiez que vous obtenez une réponse 200 OK dans Postman et que la notification silencieuse n’apparaît pas dans la zone de notification.
Dépannage
Aucune réponse du service back-end
Lors du test local, assurez-vous que le service back-end est en cours d’exécution et utilise le port approprié.
Si vous effectuez des tests sur l’application API Azure , vérifiez que le service est en cours d’exécution et a été déployé et a démarré sans erreur.
Veillez à vérifier que vous avez spécifié correctement l’adresse de base dans Postman ou dans la configuration de l’application mobile lors du test via le client. L’adresse de base doit être https://<api_name>.azurewebsites.net/
ou https://localhost:5001/
lors du test localement.
Ne pas recevoir de notifications sur Android après le démarrage ou l’arrêt d’une session de débogage
Veillez à vous réinscrire après le démarrage ou l’arrêt d’une session de débogage. Le débogueur entraîne la génération d’un nouveau jeton Firebase
Réception d’un code d’état 401 à partir du service principal
Vérifiez que vous définissez l’en-tête de requête apikey
Si vous recevez cette erreur lors du test localement, vérifiez que la valeur de clé que vous avez définie dans la configuration du client correspond à la valeur Authentication :ApiKey paramètre utilisateur utilisée par l’API .
Si vous effectuez des tests avec une application API , vérifiez que la valeur de clé dans le fichier de configuration du client correspond au paramètre d’application Authentication :ApiKey que vous utilisez dans l’application API .
Note
Si vous avez créé ou modifié ce paramètre après avoir déployé le service principal, vous devez redémarrer le service pour qu’il prenne effet.
Si vous avez choisi de ne pas terminer la section Authentifier les clients à l’aide d’une clé API, vérifiez que vous n’avez pas appliqué l’attribut Autoriser à la classe NotificationsController.
Réception d’un code d’état 404 à partir du service principal
Vérifiez que le point de terminaison et la méthode de requête HTTP sont corrects. Par exemple, les points de terminaison doivent être :
[PUT] [DELETE] -
[POST]
https://<api_name>.azurewebsites.net/api/notifications/requests
Ou lors du test local :
[PUT] [DELETE] -
[POST]
https://localhost:5001/api/notifications/requests
Lorsque vous spécifiez l’adresse de base dans l’application cliente, assurez-vous qu’elle se termine par un /
. L’adresse de base doit être https://<api_name>.azurewebsites.net/
ou https://localhost:5001/
lors du test localement.
Impossible d’inscrire et un message d’erreur du hub de notification s’affiche
Vérifiez que l’appareil de test dispose d’une connectivité réseau. Ensuite, déterminez le code d’état de la réponse Http en définissant un point d’arrêt pour inspecter la valeur de propriété
Passez en revue les suggestions de résolution des problèmes précédentes, le cas échéant, en fonction du code d’état.
Définissez un point d’arrêt sur les lignes qui retournent ces codes d’état spécifiques pour l’API respective. Essayez ensuite d’appeler le service principal lors du débogage localement.
Vérifiez que le service principal fonctionne comme prévu via Postman à l’aide de la charge utile appropriée. Utilisez la charge utile réelle créée par le code client pour la plateforme en question.
Passez en revue les sections de configuration spécifiques à la plateforme pour vous assurer qu’aucune procédure n’a été manquée. Vérifiez que les valeurs appropriées sont résolues pour installation id
et token
variables pour la plateforme appropriée.
Impossible de résoudre un ID pour le message d’erreur de l’appareil s’affiche
Passez en revue les sections de configuration spécifiques à la plateforme pour vous assurer qu’aucune procédure n’a été manquée.
Liens connexes
- Vue d’ensemble Azure Notification Hubs
- installation de Flutter sur macOS
- installation de Flutter sur Windows
- Kit de développement logiciel (SDK) Notification Hubs pour les opérations principales
- Kit de développement logiciel (SDK) Notification Hubs sur GitHub
- Inscrire auprès du serveur principal d’application
- de gestion des inscriptions
- Utilisation des étiquettes
- Utilisation de modèles personnalisés
Étapes suivantes
Vous devez maintenant disposer d’une application Flutter de base connectée à un hub de notification via un service principal et recevoir des notifications.
Vous devrez probablement adapter l’exemple utilisé dans ce tutoriel pour qu’il corresponde à votre propre scénario. L’implémentation d’une gestion des erreurs plus robuste, une logique de nouvelle tentative et la journalisation sont également recommandées.
Visual Studio App Center peut être rapidement incorporé dans des applications mobiles fournissant des analytique et des diagnostics pour faciliter la résolution des problèmes.