Condividi tramite


Esercitazione: Inviare notifiche push alle app MAUI .NET usando Hub di notifica di Azure tramite un servizio back-end

Sfogliare l'esempio. Esplorare l'esempio

Le notifiche push recapitano informazioni da un sistema back-end a un'app client. Apple, Google e altre piattaforme dispongono di un proprio servizio PNS (Push Notification Service). Hub di notifica di Azure consente di centralizzare le notifiche tra piattaforme in modo che l'app back-end possa comunicare con un singolo hub, che si occupa della distribuzione delle notifiche a ogni PNS.

Hub di notifica di Azure richiede che le app si registrino con l'hub e, facoltativamente, definisci modelli e/o sottoscrivono i tag:

  • L'esecuzione di un'installazione del dispositivo collega un handle PNS a un identificatore nell'hub di notifica di Azure. Per altre informazioni sulle registrazioni, vedere Gestione della registrazione.
  • I modelli consentono ai dispositivi di specificare modelli di messaggio con parametri. I messaggi in arrivo possono essere personalizzati per ogni dispositivo. Per altre informazioni, vedere Modelli di Hub di notifica.
  • I tag possono essere usati per sottoscrivere categorie di messaggi come notizie, sport e meteo. Per altre informazioni, vedere Routing ed espressioni tag.

In questa esercitazione si useranno Hub di notifica di Azure per inviare notifiche push a un'app .NET multipiattaforma (.NET MAUI) destinata ad Android e iOS. Un back-end dell'API Web core ASP.NET viene usato per gestire la registrazione del dispositivo per il client e per avviare una notifica push. Queste operazioni vengono gestite usando il pacchetto NuGet Microsoft.Azure.NotificationHubs . Per altre informazioni sull'approccio generale, vedere Gestione della registrazione da un back-end.

In questa esercitazione:

  • Configurare i servizi di notifica push e l'hub di notifica di Azure.
  • Creare un'app back-end WebAPI core ASP.NET.
  • Creare un'app .NET MAUI.
  • Configurare l'app Android per le notifiche push.
  • Configurare l'app iOS per le notifiche push.
  • Test dell'app.
  • Risolvere eventuali problemi di installazione e configurazione.

Prerequisiti

Per completare questa esercitazione, è necessario:

  • Un account Azure con una sottoscrizione attiva.
  • Un PC o Mac che esegue la versione più recente di Visual Studio/Visual Studio Code con il carico di lavoro Sviluppo dell'interfaccia utente app multipiattaforma .NET e i carichi di lavoro di sviluppo ASP.NET e Web installati.

Per Android, è necessario avere:

  • Uno sviluppatore ha sbloccato un dispositivo fisico o un emulatore che esegue l'API 26+ con Google Play Services installato.

Per iOS, è necessario avere:

  • Un account sviluppatore Apple attivo.
  • Un Mac che esegue Xcode, insieme a un certificato dello sviluppatore valido installato nel portachiavi.

Quindi, in iOS è necessario avere:

  • Simulatore iOS 16+ in esecuzione in macOS 13+ su computer Mac con processori Apple silicon o T2.

    OPPURE

  • Un dispositivo iOS fisico registrato nell'account per sviluppatore (che esegue iOS 13.0+).

  • Il dispositivo fisico registrato nell'account sviluppatore Apple e associato al certificato.

Importante

Il simulatore iOS supporta le notifiche remote in iOS 16+ durante l'esecuzione in macOS 13+ nei computer Mac con processori Apple silicon o T2. Se non si soddisfano questi requisiti hardware, è necessario un account sviluppatore Apple attivo e un dispositivo fisico.

Per seguire questa esercitazione, è necessario avere familiarità con:

Anche se questa esercitazione è destinata a Visual Studio, è possibile seguirla usando Visual Studio Code in un PC o Mac. Tuttavia, ci saranno alcune differenze che richiedono la riconciliazione. Ad esempio, le descrizioni dell'interfaccia utente e dei flussi di lavoro, i nomi dei modelli e la configurazione dell'ambiente.

Configurare i servizi di notifica push e l'hub di notifica di Azure

In questa sezione verrà configurato Firebase Cloud Messaging e Apple Push Notification Services (APNS). Si creerà e si configurerà quindi un hub di notifica di Azure per l'uso di questi servizi.

Creare un progetto Firebase

Per creare un progetto Firebase:

  1. In un Web browser accedere alla console firebase.

  2. Nella console firebase selezionare il pulsante Aggiungi progetto e creare un nuovo progetto Firebase, immettendo PushDemo come nome progetto.

    Nota

    Verrà generato automaticamente un nome univoco. Per impostazione predefinita, si tratta di una variante minuscola del nome specificato più un numero generato separato da un trattino. Se lo si desidera, è possibile modificarlo, purché le modifiche siano ancora univoche a livello globale.

  3. Dopo aver creato il progetto, selezionare il logo Android per aggiungere Firebase a un'app Android:

    Screenshot dell'aggiunta di Firebase a un'app Android nella console di Firebase Cloud Messaging.

  4. Nella pagina Aggiungi Firebase all'app Android immettere un nome per il pacchetto, facoltativamente un nome alternativo dell'app e selezionare il pulsante Registra app:

    Screenshot della registrazione dell'app Android con Firebase.

  5. Nella pagina Aggiungi Firebase all'app Android selezionare il pulsante Scarica google-services.json e salvare il file in una cartella locale prima di selezionare il pulsante Avanti:

    Screenshot del download del file JSON dei servizi Google.

  6. Nella pagina Aggiungi Firebase all'app Android selezionare il pulsante Avanti.

  7. Nella pagina Aggiungi Firebase all'app Android selezionare il pulsante Continua nella console.

  8. Nella console firebase selezionare l'icona Panoramica progetto e quindi selezionare Impostazioni progetto:

    Screenshot della selezione delle impostazioni del progetto nella console di Firebase Cloud Messaging.

  9. Nelle impostazioni del progetto selezionare la scheda Messaggistica cloud. Si noterà che Firebase Cloud Messaging API (V1) è abilitato:

    Screenshot che conferma che Firebase Cloud Messaging V1 è abilitato.

  10. In Impostazioni progetto selezionare la scheda Account di servizio e quindi selezionare il pulsante Genera nuova chiave privata.

  11. Nella finestra di dialogo Genera nuova chiave privata selezionare il pulsante Genera chiave:

    Screenshot della generazione di una nuova chiave privata nella console di Firebase Cloud Messaging.

    Verrà scaricato un file JSON che conterrà i valori immessi nell'hub di notifica di Azure.

Registrare l'app iOS per le notifiche push

Per inviare notifiche push a un'app iOS è necessario registrare l'app con Apple e registrarsi per le notifiche push. A tale scopo, eseguire la procedura descritta nella documentazione di Hub di notifica di Azure seguente:

Se vuoi ricevere notifiche push in un dispositivo fisico, dovrai anche creare un profilo di provisioning.

Importante

Per ricevere notifiche in background in iOS, devi aggiungere la modalità in background delle notifiche remote alla tua app. Per altre informazioni, vedere Abilitare la funzionalità di notifiche remote in developer.apple.com.

Creare un hub di notifica di Azure

Per creare un hub di notifica nel portale di Azure:

  1. In un Web browser accedere al portale di Azure.
  2. Nella portale di Azure fare clic sul pulsante Crea una risorsa e quindi cercare e scegliere Hub di notifica prima di selezionare il pulsante Crea.
  3. Nella pagina Hub di notifica seguire questa procedura:
    1. Nel campo Sottoscrizione selezionare il nome della sottoscrizione di Azure che si vuole usare e quindi selezionare un gruppo di risorse esistente o crearne uno nuovo.

    2. Nel campo Dettagli spazio dei nomi immettere un nome univoco per il nuovo spazio dei nomi.

    3. Nel campo Dettagli hub di notifica digitare un nome per l'hub di notifica. Questa operazione è necessaria perché uno spazio dei nomi contiene uno o più hub di notifica.

    4. Nell'elenco a discesa Località selezionare un valore che specifica il percorso in cui si vuole creare l'hub di notifica.

    5. Esaminare l'opzione Zone di disponibilità. Se si sceglie un'area con zone di disponibilità, la casella di controllo è selezionata per impostazione predefinita.

      Nota

      Le zone di disponibilità sono una funzionalità a pagamento, quindi viene aggiunta una tariffa aggiuntiva al livello.

    6. Scegliere un'opzione di ripristino di emergenza: nessuna, area di ripristino abbinata o area di ripristino flessibile. Se si sceglie Area di ripristino abbinata, viene visualizzata l'area di failover. Se si seleziona Area di ripristino flessibile, usare l'elenco a discesa per scegliere tra un elenco di aree di ripristino.

    7. Selezionare il pulsante Crea. Verrà creato l'hub di notifica.

  4. Nel portale di Azure passare all'hub di notifica appena creato e quindi al pannello Gestisci criteri > di accesso.
  5. Nel pannello Criteri di accesso prendere nota del stringa di connessione per il DefaultFullSharedAccessSignature criterio. Questa operazione sarà necessaria in un secondo momento quando si compila un servizio back-end che comunica con l'hub di notifica.

Per altre informazioni sulla creazione di un hub di notifica, vedere Creare un hub di notifica di Azure nel portale di Azure.

Configurare Firebase Cloud Messaging nell'hub di notifica

Per configurare l'hub di notifica per comunicare con Firebase Cloud Messaging:

  1. Nel portale di Azure passare all'hub di notifica e selezionare il pannello Impostazioni > Google (FCM v1).

  2. Nel pannello Google (FCM v1) immettere i valori per i campi Chiave privata, Posta elettronica client e ID progetto. Questi valori sono disponibili nel file JSON della chiave privata scaricato da Firebase Cloud Messaging:

    Campo di Azure Chiave JSON Esempio di valore JSON
    Chiave privata private_key Questo valore deve iniziare con e terminare con -----BEGIN PRIVATE KEY-----\n -----END PRIVATE KEY-----\n.
    Client Email client_email firebase-adminsdk-55sfg@pushdemo-d6ab2.iam.gserviceaccount.com
    ID progetto project_id pushdemo-d6ab2
  3. Nel pannello Google (FCM v1) selezionare il pulsante Salva .

Configurare Apple Push Notification Service nell'hub di notifica

Nel portale di Azure passare all'hub di notifica e selezionare il pannello Impostazioni > Apple (APNS). Seguire quindi i passaggi appropriati in base all'approccio scelto in precedenza durante la creazione di un certificato per l'hub di notifica.

Importante

Quando si imposta la modalità applicazione, scegliere Produzione solo se si vogliono inviare notifiche push agli utenti che hanno acquistato l'app dallo Store.

Opzione 1- Usare un certificato push p12

  1. Nel pannello Apple (APNS) selezionare la modalità di autenticazione del certificato .
  2. Nel pannello Apple (APNS) selezionare l'icona del file accanto al campo Carica certificato . Selezionare quindi il file con estensione p12 esportato in precedenza e caricarlo.
  3. Nel pannello Apple (APNS) immettere la password del certificato nel campo Password , se necessario.
  4. Nel pannello Apple (APNS) selezionare la modalità applicazione Sandbox .
  5. Nel pannello Apple (APNS) selezionare il pulsante Salva .

Opzione 2- Usare l'autenticazione basata su token

  1. Nel pannello Apple (APNS) selezionare la modalità di autenticazione del token .
  2. Nel pannello Apple (APNS) immettere i valori acquisiti in precedenza per i campi ID chiave, ID bundle, ID team e Token.
  3. Nel pannello Apple (APNS) selezionare la modalità applicazione Sandbox .
  4. Nel pannello Apple (APNS) selezionare il pulsante Salva .

Creare un'app back-end dell'API Web di ASP.NET Core

In questa sezione si creerà un back-end dell'API Web di ASP.NET Core per gestire l'installazione del dispositivo e l'invio di notifiche all'app MAUI .NET.

Creare un progetto di API Web

Per creare un progetto API Web:

  1. In Visual Studio creare un progetto API Web di ASP.NET Core:

    Screenshot della creazione di un nuovo progetto API Web di ASP.NET Core in Visual Studio.

  2. Nella finestra di dialogo Configura il nuovo progetto assegnare al progetto il nome PushNotificationsAPI.

  3. Nella finestra di dialogo Informazioni aggiuntive assicurarsi che le caselle di controllo Configura per HTTPS e Usa controller siano abilitate:

    Screenshot della configurazione del progetto API Web core di ASP.NET in Visual Studio.

  4. Dopo aver creato il progetto, premere F5 per eseguire il progetto.

    L'app è attualmente configurata per l'uso WeatherForecastController di come launchUrl, impostato nel file Properties\launchSettings.json . L'app verrà avviata in un Web browser e visualizzerà alcuni dati JSON.

    Importante

    Quando si esegue un progetto ASP.NET Core che usa HTTPS, Visual Studio rileverà se il certificato di sviluppo HTTPS di ASP.NET Core è installato nell'archivio certificati utente locale e offrirà di installarlo e considerarlo attendibile se manca.

  5. Chiudere il Web browser.

  6. In Esplora soluzioni espandere la cartella Controller ed eliminare WeatherForecastController.cs.

  7. In Esplora soluzioni, nella radice del progetto, eliminare WeatherForecast.cs.

  8. Aprire una finestra di comando e passare alla directory che contiene il file di progetto. Eseguire quindi i comandi seguenti:

    dotnet user-secrets init
    dotnet user-secrets set "NotificationHub:Name" <value>
    dotnet user-secrets set "NotificationHub:ConnectionString" "<value>"
    

    Sostituire i valori segnaposto con il nome dell'hub di notifica di Azure e i valori stringa di connessione. Queste informazioni sono disponibili nelle posizioni seguenti nell'hub di notifica di Azure:

    Valore di configurazione Ufficio
    NotificationHub:Name Vedere Nome nel riepilogo Informazioni di base nella parte superiore della pagina Panoramica .
    NotificationHub:ConnectinString Vedere DefaultFullSharedAccessSignature* nella pagina Criteri di accesso.

    In questo modo vengono impostati i valori di configurazione locali usando lo strumento Secret Manager. In questo modo i segreti dell'hub di notifica di Azure vengono disaccoppiato dalla soluzione Visual Studio per assicurarsi che non finisano nel controllo del codice sorgente.

    Suggerimento

    Per gli scenari di produzione, prendere in considerazione un servizio come Azure KeyVault per archiviare in modo sicuro il stringa di connessione.

Autenticare i client con una chiave API

Per autenticare i client con una chiave API:

  1. Aprire una finestra di comando e passare alla directory che contiene il file di progetto. Eseguire quindi i comandi seguenti:

    dotnet user-secrets set "Authentication:ApiKey" <value>
    

    Sostituire il valore segnaposto con la chiave API, che può essere qualsiasi valore.

  2. In Visual Studio aggiungere una nuova cartella denominata Authentication al progetto e quindi aggiungere una nuova classe denominata ApiKeyAuthOptions alla cartella Authentication e sostituirla con il codice seguente:

    using Microsoft.AspNetCore.Authentication;
    
    namespace PushNotificationsAPI.Authentication;
    
    public class ApiKeyAuthOptions : AuthenticationSchemeOptions
    {
        public const string DefaultScheme = "ApiKey";
        public string Scheme => DefaultScheme;
        public string ApiKey { get; set; }
    }
    
  3. In Visual Studio aggiungere una nuova classe denominata ApiKeyAuthHandler alla cartella Authentication e sostituirla con il codice seguente:

    using Microsoft.AspNetCore.Authentication;
    using Microsoft.Extensions.Options;
    using System.Security.Claims;
    using System.Text.Encodings.Web;
    
    namespace PushNotificationsAPI.Authentication;
    
    public class ApiKeyAuthHandler : AuthenticationHandler<ApiKeyAuthOptions>
    {
        const string ApiKeyIdentifier = "apikey";
    
        public ApiKeyAuthHandler(
            IOptionsMonitor<ApiKeyAuthOptions> options,
            ILoggerFactory logger,
            UrlEncoder encoder)
            : base(options, logger, encoder)
        {
        }
    
        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));
        }
    }
    

    Un gestore di autenticazione è un tipo che implementa il comportamento di uno schema, che in questo caso è uno schema di chiave API personalizzato.

  4. In Visual Studio aggiungere una nuova classe denominata AuthenticationBuilderExtensions alla cartella Authentication e sostituirla con il codice seguente:

    using Microsoft.AspNetCore.Authentication;
    
    namespace PushNotificationsAPI.Authentication;
    
    public static class AuthenticationBuilderExtensions
    {
      public static AuthenticationBuilder AddApiKeyAuth(
          this AuthenticationBuilder builder,
          Action<ApiKeyAuthOptions> configureOptions)
        {
            return builder
                .AddScheme<ApiKeyAuthOptions, ApiKeyAuthHandler>(
                ApiKeyAuthOptions.DefaultScheme,
                configureOptions);
        }
    }
    

    Questo metodo di estensione verrà usato per semplificare il codice di configurazione del middleware in Program.cs.

  5. In Visual Studio aprire Program.cs e aggiornare il codice per configurare l'autenticazione della chiave API sotto la chiamata al builder.Services.AddControllers metodo :

    using PushNotificationsAPI.Authentication;
    
    builder.Services.AddControllers();
    
    builder.Services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = ApiKeyAuthOptions.DefaultScheme;
        options.DefaultChallengeScheme = ApiKeyAuthOptions.DefaultScheme;
    }).AddApiKeyAuth(builder.Configuration.GetSection("Authentication").Bind);
    
  6. In Program.cs aggiornare il codice sotto il // Configure the HTTP request pipeline commento per chiamare i UseRoutingmetodi di estensione , UseAuthenticatione MapControllers :

    // Configure the HTTP request pipeline.
    
    app.UseHttpsRedirection();
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    app.MapControllers();
    
    app.Run();
    

    Il UseAuthentication metodo di estensione registra il middleware che usa lo schema di autenticazione registrato in precedenza. UseAuthentication deve essere chiamato prima di qualsiasi middleware che dipende dall'autenticazione degli utenti.

    Nota

    Anche se una chiave API non è sicura come un token, è sufficiente per questa esercitazione e può essere configurata facilmente tramite il middleware ASP.NET.

Aggiungere e configurare i servizi

Per aggiungere e configurare servizi nell'app back-end dell'API Web:

  1. In Visual Studio aggiungere il pacchetto NuGet Microsoft.Azure.NotificationHubs al progetto. Questo pacchetto NuGet viene usato per accedere all'hub di notifica, incapsulato all'interno di un servizio.

  2. In Visual Studio aggiungere una nuova cartella denominata Models al progetto e quindi aggiungere una nuova classe denominata PushTemplates alla cartella Models e sostituirla con il codice seguente:

    namespace PushNotificationsAPI.Models;
    
    public class PushTemplates
    {
        public class Generic
        {
            public const string Android = "{ \"message\" : { \"notification\" : { \"title\" : \"PushDemo\", \"body\" : \"$(alertMessage)\"}, \"data\" : { \"action\" : \"$(alertAction)\" } } }";
            public const string iOS = "{ \"aps\" : {\"alert\" : \"$(alertMessage)\"}, \"action\" : \"$(alertAction)\" }";
        }
    
        public class Silent
        {
            public const string Android = "{ \"message\" : { \"data\" : {\"message\" : \"$(alertMessage)\", \"action\" : \"$(alertAction)\"} } }";
            public const string iOS = "{ \"aps\" : {\"content-available\" : 1, \"apns-priority\": 5, \"sound\" : \"\", \"badge\" : 0}, \"message\" : \"$(alertMessage)\", \"action\" : \"$(alertAction)\" }";
        }
    }
    

    La PushTemplates classe contiene payload di notifica con token per le notifiche push generiche e invisibile all'utente. Questi payload vengono definiti all'esterno dell'installazione per consentire la sperimentazione senza dover aggiornare le installazioni esistenti tramite il servizio. La gestione delle modifiche apportate alle installazioni in questo modo non rientra nell'ambito di questo articolo. Negli scenari di prodotto prendere in considerazione l'uso di modelli personalizzati.

  3. In Visual Studio aggiungere una nuova classe denominata DeviceInstallation alla cartella Models e sostituirla con il codice seguente:

    using System.ComponentModel.DataAnnotations;
    
    namespace PushNotificationsAPI.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>();
    }
    
  4. In Visual Studio aggiungere una nuova classe denominata NotificationRequest alla cartella Models e sostituirla con il codice seguente:

    namespace PushNotificationsAPI.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; }
    }
    
  5. In Visual Studio aggiungere una nuova classe denominata NotificationHubOptions alla cartella Models e sostituirla con il codice seguente:

    using System.ComponentModel.DataAnnotations;
    
    namespace PushNotificationsAPI.Models;
    
    public class NotificationHubOptions
    {
        [Required]
        public string Name { get; set; }
    
        [Required]
        public string ConnectionString { get; set; }
    }
    
  6. In Visual Studio aggiungere una nuova cartella denominata Services al progetto e quindi aggiungere una nuova interfaccia denominata INotificationService alla cartella Services e sostituirla con il codice seguente:

    using PushNotificationsAPI.Models;
    
    namespace PushNotificationsAPI.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);
    }
    
  7. In Visual Studio aggiungere una nuova classe denominata NotificationHubService alla cartella Services e sostituirla con il codice seguente:

    using Microsoft.Extensions.Options;
    using Microsoft.Azure.NotificationHubs;
    using PushNotificationsAPI.Models;
    
    namespace PushNotificationsAPI.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.FcmV1).ToLower(), NotificationPlatform.FcmV1 }
            };
        }
    
        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.SendFcmV1NativeNotificationAsync(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.SendFcmV1NativeNotificationAsync(androidPayload, tags, token),
                _hub.SendAppleNativeNotificationAsync(iOSPayload, tags, token)
            };
    
            return Task.WhenAll(sendTasks);
        }
    }
    

    L'espressione tag fornita al SendTemplateNotificationsAsync metodo è limitata a 20 tag se contengono solo ORS. In caso contrario, sono limitati a 6 tag. Per altre informazioni, vedere Routing ed espressioni tag.

  8. In Visual Studio aprire Program.cs e aggiornare il codice per aggiungere come NotificationHubService implementazione singleton di INotificationService sotto la chiamata al builder.Services.AddAuthentication metodo :

    using PushNotificationsAPI.Authentication;
    using PushNotificationsAPI.Services;
    using PushNotificationsAPI.Models;
    
    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    
    builder.Services.AddControllers();
    
    builder.Services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = ApiKeyAuthOptions.DefaultScheme;
        options.DefaultChallengeScheme = ApiKeyAuthOptions.DefaultScheme;
    }).AddApiKeyAuth(builder.Configuration.GetSection("Authentication").Bind);
    
    builder.Services.AddSingleton<INotificationService, NotificationHubService>();
    builder.Services.AddOptions<NotificationHubOptions>()
        .Configure(builder.Configuration.GetSection("NotificationHub").Bind)
        .ValidateDataAnnotations();
    
    var app = builder.Build();
    

Creare l'API REST per le notifiche

Per creare l'API REST delle notifiche:

  1. In Visual Studio aggiungere un nuovo controller denominato NotificationsController alla cartella Controllers .

    Suggerimento

    Scegliere il controller API con il modello di azioni di lettura/scrittura.

  2. Nel file NotificationsController.cs aggiungere le istruzioni seguenti using all'inizio del file:

    using System.ComponentModel.DataAnnotations;
    using System.Net;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using PushNotificationsAPI.Models;
    using PushNotificationsAPI.Services;
    
  3. Nel file NotificationsController.cs aggiungere l'attributo Authorize alla NotificationsController classe :

    [Authorize]
    [ApiController]
    [Route("api/[controller]")]
    public class NotificationsController : ControllerBase
    
  4. Nel file NotificationsController.cs aggiornare il NotificationsContoller costruttore per accettare l'istanza registrata di INotificationService come argomento e assegnarlo a un membro readonly:

    readonly INotificationService _notificationService;
    
    public NotificationsController(INotificationService notificationService)
    {
        _notificationService = notificationService;
    }
    
  5. Nel file NotificationsContoller.cs sostituire tutti i metodi con il codice seguente:

    [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)
    {
        // Probably want to ensure deletion even if the connection is broken
        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();
    }
    
  6. Nel file Proprietà/launchSettings.json modificare la launchUrl proprietà per ogni profilo da weatherforecast a api/notifications.

Creare un'app per le API

Si creerà ora un'app per le API in app Azure Servizio per ospitare il servizio back-end. Questa operazione può essere eseguita direttamente da Visual Studio o Visual Studio Code, con l'interfaccia della riga di comando di Azure, Azure PowerShell, l'interfaccia della riga di comando per sviluppatori di Azure e tramite il portale di Azure. Per altre informazioni, vedere Pubblicare l'app Web.

Per creare un'app per le API nel portale di Azure:

  1. In un Web browser accedere al portale di Azure.

  2. Nella portale di Azure fare clic sul pulsante Crea una risorsa e quindi cercare e scegliere App per le API prima di selezionare il pulsante Crea.

  3. Nella pagina Crea app per le API aggiornare i campi seguenti prima di selezionare il pulsante Crea :

    Campo Azione
    Abbonamento Scegliere la stessa sottoscrizione di destinazione in cui è stato creato l'hub di notifica.
    Gruppo di risorse Scegliere lo stesso gruppo di risorse in cui è stato creato l'hub di notifica.
    Nome Immettere un nome globalmente univoco.
    Stack di runtime Assicurarsi che sia selezionata la versione più recente di .NET.
  4. Dopo aver effettuato il provisioning dell'app per le API, passare alla risorsa.

  5. Nella pagina Panoramica prendere nota del valore di dominio predefinito. Questo URL è l'endpoint back-end che verrà usato dall'app .NET MAUI. L'URL userà il nome dell'app per le API specificato, con il formato https://<app_name>.azurewebsites.net.

  6. Nel portale di Azure passare al pannello Impostazioni Variabili > di ambiente e quindi assicurarsi che sia selezionata la scheda Impostazioni app. Usare quindi il pulsante Aggiungi per aggiungere le impostazioni seguenti:

    Nome Valore
    Authentication:ApiKey <api_key_value>
    NotificationHub:Name <hub_name_value>
    NotificationHub:ConnectionString <hub_connection_string_value>

    Importante

    L'impostazione Authentication:ApiKey dell'applicazione è stata aggiunta per semplicità. Per gli scenari di produzione, prendere in considerazione un servizio come Azure KeyVault per archiviare in modo sicuro il stringa di connessione.

    Dopo aver immesso tutte queste impostazioni, selezionare il pulsante Applica e quindi il pulsante Conferma .

Pubblicare il servizio back-end

Per pubblicare il servizio back-end nel servizio app Azure:

  1. In Visual Studio fare clic con il pulsante destro del mouse sul progetto e scegliere Pubblica.
  2. Nella procedura guidata Pubblica selezionare Azure e quindi il pulsante Avanti.
  3. Nella procedura guidata Pubblica selezionare app Azure Servizio (Windows) e quindi il pulsante Avanti.
  4. Nella pubblicazione guidata seguire il flusso di autenticazione per connettere Visual Studio alla sottoscrizione di Azure e pubblicare l'app.

Visual Studio compila, crea pacchetti e pubblica l'app in Azure e quindi avvia l'app nel browser predefinito. Per altre informazioni, vedere Pubblicare un'app Web ASP.NET.

Suggerimento

È possibile scaricare un profilo di pubblicazione per l'app dal pannello Panoramica dell'app per le API nel portale di Azure e quindi usare il profilo in Visual Studio per pubblicare l'app.

Convalidare l'API pubblicata

Per verificare che l'app per le API sia stata pubblicata correttamente, è necessario usare gli strumenti REST di propria scelta per inviare una POST richiesta all'indirizzo seguente:

https://<app_name>.azurewebsites.net/api/notifications/requests

Nota

L'indirizzo di base è https://<app_name>.azurewebsites.net.

Assicurarsi di configurare le intestazioni della richiesta per includere la chiave apikey e il relativo valore, impostare il corpo su raw e usare il contenuto JSON segnaposto seguente:

{}

Si dovrebbe ricevere una 400 Bad Request risposta dal servizio.

Nota

Non è ancora possibile testare l'API usando dati di richiesta validi, perché saranno necessarie informazioni specifiche della piattaforma dall'app MAUI .NET.

Per altre informazioni sulla chiamata di API REST, vedere Usare file .http in Visual Studio e Testare le API Web con Http Repl. In Visual Studio Code è possibile usare il client REST per testare le API REST.

Creare un'app .NET MAUI

In questa sezione si creerà un'app .NET multipiattaforma dell'interfaccia utente dell'app (.NET MAUI) che consente di eseguire la registrazione per ricevere notifiche push da un hub di notifica tramite il servizio back-end e annullare la registrazione.

Per creare l'app .NET MAUI:

  1. In Visual Studio creare una nuova app MAUI .NET denominata PushNotificationsDemo usando il modello di progetto .NET MAUI App .

  2. In Visual Studio aggiungere una nuova cartella denominata Models al progetto MAUI .NET e quindi aggiungere una nuova classe denominata DeviceInstallation alla cartella Models e sostituirla con il codice seguente:

    using System.Text.Json.Serialization;
    
    namespace PushNotificationsDemo.Models;
    
    public class DeviceInstallation
    {
        [JsonPropertyName("installationId")]
        public string InstallationId { get; set; }
    
        [JsonPropertyName("platform")]
        public string Platform { get; set; }
    
        [JsonPropertyName("pushChannel")]
        public string PushChannel { get; set; }
    
        [JsonPropertyName("tags")]
        public List<string> Tags { get; set; } = new List<string>();
    }
    
  3. In Visual Studio aggiungere un'enumerazione denominata PushDemoAction alla cartella Models e sostituirla con il codice seguente:

    namespace PushNotificationsDemo.Models;
    
    public enum PushDemoAction
    {
        ActionA,
        ActionB
    }
    
  4. In Visual Studio aggiungere una nuova cartella denominata Services al progetto MAUI .NET e quindi aggiungere una nuova interfaccia denominata IDeviceInstallationService alla cartella Services e sostituirla con il codice seguente:

    using PushNotificationsDemo.Models;
    
    namespace PushNotificationsDemo.Services;
    
    public interface IDeviceInstallationService
    {
        string Token { get; set; }
        bool NotificationsSupported { get; }
        string GetDeviceId();
        DeviceInstallation GetDeviceInstallation(params string[] tags);
    }
    

    Questa interfaccia verrà implementata in ogni piattaforma in un secondo momento per fornire le DeviceInstallation informazioni richieste dal servizio back-end.

  5. In Visual Studio aggiungere un'interfaccia denominata INotificationRegistrationService alla cartella Services e sostituirla con il codice seguente:

    namespace PushNotificationsDemo.Services;
    
    public interface INotificationRegistrationService
    {
        Task DeregisterDeviceAsync();
        Task RegisterDeviceAsync(params string[] tags);
        Task RefreshRegistrationAsync();
    }
    

    Questa interfaccia gestirà l'interazione tra il client e il servizio back-end.

  6. In Visual Studio aggiungere un'interfaccia denominata INotificationActionService alla cartella Services e sostituirla con il codice seguente:

    namespace PushNotificationsDemo.Services;
    
    public interface INotificationActionService
    {
        void TriggerAction(string action);
    }
    

    Questa interfaccia verrà usata come meccanismo semplice per centralizzare la gestione delle azioni di notifica.

  7. In Visual Studio aggiungere un'interfaccia denominata IPushDemoNotificationActionService alla cartella Services e sostituirla con il codice seguente:

    using PushNotificationsDemo.Models;
    
    namespace PushNotificationsDemo.Services;
    
    public interface IPushDemoNotificationActionService : INotificationActionService
    {
        event EventHandler<PushDemoAction> ActionTriggered;
    }
    

    Il IPushDemoNotificationActionService tipo è specifico di questa app e usa l'enumerazione PushDemoAction per identificare l'azione attivata usando un approccio fortemente tipizzato.

  8. In Visual Studio aggiungere una classe denominata NotificationRegistrationService alla cartella Services e sostituirla con il codice seguente:

    using System.Text;
    using System.Text.Json;
    using PushNotificationsDemo.Models;
    
    namespace PushNotificationsDemo.Services;
    
    public class NotificationRegistrationService : INotificationRegistrationService
    {
        const string RequestUrl = "api/notifications/installations";
        const string CachedDeviceTokenKey = "cached_device_token";
        const string CachedTagsKey = "cached_tags";
    
        string _baseApiUrl;
        HttpClient _client;
        IDeviceInstallationService _deviceInstallationService;
    
        IDeviceInstallationService DeviceInstallationService =>
            _deviceInstallationService ?? (_deviceInstallationService = Application.Current.Windows[0].Page.Handler.MauiContext.Services.GetService<IDeviceInstallationService>());
    
        public NotificationRegistrationService(string baseApiUri, string apiKey)
        {
            _client = new HttpClient();
            _client.DefaultRequestHeaders.Add("Accept", "application/json");
            _client.DefaultRequestHeaders.Add("apikey", apiKey);
    
            _baseApiUrl = baseApiUri;
        }
    
        public async Task DeregisterDeviceAsync()
        {
            var cachedToken = await SecureStorage.GetAsync(CachedDeviceTokenKey)
                .ConfigureAwait(false);
    
            if (cachedToken == null)
                return;
    
            var deviceId = DeviceInstallationService?.GetDeviceId();
    
            if (string.IsNullOrWhiteSpace(deviceId))
                throw new Exception("Unable to resolve an ID for the device.");
    
            await SendAsync(HttpMethod.Delete, $"{RequestUrl}/{deviceId}")
                .ConfigureAwait(false);
    
            SecureStorage.Remove(CachedDeviceTokenKey);
            SecureStorage.Remove(CachedTagsKey);
        }
    
        public async Task RegisterDeviceAsync(params string[] tags)
        {
            var deviceInstallation = DeviceInstallationService?.GetDeviceInstallation(tags);
    
            await SendAsync<DeviceInstallation>(HttpMethod.Put, RequestUrl, deviceInstallation)
                .ConfigureAwait(false);
    
            await SecureStorage.SetAsync(CachedDeviceTokenKey, deviceInstallation.PushChannel)
                .ConfigureAwait(false);
    
            await SecureStorage.SetAsync(CachedTagsKey, JsonSerializer.Serialize(tags));
        }
    
        public async Task RefreshRegistrationAsync()
        {
            var cachedToken = await SecureStorage.GetAsync(CachedDeviceTokenKey)
                .ConfigureAwait(false);
    
            var serializedTags = await SecureStorage.GetAsync(CachedTagsKey)
                .ConfigureAwait(false);
    
            if (string.IsNullOrWhiteSpace(cachedToken) ||
                string.IsNullOrWhiteSpace(serializedTags) ||
                string.IsNullOrWhiteSpace(_deviceInstallationService.Token) ||
                cachedToken == DeviceInstallationService.Token)
                return;
    
            var tags = JsonSerializer.Deserialize<string[]>(serializedTags);
    
            await RegisterDeviceAsync(tags);
        }
    
        async Task SendAsync<T>(HttpMethod requestType, string requestUri, T obj)
        {
            string serializedContent = null;
    
            await Task.Run(() => serializedContent = JsonSerializer.Serialize(obj))
                .ConfigureAwait(false);
    
            await SendAsync(requestType, requestUri, serializedContent);
        }
    
        async Task SendAsync(HttpMethod requestType, string requestUri, string jsonRequest = null)
        {
            var request = new HttpRequestMessage(requestType, new Uri($"{_baseApiUrl}{requestUri}"));
    
            if (jsonRequest != null)
                request.Content = new StringContent(jsonRequest, Encoding.UTF8, "application/json");
    
            var response = await _client.SendAsync(request).ConfigureAwait(false);
    
            response.EnsureSuccessStatusCode();
        }
    }
    
  9. In Visual Studio aggiungere una classe denominata PushDemoNotificationActionService alla cartella Services e sostituirla con il codice seguente:

    using PushNotificationsDemo.Models;
    
    namespace PushNotificationsDemo.Services;
    
    public class PushDemoNotificationActionService : IPushDemoNotificationActionService
    {
        readonly Dictionary<string, PushDemoAction> _actionMappings = new Dictionary<string, PushDemoAction>
        {
            { "action_a", PushDemoAction.ActionA },
            { "action_b", PushDemoAction.ActionB }
        };
    
        public event EventHandler<PushDemoAction> ActionTriggered = delegate { };
    
        public void TriggerAction(string action)
        {
            if (!_actionMappings.TryGetValue(action, out var pushDemoAction))
                return;
    
            List<Exception> exceptions = new List<Exception>();
    
            foreach (var handler in ActionTriggered?.GetInvocationList())
            {
                try
                {
                    handler.DynamicInvoke(this, pushDemoAction);
                }
                catch (Exception ex)
                {
                    exceptions.Add(ex);
                }
            }
    
            if (exceptions.Any())
                throw new AggregateException(exceptions);
        }
    }
    
  10. In Visual Studio aggiungere una classe denominata Config alla radice del progetto e sostituirla con il codice seguente:

    namespace PushNotificationsDemo;
    
    public static partial class Config
    {
        public static string ApiKey = "API_KEY";
        public static string BackendServiceEndpoint = "BACKEND_SERVICE_ENDPOINT";
    }
    

    La Config classe viene usata come modo semplice per mantenere i segreti fuori dal controllo del codice sorgente. È possibile sostituire questi valori come parte di una compilazione automatizzata o eseguirne l'override usando una classe parziale locale.

    Importante

    Quando si specifica l'indirizzo di base nell'app MAUI .NET, assicurarsi che termini con ./

  11. In Visual Studio aggiungere una classe denominata Config.local_secrets alla radice del progetto. Sostituire quindi il codice nel file Config.local_secrets.cs con il codice seguente:

    namespace PushNotificationsDemo;
    
    public static partial class Config
    {
        static Config()
        {
            ApiKey = "<your_api_key>";
            BackendServiceEndpoint = "<your_api_app_url>";
        }
    }
    

    Sostituire i valori segnaposto con i valori scelti durante la creazione del servizio back-end. L'URL BackendServiceEndpoint deve usare il formato https://<api_app_name>.azurewebsites.net/.

    Suggerimento

    Ricordarsi di aggiungere *.local_secrets.* al .gitignore file per evitare di eseguire il commit di questo file nel controllo del codice sorgente.

Creare l'interfaccia utente

Per creare l'interfaccia utente dell'app:

  1. In Visual Studio aprire MainPage.xaml e sostituire VerticalStackLayout e i relativi elementi figlio con il codice XAML seguente:

    <VerticalStackLayout Margin="20"
                         Spacing="6">
        <Button x:Name="registerButton"
                Text="Register"
                Clicked="OnRegisterButtonClicked" />
        <Button x:Name="deregisterButton"
                Text="Deregister"
                Clicked="OnDeregisterButtonClicked" />
    </VerticalStackLayout>
    
  2. In Visual Studio aprire MainPage.xaml.cs e aggiungere un'istruzione using per lo spazio dei PushNotificationsDemo.Services nomi :

    using PushNotificationsDemo.Services;
    
  3. In MainPage.xaml.cs aggiungere un readonly campo sottostante per archiviare un riferimento all'implementazioneINotificationRegistrationService:

    readonly INotificationRegistrationService _notificationRegistrationService;
    
  4. MainPage Nel costruttore risolvere l'implementazione INotificationRegistrationService e assegnarla al _notificationRegistrationService campo sottostante:

    public MainPage(INotificationRegistrationService service)
    {
        InitializeComponent();
    
        _notificationRegistrationService = service;
    }
    
  5. MainPage Nella classe implementare i OnRegisterButtonClicked gestori eventi eOnDeregisterButtonClicked, chiamando i metodi register e deregister corrispondenti nell'oggetto INotificationRegistrationService :

    void OnRegisterButtonClicked(object sender, EventArgs e)
    {
        _notificationRegistrationService.RegisterDeviceAsync()
            .ContinueWith((task) =>
            {
                ShowAlert(task.IsFaulted ? task.Exception.Message : $"Device registered");
            });
    }
    
    void OnDeregisterButtonClicked(object sender, EventArgs e)
    {
        _notificationRegistrationService.DeregisterDeviceAsync()
            .ContinueWith((task) =>
            {
                ShowAlert(task.IsFaulted ? task.Exception.Message : $"Device deregistered");
            });
    }
    
    void ShowAlert(string message)
    {
        MainThread.BeginInvokeOnMainThread(() =>
        {
            DisplayAlert("Push notifications demo", message, "OK")
                .ContinueWith((task) =>
                {
                    if (task.IsFaulted)
                        throw task.Exception;
                });
        });
    }
    

    Importante

    Nell'app, la registrazione e la de-registrazione vengono eseguite in risposta all'input dell'utente, per consentire l'esplorazione e il test di questa funzionalità più facilmente. In un'app di produzione si eseguiranno in genere le azioni di registrazione e de-registrazione durante il punto appropriato nel ciclo di vita dell'app, senza richiedere l'input esplicito dell'utente.

  6. In Visual Studio aprire App.xaml.cs e aggiungere le istruzioni seguenti using :

    using PushNotificationsDemo.Models;
    using PushNotificationsDemo.Services;
    
  7. In App.xaml.cs aggiungere un readonly campo sottostante per archiviare un riferimento all'implementazioneIPushDemoNotificationActionService:

    readonly IPushDemoNotificationActionService _actionService;
    
  1. App Nel costruttore risolvere l'implementazione IPushDemoNotificationActionService e assegnarla al _actionService campo sottostante e sottoscrivere l'eventoIPushDemoNotificationActionService.ActionTriggered:

    public App(IPushDemoNotificationActionService service)
    {
        InitializeComponent();
    
        _actionService = service;
        _actionService.ActionTriggered += NotificationActionTriggered;
    
        MainPage = new AppShell();
    }
    
  1. App Nel costruttore risolvere l'implementazione IPushDemoNotificationActionService e assegnarla al _actionService campo sottostante e sottoscrivere l'eventoIPushDemoNotificationActionService.ActionTriggered:

    public App(IPushDemoNotificationActionService service)
    {
        InitializeComponent();
    
        _actionService = service;
        _actionService.ActionTriggered += NotificationActionTriggered;
    }
    
  1. App Nella classe implementare il gestore eventi per l'eventoIPushDemoNotificationActionService.ActionTriggered:

    void NotificationActionTriggered(object sender, PushDemoAction e)
    {
        ShowActionAlert(e);
    }
    
    void ShowActionAlert(PushDemoAction action)
    {
        MainThread.BeginInvokeOnMainThread(() =>
        {
            Windows[0].Page?.DisplayAlert("Push notifications demo", $"{action} action received.", "OK")
                .ContinueWith((task) =>
                {
                    if (task.IsFaulted)
                        throw task.Exception;
                });
        });
    }
    

    Il gestore eventi per l'evento ActionTriggered illustra la ricezione e la propagazione delle azioni di notifica push. Questi vengono in genere gestiti automaticamente, ad esempio passando a una visualizzazione specifica o aggiornando alcuni dati anziché visualizzare un avviso.

Configurare l'app Android

Per configurare l'app MAUI .NET in Android per ricevere ed elaborare le notifiche push:

  1. In Visual Studio aggiungere il pacchetto NuGet Xamarin.Firebase.Messaging al progetto di app .NET MAUI.

  2. In Visual Studio aggiungere il file google-services.json alla cartella Platforms/Android del progetto di app .NET MAUI. Dopo aver aggiunto il file al progetto, dovrebbe essere stato aggiunto con un'azione di compilazione di GoogleServicesJson:

    <ItemGroup Condition="'$(TargetFramework)' == 'net8.0-android'">
      <GoogleServicesJson Include="Platforms\Android\google-services.json" />
    </ItemGroup>
    

    Suggerimento

    Ricordarsi di aggiungere google-services.json al .gitignore file per evitare di eseguire il commit di questo file nel controllo del codice sorgente.

  3. In Visual Studio modificare il file di progetto (*.csproj) e impostare per Android su SupportedOSPlatformVersion 26.0:

    <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">26.0</SupportedOSPlatformVersion>
    

    Google ha apportato modifiche ai canali di notifica Android nell'API 26. Per altre informazioni, vedere Canali di notifica su developer.android.com.

  4. Nella cartella Platforms/Android del progetto aggiungere una nuova classe denominata DeviceInstallationService e sostituirla con il codice seguente:

    using Android.Gms.Common;
    using PushNotificationsDemo.Models;
    using PushNotificationsDemo.Services;
    using static Android.Provider.Settings;
    
    namespace PushNotificationsDemo.Platforms.Android;
    
    public class DeviceInstallationService : IDeviceInstallationService
    {
        public string Token { get; set; }
    
        public bool NotificationsSupported
            => GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(Platform.AppContext) == ConnectionResult.Success;
    
        public string GetDeviceId()
            => Secure.GetString(Platform.AppContext.ContentResolver, Secure.AndroidId);
    
        public DeviceInstallation GetDeviceInstallation(params string[] tags)
        {
            if (!NotificationsSupported)
                throw new Exception(GetPlayServicesError());
    
            if (string.IsNullOrWhiteSpace(Token))
                throw new Exception("Unable to resolve token for FCMv1.");
    
            var installation = new DeviceInstallation
            {
                InstallationId = GetDeviceId(),
                Platform = "fcmv1",
                PushChannel = Token
            };
    
            installation.Tags.AddRange(tags);
    
            return installation;
        }
    
        string GetPlayServicesError()
        {
            int resultCode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(Platform.AppContext);
    
            if (resultCode != ConnectionResult.Success)
                return GoogleApiAvailability.Instance.IsUserResolvableError(resultCode) ?
                           GoogleApiAvailability.Instance.GetErrorString(resultCode) :
                           "This device isn't supported.";
    
            return "An error occurred preventing the use of push notifications.";
        }
    }
    

    Questa classe fornisce un ID univoco, usando il Secure.AndroidId valore e il payload di registrazione dell'hub di notifica.

  5. Nella cartella Platforms/Android del progetto aggiungere una nuova classe denominata PushNotificationFirebaseMessagingService e sostituirla con il codice seguente:

    using Android.App;
    using Firebase.Messaging;
    using PushNotificationsDemo.Services;
    
    namespace PushNotificationsDemo.Platforms.Android;
    
    [Service(Exported = false)]
    [IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
    public class PushNotificationFirebaseMessagingService : FirebaseMessagingService
    {
        IPushDemoNotificationActionService _notificationActionService;
        INotificationRegistrationService _notificationRegistrationService;
        IDeviceInstallationService _deviceInstallationService;
        int _messageId;
    
        IPushDemoNotificationActionService NotificationActionService =>
            _notificationActionService ?? (_notificationActionService = IPlatformApplication.Current.Services.GetService<IPushDemoNotificationActionService>());
    
        INotificationRegistrationService NotificationRegistrationService =>
            _notificationRegistrationService ?? (_notificationRegistrationService = IPlatformApplication.Current.Services.GetService<INotificationRegistrationService>());
    
        IDeviceInstallationService DeviceInstallationService =>
            _deviceInstallationService ?? (_deviceInstallationService = IPlatformApplication.Current.Services.GetService<IDeviceInstallationService>());
    
        public override void OnNewToken(string token)
        {
            DeviceInstallationService.Token = token;
    
            NotificationRegistrationService.RefreshRegistrationAsync()
                .ContinueWith((task) =>
                {
                    if (task.IsFaulted)
                        throw task.Exception;
                });
        }
    
        public override void OnMessageReceived(RemoteMessage message)
        {
            base.OnMessageReceived(message);
    
            if (message.Data.TryGetValue("action", out var messageAction))
                NotificationActionService.TriggerAction(messageAction);
        }
    }
    

    Questa classe ha un IntentFilter attributo che include il com.google.firebase.MESSAGING_EVENT filtro. Questo filtro consente ad Android di passare messaggi in ingresso a questa classe per l'elaborazione.

    Per informazioni sul formato dei messaggi di Firebase Cloud Messaging, vedere Informazioni sui messaggi FCM in developer.android.com.

  6. In Visual Studio aprire il file MainActivity.cs nella cartella Platforms/Android e aggiungere le istruzioni seguenti using :

    using Android.App;
    using Android.Content;
    using Android.Content.PM;
    using Android.OS;
    using PushNotificationsDemo.Services;
    using Firebase.Messaging;
    
  7. MainActivity Nella classe impostare su LaunchMode SingleTop in modo che l'oggetto non venga nuovamente creato all'aperturaMainActivity:

    [Activity(
        Theme = "@style/Maui.SplashTheme",
        MainLauncher = true,
        LaunchMode = LaunchMode.SingleTop,
        ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
    
  8. MainActivity Nella classe aggiungere campi di backup per archiviare i riferimenti alle IPushDemoNotificationActionService implementazioni e IDeviceInstallationService :

    IPushDemoNotificationActionService _notificationActionService;
    IDeviceInstallationService _deviceInstallationService;
    
  9. MainActivity Nella classe aggiungere NotificationActionService e DeviceInstallationService private proprietà che recuperano le implementazioni concrete dal contenitore di inserimento delle dipendenze dell'app:

    IPushDemoNotificationActionService NotificationActionService =>
        _notificationActionService ?? (_notificationActionService = IPlatformApplication.Current.Services.GetService<IPushDemoNotificationActionService>());
    
    IDeviceInstallationService DeviceInstallationService =>
        _deviceInstallationService ?? (_deviceInstallationService = IPlatformApplication.Current.Services.GetService<IDeviceInstallationService>());
    
  10. MainActivity Nella classe implementare l'interfaccia Android.Gms.Tasks.IOnSuccessListener per recuperare e archiviare il token Firebase:

    public class MainActivity : MauiAppCompatActivity, Android.Gms.Tasks.IOnSuccessListener
    {
        public void OnSuccess(Java.Lang.Object result)
        {
            DeviceInstallationService.Token = result.ToString();
        }
    }
    
  11. MainActivity Nella classe aggiungere il ProcessNotificationActions metodo che verificherà se un dato Intent ha un valore aggiuntivo denominato actione quindi attivare in modo condizionale che action usa l'implementazioneIPushDemoNotificationActionService:

    void ProcessNotificationsAction(Intent intent)
    {
        try
        {
            if (intent?.HasExtra("action") == true)
            {
                var action = intent.GetStringExtra("action");
    
                if (!string.IsNullOrEmpty(action))
                    NotificationActionService.TriggerAction(action);
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message);
        }
    }
    
  12. Nella classe eseguire l'override MainActivity del OnNewIntent metodo per chiamare il ProcessNotificationActions metodo :

    protected override void OnNewIntent(Intent? intent)
    {
        base.OnNewIntent(intent);
        ProcessNotificationsAction(intent);
    }
    

    Poiché per LaunchMode Activity è impostato su SingleTop, Intent un oggetto verrà inviato all'istanza esistente Activity tramite l'override OnNewIntent , anziché il OnCreate metodo . Pertanto, è necessario gestire una finalità in ingresso sia in che OnCreatein OnNewIntent .

  13. Nella classe eseguire l'override MainActivity del OnCreate metodo per chiamare il ProcessNotificationActions metodo e per recuperare il token da Firebase, aggiungendo MainActivity come IOnSuccessListener:

    protected override void OnCreate(Bundle? savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
    
        if (DeviceInstallationService.NotificationsSupported)
            FirebaseMessaging.Instance.GetToken().AddOnSuccessListener(this);
    
        ProcessNotificationsAction(Intent);
    }
    

    Nota

    L'app deve essere nuovamente registrata ogni volta che viene eseguita e arrestarla da una sessione di debug per continuare a ricevere notifiche push.

  14. In Visual Studio aggiungere l'autorizzazione POST_NOTIFICATIONS al file AndroidManifest.xml nella cartella Platforms/Android :

    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    

    Per altre informazioni su questa autorizzazione, vedere Autorizzazione runtime di notifica per developer.android.com.

  15. In Visual Studio aprire MainPage.xaml.cs e aggiungere il codice seguente alla MainPage classe :

    #if ANDROID
            protected override async void OnAppearing()
            {
                base.OnAppearing();
    
                PermissionStatus status = await Permissions.RequestAsync<Permissions.PostNotifications>();
            }
    #endif
    

    Questo codice viene eseguito in Android quando MainPage viene visualizzato e richiede all'utente di concedere l'autorizzazione POST_NOTIFICATIONS . Per altre informazioni sulle autorizzazioni MAUI .NET, vedere Autorizzazioni.

Configurare l'app iOS

Il simulatore iOS supporta le notifiche remote in iOS 16+ durante l'esecuzione in macOS 13+ nei computer Mac con processori Apple silicon o T2. Ogni simulatore genera token di registrazione univoci per la combinazione del simulatore e dell'hardware Mac su cui è in esecuzione.

Importante

Il simulatore supporta l'ambiente sandbox apple Push Notification Service.

Le istruzioni seguenti presuppongono l'uso di hardware che supporta la ricezione di notifiche remote in un simulatore iOS. Se non si tratta del caso, è necessario eseguire l'app iOS in un dispositivo fisico, che richiederà di creare un profilo di provisioning per l'app che include la funzionalità Notifiche push. Sarà quindi necessario assicurarsi che l'app venga compilata usando il certificato e il profilo di provisioning. Per altre informazioni su come eseguire questa operazione, vedere Configurare l'app iOS per l'uso con Hub di notifica di Azure e quindi seguire le istruzioni riportate di seguito.

Per configurare l'app MAUI .NET in iOS per ricevere ed elaborare le notifiche push:

  1. In Visual Studio modificare il file di progetto (*.csproj) e impostare per iOS su SupportedOSPlatformVersion 13.0:

    <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">13.0</SupportedOSPlatformVersion>
    

    Apple ha apportato modifiche al servizio push in iOS 13. Per altre informazioni, vedere Aggiornamenti di Hub di notifica di Azure per iOS 13.

  2. In Visual Studio aggiungere un file Entitlements.plist alla cartella Platforms/iOS del progetto e aggiungere il codice XML seguente al file:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
      <key>aps-environment</key>
      <string>development</string>
    </dict>
    </plist>
    

    In questo modo viene impostato l'entitlement dell'ambiente APS e viene specificato l'uso dell'ambiente Apple Push Notification Service per lo sviluppo. Nelle app di produzione questo valore entitlement deve essere impostato su production. Per altre informazioni su questo diritto, vedere APS Environment Entitlement on developer.apple.com (Entitlement dell'ambiente APS in developer.apple.com).

    Per altre informazioni sull'aggiunta di un file entitlement, vedere Entitlement iOS.

  3. In Visual Studio aggiungere una nuova classe denominata DeviceInstallationService alla cartella Platforms/iOS del progetto e aggiungere il codice seguente al file:

    using PushNotificationsDemo.Services;
    using PushNotificationsDemo.Models;
    using UIKit;
    
    namespace PushNotificationsDemo.Platforms.iOS;
    
    public class DeviceInstallationService : IDeviceInstallationService
    {
        const int SupportedVersionMajor = 13;
        const int SupportedVersionMinor = 0;
    
        public string Token { get; set; }
    
        public bool NotificationsSupported =>
            UIDevice.CurrentDevice.CheckSystemVersion(SupportedVersionMajor, SupportedVersionMinor);
    
        public string GetDeviceId() =>
            UIDevice.CurrentDevice.IdentifierForVendor.ToString();
    
        public DeviceInstallation GetDeviceInstallation(params string[] tags)
        {
            if (!NotificationsSupported)
                throw new Exception(GetNotificationsSupportError());
    
            if (string.IsNullOrWhiteSpace(Token))
                throw new Exception("Unable to resolve token for APNS");
    
            var installation = new DeviceInstallation
            {
                InstallationId = GetDeviceId(),
                Platform = "apns",
                PushChannel = Token
            };
    
            installation.Tags.AddRange(tags);
    
            return installation;
        }
    
        string GetNotificationsSupportError()
        {
            if (!NotificationsSupported)
                return $"This app only supports notifications on iOS {SupportedVersionMajor}.{SupportedVersionMinor} and above. You are running {UIDevice.CurrentDevice.SystemVersion}.";
    
            if (Token == null)
                return $"This app can support notifications but you must enable this in your settings.";
    
            return "An error occurred preventing the use of push notifications";
        }
    }
    

    Questa classe fornisce un ID univoco, usando il UIDevice.IdentifierForVendor valore e il payload di registrazione dell'hub di notifica.

  4. In Visual Studio aggiungere una nuova classe denominata NSDataExtensions alla cartella Platforms/iOS del progetto e aggiungere il codice seguente al file:

    using Foundation;
    using System.Text;
    
    namespace PushNotificationsDemo.Platforms.iOS;
    
    internal static class NSDataExtensions
    {
        internal static string ToHexString(this NSData data)
        {
            var bytes = data.ToArray();
    
            if (bytes == null)
                return null;
    
            StringBuilder sb = new StringBuilder(bytes.Length * 2);
    
            foreach (byte b in bytes)
                sb.AppendFormat("{0:x2}", b);
    
            return sb.ToString().ToUpperInvariant();
        }
    }
    

    Il ToHexString metodo di estensione verrà utilizzato dal codice che verrà aggiunto che analizza il token del dispositivo recuperato.

  5. In Visual Studio aprire il file AppDelegate.cs nella cartella Platforms/iOS e aggiungere le istruzioni seguenti using :

    using System.Diagnostics;
    using Foundation;
    using PushNotificationsDemo.Platforms.iOS;
    using PushNotificationsDemo.Services;
    using UIKit;
    using UserNotifications;
    
  6. AppDelegate Nella classe aggiungere campi di backup per archiviare i riferimenti alle IPushDemoNotificationActionServiceimplementazioni , INotificationRegistrationServicee IDeviceInstallationService :

    IPushDemoNotificationActionService _notificationActionService;
    INotificationRegistrationService _notificationRegistrationService;
    IDeviceInstallationService _deviceInstallationService;
    
  7. AppDelegate Nella classe aggiungere NotificationActionServiceNotificationRegistrationService, e DeviceInstallationService proprietà private che recuperano le implementazioni concrete dal contenitore di inserimento delle dipendenze dell'app:

    IPushDemoNotificationActionService NotificationActionService =>
        _notificationActionService ?? (_notificationActionService = IPlatformApplication.Current.Services.GetService<IPushDemoNotificationActionService>());
    
    INotificationRegistrationService NotificationRegistrationService =>
        _notificationRegistrationService ?? (_notificationRegistrationService = IPlatformApplication.Current.Services.GetService<INotificationRegistrationService>());
    
    IDeviceInstallationService DeviceInstallationService =>
        _deviceInstallationService ?? (_deviceInstallationService = IPlatformApplication.Current.Services.GetService<IDeviceInstallationService>());
    
  8. AppDelegate Nella classe aggiungere il CompleteRegistrationAsync metodo per impostare il valore della IDeviceInstallationService.Token proprietà:

    Task CompleteRegistrationAsync(NSData deviceToken)
    {
        DeviceInstallationService.Token = deviceToken.ToHexString();
        return NotificationRegistrationService.RefreshRegistrationAsync();
    }
    

    Questo metodo aggiorna anche la registrazione e memorizza nella cache il token del dispositivo se è stato aggiornato dopo l'ultima archiviazione.

  9. AppDelegate Nella classe aggiungere il ProcessNotificationActions metodo per elaborare i dati di NSDictionary notifica e chiamare NotificationActionService.TriggerActionin modo condizionale :

    void ProcessNotificationActions(NSDictionary userInfo)
    {
        if (userInfo == null)
            return;
    
        try
        {
            // If your app isn't in the foreground, the notification goes to Notification Center.
            // If your app is in the foreground, the notification goes directly to your app and you
            // need to process the notification payload yourself.
            var actionValue = userInfo.ObjectForKey(new NSString("action")) as NSString;
    
            if (!string.IsNullOrWhiteSpace(actionValue?.Description))
                NotificationActionService.TriggerAction(actionValue.Description);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
    }
    
  10. AppDelegate Nella classe aggiungere il RegisteredForRemoteNotifications metodo passando l'argomento deviceToken al CompleteRegistrationAsync metodo :

    [Export("application:didRegisterForRemoteNotificationsWithDeviceToken:")]
    public void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
    {
        CompleteRegistrationAsync(deviceToken)
            .ContinueWith((task) =>
            {
                if (task.IsFaulted)
                    throw task.Exception;
            });
    }
    

    Questo metodo verrà chiamato quando l'app viene registrata per ricevere una notifica remota e viene usata per richiedere il token univoco del dispositivo, che è effettivamente l'indirizzo dell'app nel dispositivo.

  11. AppDelegate Nella classe aggiungere il ReceivedRemoteNotification metodo passando l'argomento userInfo al ProcessNotificationActions metodo :

    [Export("application:didReceiveRemoteNotification:")]
    public void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
    {
        ProcessNotificationActions(userInfo);
    }
    

    Questo metodo verrà chiamato quando l'app ha ricevuto una notifica remota e viene usata per elaborare la notifica.

  12. AppDelegate Nella classe aggiungere il FailedToRegisterForRemoteNotifications metodo per registrare eventuali errori:

    [Export("application:didFailToRegisterForRemoteNotificationsWithError:")]
    public void FailedToRegisterForRemoteNotifications(UIApplication application, NSError error)
    {
        Debug.WriteLine(error.Description);
    }
    

    Questo metodo verrà chiamato quando l'app non è riuscita a registrarsi per ricevere notifiche remote. La registrazione potrebbe non riuscire se il dispositivo non è connesso alla rete, se il server APNS non è raggiungibile o se l'app non è configurata correttamente.

    Nota

    Per gli scenari di produzione, è necessario implementare la registrazione e la gestione degli errori appropriati nel FailedToRegisterForRemoteNotifications metodo .

  13. AppDelegate Nella classe aggiungere il metodo per richiedere in modo condizionale l'autorizzazione FinishedLaunching per usare le notifiche e registrarsi per le notifiche remote:

    [Export("application:didFinishLaunchingWithOptions:")]
    public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
    {
        if (DeviceInstallationService.NotificationsSupported)
        {
            UNUserNotificationCenter.Current.RequestAuthorization(
                UNAuthorizationOptions.Alert |
                UNAuthorizationOptions.Badge |
                UNAuthorizationOptions.Sound,
                (approvalGranted, error) =>
                {
                    if (approvalGranted && error == null)
                    {
                        MainThread.BeginInvokeOnMainThread(() =>
                        {
                            UIApplication.SharedApplication.RegisterForRemoteNotifications();
                        });
                    }
                });
        }
    
        using (var userInfo = launchOptions?.ObjectForKey(UIApplication.LaunchOptionsRemoteNotificationKey) as NSDictionary)
        {
            ProcessNotificationActions(userInfo);
        }
    
        return base.FinishedLaunching(application, launchOptions);
    }
    

    Per informazioni sulla richiesta dell'autorizzazione per l'uso delle notifiche, vedere La richiesta di autorizzazioni per l'uso delle notifiche in developer.apple.com.

Per informazioni sulle notifiche in iOS, vedere Notifiche utente su developer.apple.com.

Registrare i tipi con il contenitore di inserimento delle dipendenze dell'app

  1. In Visual Studio aprire MauiProgram.cs e aggiungere un'istruzione using per lo spazio dei PushNotificationsDemo.Services nomi :

    using PushNotificationsDemo.Services;
    
  2. MauiProgram Nella classe aggiungere codice per il RegisterServices metodo di estensione che registra in DeviceInstallationService ogni piattaforma e i servizi e NotificationRegistrationService multipiattaforma PushDemoNotificationActionService e che restituisce un MauiAppBuilder oggetto :

    public static MauiAppBuilder RegisterServices(this MauiAppBuilder builder)
    {
    #if IOS
        builder.Services.AddSingleton<IDeviceInstallationService, PushNotificationsDemo.Platforms.iOS.DeviceInstallationService>();
    #elif ANDROID
        builder.Services.AddSingleton<IDeviceInstallationService, PushNotificationsDemo.Platforms.Android.DeviceInstallationService>();
    #endif
    
        builder.Services.AddSingleton<IPushDemoNotificationActionService, PushDemoNotificationActionService>();
        builder.Services.AddSingleton<INotificationRegistrationService>(new NotificationRegistrationService(Config.BackendServiceEndpoint, Config.ApiKey));
    
        return builder;
    }
    
  3. MauiProgram Nella classe aggiungere codice per il RegisterViews metodo di estensione che registra il MainPage tipo come singleton e che restituisce un MauiAppBuilder oggetto :

    public static MauiAppBuilder RegisterViews(this MauiAppBuilder builder)
    {
        builder.Services.AddSingleton<MainPage>();
        return builder;
    }
    

    Il MainPage tipo viene registrato perché richiede una INotificationRegistrationService dipendenza e tutti i tipi che richiedono una dipendenza devono essere registrati con il contenitore di inserimento delle dipendenze.

  4. MauiProgram Nella classe modificare il CreateMauiApp metodo in modo che chiami i RegisterServices metodi di estensione e RegisterViews :

    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
            })
            .RegisterServices()
            .RegisterViews();
    
    #if DEBUG
          builder.Logging.AddDebug();
    #endif
          return builder.Build();
    }
    

Per altre informazioni sull'inserimento delle dipendenze in .NET MAUI, vedere Inserimento delle dipendenze.

Testare l'app

È possibile testare l'app inviando notifiche push all'app usando il servizio back-end o tramite il portale di Azure.

Il simulatore iOS supporta le notifiche remote in iOS 16+ durante l'esecuzione in macOS 13+ nei computer Mac con processori Apple silicon o T2. Se non si soddisfano questi requisiti hardware, è necessario testare l'app iOS in un dispositivo fisico. In Android è possibile testare l'app in un dispositivo fisico sbloccato dallo sviluppatore o in un emulatore.

Android e iOS visualizzano le notifiche push per conto dell'app quando è in esecuzione in background. Se l'app è in esecuzione in primo piano quando viene ricevuta la notifica, il codice dell'app determina il comportamento. Ad esempio, è possibile aggiornare l'interfaccia dell'app in modo da riflettere le nuove informazioni contenute nella notifica.

Eseguire il test usando il servizio back-end

Per inviare una notifica push di test all'app tramite il servizio back-end pubblicato nel servizio app Azure:

  1. In Visual Studio eseguire l'app PushNotificationsDemo in Android o iOS e selezionare il pulsante Registra .

    Nota

    Se si esegue il test in Android, assicurarsi di non essere in esecuzione usando la configurazione di debug. In alternativa, se l'app è stata distribuita in precedenza, assicurarsi che sia stata chiusa forzata e quindi avviarla di nuovo dall'utilità di avvio.

  2. Negli strumenti REST di propria scelta inviare una POST richiesta all'indirizzo seguente:

    https://<app_name>.azurewebsites.net/api/notifications/requests
    

    Assicurarsi di configurare le intestazioni della richiesta per includere la chiave apikey e il relativo valore, impostare il corpo su raw e usare il contenuto JSON seguente:

    {
        "text": "Message from REST tooling!",
        "action": "action_a"
    }
    

    La richiesta complessiva dovrebbe essere simile all'esempio seguente:

    POST /api/notifications/requests HTTP/1.1
    Host: https://<app_name>.azurewebsites.net
    apikey: <your_api_key>
    Content-Type: application/json
    
    {
        "text": "Message from REST tooling!",
        "action": "action_a"
    }
    
  3. Negli strumenti REST di propria scelta verificare di ricevere una risposta 200 OK .

  4. Nell'app in Android o iOS dovrebbe essere visualizzato un avviso che mostra l'azione ActionA ricevuta.

Per altre informazioni sulla chiamata di API REST, vedere Usare file .http in Visual Studio e Testare le API Web con Http Repl. In Visual Studio Code è possibile usare il client REST per testare le API REST.

Eseguire il test usando il portale di Azure

Hub di notifica di Azure consente di verificare che l'app possa ricevere notifiche push.

Per inviare una notifica push di test all'app tramite il portale di Azure:

  1. In Visual Studio eseguire l'app PushNotificationsDemo in Android o iOS e selezionare il pulsante Registra .

    Nota

    Se si esegue il test in Android, assicurarsi di non essere in esecuzione usando la configurazione di debug. In alternativa, se l'app è stata distribuita in precedenza, assicurarsi che sia stata chiusa forzata e quindi avviarla di nuovo dall'utilità di avvio.

  2. Nella portale di Azure passare all'hub di notifica e selezionare il pulsante Invia test nel pannello Panoramica.

  3. Nel pannello Invio di test selezionare la piattaforma richiesta e modificare il payload.

    Per Apple, usare il payload seguente:

    {
      "aps": {
        "alert": "Message from Notification Hub!"
      },
      "action": "action_a"
    }
    

    Per Android, usare il payload seguente:

    {
      "message": {
        "notification": {
          "title": "PushDemo",
          "body": "Message from Notification Hub!"
        },
        "data": {
          "action": "action_a"
        }
      }
    }
    

    Il portale di Azure dovrebbe indicare che la notifica è stata inviata correttamente.

    Per informazioni sul formato dei messaggi di Firebase Cloud Messaging, vedere Informazioni sui messaggi FCM in developer.android.com.

  4. Nell'app in Android o iOS dovrebbe essere visualizzato un avviso che mostra l'azione ActionA ricevuta.

Risoluzione dei problemi

Le sezioni seguenti illustrano i problemi comuni riscontrati durante il tentativo di utilizzare le notifiche push in un'app client.

Nessuna risposta dal servizio back-end

Durante i test in locale assicurarsi che il servizio back-end sia in esecuzione e che usi la porta corretta.

Se si esegue il test sull'app per le API di Azure, verificare che il servizio sia in esecuzione e che sia stato distribuito e avviato senza errori.

Assicurarsi di aver specificato correttamente l'indirizzo di base negli strumenti REST o nella configurazione dell'app MAUI .NET. L'indirizzo di base deve essere https://<api_name>.azurewebsites.net o https://localhost:7020 quando si esegue il test in locale.

Ricezione di un codice di stato 401 dal servizio back-end

Verificare che l'intestazione della apikey richiesta sia impostata correttamente e che questo valore corrisponda a quello configurato per il servizio back-end.

Se questo errore viene visualizzato durante il test in locale, assicurarsi che il valore della chiave definito nell'app MAUI .NET corrisponda al Authentication:ApiKey valore dei segreti utente usato dal servizio back-end.

Se si esegue il test con un'app per le API di Azure, assicurarsi che il valore della chiave definito nell'app MAUI .NET corrisponda al Authentication:ApiKey valore dell'impostazione dell'app definito nella portale di Azure. Se questa impostazione dell'app è stata creata o modificata dopo aver distribuito il servizio back-end, è necessario riavviare il servizio per rendere effettivo il valore.

Ricezione di un codice di stato 404 dal servizio back-end

Verificare che l'endpoint e il metodo di richiesta HTTP siano corretti:

  • METTERE- https://<api_name>.azurewebsites.net/api/notifications/installations
  • CANCELLARE- https://<api_name>.azurewebsites.net/api/notifications/installations/<installation_id>
  • INSERISCI- https://<api_name>.azurewebsites.net/api/notifications/requests

Oppure durante i test in locale:

  • METTERE- https://localhost:7020/api/notifications/installations
  • CANCELLARE- https://localhost:7020/api/notifications/installations/<installation_id>
  • INSERISCI- https://localhost:7020/api/notifications/requests

Importante

Quando si specifica l'indirizzo di base nell'app MAUI .NET, assicurarsi che termini con ./ L'indirizzo di base deve essere https://<api_name>.azurewebsites.net o https://localhost:7020/ quando si esegue il test in locale.

Mancata ricezione delle notifiche in Android dopo l'avvio o l'arresto di una sessione di debug

Assicurarsi di eseguire la registrazione ogni volta che si avvia una sessione di debug. Il debugger genererà la generazione di un nuovo token Firebase e quindi l'installazione dell'hub di notifica deve essere aggiornata.

Non è possibile eseguire la registrazione e viene visualizzato un messaggio di errore dell'hub di notifica

Verificare che il dispositivo di test abbia connettività di rete. Determinare quindi il codice di stato della risposta HTTP impostando un punto di interruzione per esaminare la StatusCode proprietà in HttpResponse.

Esaminare i suggerimenti precedenti per la risoluzione dei problemi, se applicabile, in base al codice di stato.

Impostare un punto di interruzione nelle righe che restituiscono codici di stato specifici per l'API corrispondente. Provare quindi a chiamare il servizio back-end durante il debug in locale.

Verificare che il servizio back-end funzioni come previsto dagli strumenti REST scelti e usare il payload creato dall'app MAUI .NET per la piattaforma scelta.

Esaminare le sezioni di configurazione specifiche della piattaforma per assicurarsi di aver eseguito tutti i passaggi. Verificare che i valori appropriati vengano risolti per InstallationId le variabili e Token per la piattaforma scelta.

Impossibile risolvere un ID per il dispositivo nel messaggio di errore del dispositivo

Esaminare le sezioni di configurazione specifiche della piattaforma per assicurarsi di aver eseguito tutti i passaggi.