Partilhar via


Tutorial: Enviar notificações por push para aplicativos .NET MAUI usando os Hubs de Notificação do Azure por meio de um serviço de back-end

Explorar exemplo. Explorar o de exemplo

As notificações por push fornecem informações de um sistema de back-end para um aplicativo cliente. Apple, Google e outras plataformas têm seu próprio Serviço de Notificação por Push (PNS). Os Hubs de Notificação do Azure permitem centralizar notificações entre plataformas para que seu aplicativo de back-end possa se comunicar com um único hub, que se encarrega de distribuir notificações para cada PNS.

Os Hubs de Notificação do Azure exigem que os aplicativos se registrem no hub e, opcionalmente, definam modelos e/ou assinem tags:

  • Executar a configuração de um dispositivo vincula um identificador do serviço de notificações push (PNS) a um identificador no Hub de Notificação do Azure. Para obter mais informações sobre registros, consulte Gerenciamento de registros.
  • Os modelos permitem que os dispositivos especifiquem modelos de mensagens parametrizadas. As mensagens recebidas podem ser personalizadas por dispositivo. Para obter mais informações, consulte Modelos de hubs de notificação.
  • As tags podem ser usadas para se inscrever em categorias de mensagens, como notícias, esportes e meteorologia. Para obter mais informações, consulte Roteamento e expressões de tag.

Neste tutorial, você usará Hubs de Notificação do Azure para enviar notificações por push para um aplicativo .NET Multi-platform App UI (.NET MAUI) direcionado para Android e iOS. Um back-end da API Web ASP.NET Core é usado para lidar com o registro de dispositivo para o cliente e para iniciar uma notificação por push. Essas operações são tratadas usando o pacote Microsoft.Azure.NotificationHubs NuGet. Para obter mais informações sobre a abordagem geral, consulte Gestão de registos do servidor back-end.

Neste tutorial, você:

  • Configure os serviços de notificação por push e o Hub de Notificação do Azure.
  • Crie um aplicativo de back-end ASP.NET Core WebAPI.
  • Crie um aplicativo .NET MAUI.
  • Configure o aplicativo Android para notificações por push.
  • Configure o aplicativo iOS para notificações por push.
  • Teste o aplicativo.
  • Solucione quaisquer problemas de instalação e configuração.

Pré-requisitos

Para concluir este tutorial, você precisará:

  • Uma conta Azure com uma subscrição ativa.
  • Um PC ou Mac executando a versão mais recente do Visual Studio/Visual Studio Code com a carga de trabalho de desenvolvimento da interface do usuário do aplicativo multiplataforma .NET e as cargas de trabalho de desenvolvimento ASP.NET e da Web instaladas.

Para Android, você deve ter:

  • Um dispositivo físico desbloqueado pelo desenvolvedor, ou um emulador, executando a API 26+ com o Google Play Services instalado.

Para iOS, você deve ter:

  • Uma conta de programador Apple ativa.
  • Um Mac com Xcode, juntamente com um certificado de programador válido instalado no seu Porta-chaves.

Em seguida, no iOS deverás ter:

  • Um simulador iOS 16+ que roda no macOS 13+ em computadores Mac com processadores de silício ou T2 da Apple.

    OU

  • Um dispositivo iOS físico registado na sua conta de programador (com iOS 13.0+).

  • O seu dispositivo físico registado na sua conta de programador Apple e associado ao seu certificado.

Importante

O simulador iOS suporta notificações remotas no iOS 16+ quando executado no macOS 13+ em computadores Mac com processadores de silício ou T2 da Apple. Se não cumprir estes requisitos de hardware, necessitará de uma conta de programador Apple ativa e de um dispositivo físico.

Para seguir este tutorial, você deve estar familiarizado com:

Embora este tutorial tenha como alvo o Visual Studio, é possível segui-lo usando o Visual Studio Code em um PC ou Mac. No entanto, haverá algumas diferenças que precisam de ser conciliadas. Por exemplo, descrições da interface do usuário e fluxos de trabalho, nomes de modelo e configuração de ambiente.

Configurar serviços de notificação por push e o Hub de Notificação do Azure

Nesta seção, você configurará Firebase Cloud Messaging e Apple Push Notification Services (APNS). Em seguida, você criará e configurará um do Hub de Notificação do Azure para trabalhar com esses serviços.

Criar um projeto do Firebase

Para criar um projeto do Firebase:

  1. Num navegador web, inicie sessão no console do Firebase.

  2. No console do Firebase, selecione o botão Adicionar projeto e crie um novo projeto do Firebase, inserindo PushDemo como o nome do projeto .

    Observação

    Um nome exclusivo será gerado para você. Por padrão, isso inclui uma variante minúscula do nome que você forneceu mais um número gerado separado por um traço. Você pode alterar isso se desejar, desde que suas edições ainda sejam globalmente exclusivas.

  3. Depois que seu projeto for criado, selecione o logotipo do Android para adicionar o Firebase a um aplicativo Android:

    Captura de tela da adição do Firebase a um aplicativo Android no console do Firebase Cloud Messaging.

  4. Na página Adicionar Firebase à sua aplicação Android, introduza um nome para o seu pacote, opcionalmente uma alcunha de aplicação, e selecione o botão Registar aplicação:

    Captura de tela do registro de seu aplicativo Android com o Firebase.

  5. Na página Adicionar Firebase ao seu aplicativo Android, selecione o botão Download google-services.json e salve o arquivo em uma pasta local antes de selecionar o botão Avançar:

    Captura de tela do download do arquivo JSON de serviços do Google.

  6. Na página Adicionar Firebase ao seu aplicativo Android, selecione o botão Avançar.

  7. Na página Adicionar o Firebase à sua aplicação Android, selecione o botão Continuar para o console.

  8. No console do Firebase, selecione o ícone Visão geral do projeto e, em seguida, selecione Configurações do projeto:

    Captura de tela mostrando a seleção das configurações do projeto no console do Firebase Cloud Messaging.

  9. Nas Configurações do projeto, selecione a aba Cloud Messaging. Vai ver que a API do Firebase Cloud Messaging (V1) está ativada:

    Captura de tela confirmando que o Firebase Cloud Messaging V1 está ativado.

  10. Nas Configurações do projeto , selecione a guia Contas de serviço e, em seguida, selecione o botão Gerar nova chave privada .

  11. Na caixa de diálogo Gerar nova chave privada, selecione o botão Gerar chave:

    Captura de tela da geração de uma nova chave privada no console do Firebase Cloud Messaging.

    Será baixado um arquivo JSON, que conterá os valores que você inserirá no Hub de Notificação do Azure.

Registre seu aplicativo iOS para notificações por push

Para enviar notificações push para uma aplicação iOS, terá de registar a sua aplicação na Apple e registar-se para receber notificações push. Isso pode ser feito executando as etapas na seguinte documentação do Hub de Notificação do Azure:

Se quiser receber notificações por push em um dispositivo físico, você também precisará criar um perfil de provisionamento.

Importante

Para receber notificações em segundo plano no iOS, você deve adicionar o modo de plano de fundo de notificações remotas ao seu aplicativo. Para obter mais informações, consulte Habilitar o recurso de notificações remotas no developer.apple.com.

Criar um Hub de Notificação do Azure

Para criar um hub de notificação no portal do Azure:

  1. Em um navegador Web, inicie sessão no portal do Azure.
  2. No portal do Azure, clique no botão Criar um recurso e, em seguida, procure e escolha Hub de Notificação antes de selecionar o botão Criar.
  3. Na página do Hub de Notificação, execute as seguintes etapas:
    1. No campo Subscrição, selecione o nome da subscrição do Azure que pretende utilizar e, em seguida, selecione um grupo de recursos existente ou crie um novo.

    2. No campo Detalhes do Namespace, insira um nome único para o novo namespace.

    3. No campo Detalhes do Hub de Notificação, digite um nome para o hub de notificação. Isso é necessário porque um namespace contém um ou mais hubs de notificação.

    4. Na lista suspensa Local, escolha um valor que especifique o local onde pretende criar o hub de notificações.

    5. Revise a opção de Zonas de Disponibilidade . Se você escolher uma região com zonas de disponibilidade, a caixa de seleção será selecionada por padrão.

      Observação

      As zonas de disponibilidade são um recurso pago, portanto, uma taxa adicional é adicionada ao seu nível.

    6. Escolha uma opção recuperação de desastres: nenhuma, região de recuperação emparelhada ou região de recuperação flexível. Se você escolher região de recuperação emparelhada, a região de failover será exibida. Se selecionares Região de recuperação flexível, utiliza o menu suspenso para escolher uma das regiões de recuperação.

    7. Selecione o botão Criar. O hub de notificação será criado.

  4. No portal do Azure, navegue até o seu hub de notificação recém-criado e, em seguida, até a folha Gerenciar > Políticas de Acesso.
  5. Na folha Políticas de Acesso, anote a cadeia de conexão da política de DefaultFullSharedAccessSignature. Você precisará disso mais tarde ao criar um serviço de back-end que se comunique com seu hub de notificação.

Para obter mais informações sobre como criar um hub de notificação, consulte Criar um hub de notificação do Azure no portal do Azure.

Configurar o Firebase Cloud Messaging no hub de notificação

Para configurar seu hub de notificação para se comunicar com o Firebase Cloud Messaging:

  1. Na do portal doAzure , navegue até o hub de notificação e selecione a folha Configurações > Google (FCM v1).

  2. Na folha Google (FCM v1) , insira valores para os campos de Chave Privada , e-mail do cliente e ID do projeto . Esses valores podem ser encontrados no arquivo JSON de chave privada que você baixou do Firebase Cloud Messaging:

    Campo Azure Chave JSON Exemplo de valor JSON
    Chave Privada private_key Esse valor deve começar com -----BEGIN PRIVATE KEY-----\n e terminar com -----END PRIVATE KEY-----\n.
    E-mail do cliente client_email firebase-adminsdk-55sfg@pushdemo-d6ab2.iam.gserviceaccount.com
    ID do projeto project_id pushdemo-d6ab2
  3. Na folha Google (FCM v1), selecione o botão Salvar.

Configurar o Serviço de Notificação por Push da Apple no hub de notificação

No portal do Azure, navegue até o hub de notificação e selecione a folha Configurações > Apple (APNS). Em seguida, siga as etapas apropriadas com base na abordagem escolhida anteriormente ao criar um certificado para o hub de notificação.

Importante

Ao definir o Modo de Aplicativo, escolha apenas Produção se quiser enviar notificações por push aos utilizadores que compraram o seu aplicativo na loja.

Opção 1 - Usar um certificado push .p12

  1. Na lâmina Apple (APNS), selecione a autenticação pelo modo de Certificado.
  2. Na seção Apple (APNS), selecione o ícone de ficheiro ao lado do campo Upload Certificate. Em seguida, selecione o arquivo .p12 que você exportou anteriormente e carregue-o.
  3. Na folha Apple (APNS), insira a senha do certificado no campo Senha, se necessário.
  4. Na folha Apple (APNS), selecione o Sandbox modo de aplicação.
  5. Na folha Apple (APNS), selecione o botão Salvar.

Opção 2 - Usar autenticação baseada em token

  1. Na folha Apple (APNS), selecione o modo de autenticação Token .
  2. Na folha Apple (APNS), insira os valores adquiridos anteriormente para os campos Key Id, Bundle Id, Team Ide Token.
  3. Na folha Apple (APNS), selecione o modo de aplicação Sandbox.
  4. Na folha Apple (APNS), selecione o botão Salvar.

Criar uma aplicação de back-end ASP.NET Core Web API

Nesta secção, criará um back-end da API Web ASP.NET Core para lidar com a instalação de dispositivos e enviar notificações para a aplicação .NET MAUI.

Criar um projeto de API da Web

Para criar um projeto de API da Web:

  1. No Visual Studio, crie uma API Web ASP.NET Core projeto:

    Captura de tela da criação de um novo projeto ASP.NET Core Web API no Visual Studio.

  2. Na caixa de diálogo Configurar o seu novo projeto, dê o nome ao projeto PushNotificationsAPI.

  3. Na caixa de diálogo Informações adicionais, verifique se as caixas de seleção Configurar para HTTPS e Usar controladores estão habilitadas.

    Captura de tela da configuração do projeto ASP.NET Core Web API no Visual Studio.

  4. Depois que o projeto tiver sido criado, pressione F5 para executar o projeto.

    No momento, o aplicativo está configurado para usar o WeatherForecastController como o launchUrl, que é definido no\launchSettings.jsPropriedades em arquivo. O aplicativo será iniciado em um navegador da Web e exibirá alguns dados JSON.

    Importante

    Quando você executa um projeto ASP.NET Core que usa HTTPS, o Visual Studio detetará se o certificado de desenvolvimento ASP.NET Core HTTPS está instalado em seu armazenamento de certificados de usuário local e oferecerá para instalá-lo e confiar nele se estiver faltando.

  5. Feche o navegador da Web.

  6. No Explorador de Soluções, expanda a pasta Controladores e exclua WeatherForecastController.cs.

  7. No Gerenciador de Soluções , na raiz do projeto, exclua WeatherForecast.cs.

  8. Abra uma janela de comando e navegue até o diretório que contém o arquivo de projeto. Em seguida, execute os seguintes comandos:

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

    Substitua os valores de placeholders pelos seus próprios nome do Hub de Notificação do Azure e os valores da string de conexão. Eles podem ser encontrados nos seguintes locais em seu Hub de Notificação do Azure:

    Valor de configuração Localização
    NotificationHub:Name Consulte Nome no resumo do do Essentials na parte superior da página Visão Geral do.
    NotificationHub:ConnectionString Consulte DefaultFullSharedAccessSignature* na página Políticas de Acesso.

    Isso define valores de configuração local usando a ferramenta Secret Manager. Isso separa seus segredos do Hub de Notificação do Azure da solução Visual Studio, para garantir que eles não acabem no controle do código-fonte.

    Dica

    Para cenários de produção, considere um serviço como do Azure KeyVault para armazenar com segurança a cadeia de conexão.

Autenticar clientes com uma chave de API

Para autenticar clientes com uma chave de API:

  1. Abra uma janela de comando e navegue até o diretório que contém o arquivo de projeto. Em seguida, execute os seguintes comandos:

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

    Substitua o valor do espaço reservado pela sua chave da API, sendo que esta pode ser qualquer valor.

  2. No Visual Studio, adicione uma nova pasta chamada Authentication ao seu projeto e, em seguida, adicione uma nova classe chamada ApiKeyAuthOptions à pasta Authentication e substitua seu código pelo seguinte código:

    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. No Visual Studio, adicione uma nova classe chamada ApiKeyAuthHandler à pasta Authentication e substitua seu código pelo seguinte código:

    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));
        }
    }
    

    Um manipulador de autenticação é um tipo que implementa o comportamento de um esquema, que neste caso é um esquema de chave de API personalizado.

  4. No Visual Studio, adicione uma nova classe chamada AuthenticationBuilderExtensions à pasta Authentication e substitua seu código pelo seguinte código:

    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);
        }
    }
    

    Este método de extensão será usado para simplificar o código de configuração do middleware em Program.cs.

  5. No Visual Studio, abra o Program.cs e atualize o código para configurar a autenticação de chave de API abaixo da chamada para o método builder.Services.AddControllers:

    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. No Program.cs, atualize o código abaixo do comentário // Configure the HTTP request pipeline para chamar os métodos de extensão UseRouting, UseAuthenticatione MapControllers:

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

    O método de extensão UseAuthentication registra o middleware que usa o esquema de autenticação registrado anteriormente. UseAuthentication deve ser chamado antes de qualquer middleware que dependa da autenticação dos usuários.

    Observação

    Embora uma chave de API não seja tão segura quanto um token, ela será suficiente para este tutorial e será facilmente configurada por meio do ASP.NET Middleware.

Adicionar e configurar serviços

Para adicionar e configurar serviços em seu aplicativo de back-end da API Web:

  1. No Visual Studio, adicione o Microsoft.Azure.NotificationHubs pacote NuGet ao seu projeto. Este pacote NuGet é usado para acessar seu hub de notificação, encapsulado em um serviço.

  2. No Visual Studio, adicione uma nova pasta chamada Models ao seu projeto e, em seguida, adicione uma nova classe chamada PushTemplates à pasta Models e substitua seu código pelo seguinte código:

    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)\" }";
        }
    }
    

    A classe PushTemplates contém cargas úteis de notificação tokenizadas para notificações por push genéricas e silenciosas. Essas cargas úteis são definidas fora do contexto de instalação para permitir a experimentação sem precisar de atualizar as instalações existentes através do serviço. Lidar com alterações em instalações dessa maneira está fora do escopo deste artigo. Em cenários de produto, considere usar modelos personalizados.

  3. No Visual Studio, adicione uma nova classe chamada DeviceInstallation à pasta Models e substitua seu código pelo seguinte código:

    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. No Visual Studio, adicione uma nova classe chamada NotificationRequest à pasta Models e substitua seu código pelo seguinte código:

    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. No Visual Studio, adicione uma nova classe chamada NotificationHubOptions à pasta Models e substitua seu código pelo seguinte código:

    using System.ComponentModel.DataAnnotations;
    
    namespace PushNotificationsAPI.Models;
    
    public class NotificationHubOptions
    {
        [Required]
        public string Name { get; set; }
    
        [Required]
        public string ConnectionString { get; set; }
    }
    
  6. No Visual Studio, adicione uma nova pasta chamada Services ao seu projeto e, em seguida, adicione uma nova interface chamada INotificationService à pasta Services e substitua seu código pelo seguinte código:

    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. No Visual Studio, adicione uma nova classe chamada NotificationHubService à pasta Services e substitua seu código pelo seguinte código:

    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);
        }
    }
    

    A expressão de tag fornecida ao método SendTemplateNotificationsAsync é limitada a 20 tags se elas contiverem apenas ORs. Caso contrário, eles são limitados a 6 tags. Para obter mais informações, consulte Roteamento e Expressões de Marca.

  8. No Visual Studio, abra Program.cs e atualize o código para adicionar o NotificationHubService como uma implementação singleton de INotificationService abaixo da chamada para o método builder.Services.AddAuthentication:

    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();
    

Criar a API REST de notificações

Para criar a API REST de notificações:

  1. No Visual Studio, adicione um novo Controller à pasta Controllers, chamado NotificationsController.

    Dica

    Escolha o modelo de Controlador de API com ações de leitura/gravação.

  2. No arquivo NotificationsController.cs, adicione as seguintes instruções using na parte superior do arquivo:

    using System.ComponentModel.DataAnnotations;
    using System.Net;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using PushNotificationsAPI.Models;
    using PushNotificationsAPI.Services;
    
  3. No arquivo NotificationsController.cs, adicione o atributo Authorize à classe NotificationsController:

    [Authorize]
    [ApiController]
    [Route("api/[controller]")]
    public class NotificationsController : ControllerBase
    
  4. No ficheiro NotificationsController.cs, atualiza o construtor NotificationsContoller para aceitar a instância registada de INotificationService como argumento e atribuí-la a um membro readonly:

    readonly INotificationService _notificationService;
    
    public NotificationsController(INotificationService notificationService)
    {
        _notificationService = notificationService;
    }
    
  5. No arquivo NotificationsContoller.cs, substitua todos os métodos com o seguinte código:

    [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. No arquivo Properties/launchSettings.json, altere a propriedade launchUrl para cada perfil de weatherforecast para api/notifications.

Criar um aplicativo de API

Agora, irá criar uma aplicação API no Serviço de Aplicações do Azure para hospedar o seu serviço de back-end. Isso pode ser feito diretamente do Visual Studio ou do Visual Studio Code, com a CLI do Azure, o Azure PowerShell, a CLI do Desenvolvedor do Azure e por meio do Portal do Azure. Para obter mais informações, consulte Publicar seu aplicativo Web.

Para criar um aplicativo de API no portal do Azure:

  1. Em um navegador web, entre no portal do Azure.

  2. No portal do Azure, clique no botão Criar um recurso e, em seguida, pesquise e escolha Aplicação de API antes de selecionar o botão Criar.

  3. Na página Criar aplicação de API, atualize os seguintes campos antes de selecionar o botão Criar:

    Domínio Ação
    Subscrição Escolha a mesma assinatura de destino na qual você criou o hub de notificação.
    Grupo de Recursos Escolha o mesmo grupo de recursos no qual você criou o hub de notificação.
    Nome Insira um nome globalmente exclusivo.
    Pilha de tempo de execução Verifique se a versão mais recente do .NET está selecionada.
  4. Depois de providenciado o API App, navegue para o recurso específico.

  5. Na página Visão Geral, anote o valor de domínio padrão. Esta URL é o endereço de back-end que será consumido pela sua aplicação .NET MAUI. A URL usará o nome do aplicativo de API que você especificou, com o formato https://<app_name>.azurewebsites.net.

  6. No portal do Azure, navegue até o painel Definições > Variáveis de ambiente e verifique se a guia Configurações do aplicativo está selecionada. Em seguida, use o botão Adicionar para adicionar as seguintes configurações:

    Nome Valor
    Autenticação:ApiKey <api_key_value>
    NotificationHub:Nome <hub_name_value>
    NotificationHub:ConnectionString <hub_connection_string_value>

    Importante

    A definição de aplicação Authentication:ApiKey foi adicionada para maior simplicidade. Para cenários de produção, considere um serviço como do Azure KeyVault para armazenar com segurança a cadeia de conexão.

    Depois que todas essas configurações tiverem sido inseridas, selecione o botão Aplicar e, em seguida, o botão Confirmar.

Publicar o serviço de back-end

Para publicar seu serviço de back-end no Serviço de Aplicativo do Azure:

  1. No Visual Studio, clique com o botão direito do mouse em seu projeto e selecione Publicar.
  2. No assistente Publicar, selecione Azure e, em seguida, o botão Avançar.
  3. No assistente Publicar, selecione do Serviço de Aplicativo do Azure (Windows) e, em seguida, o botão Próxima.
  4. No assistente Publicar, siga o fluxo de autenticação para conectar o Visual Studio à sua assinatura do Azure e publicar o aplicativo.

O Visual Studio cria, empacota e publica o aplicativo no Azure e, em seguida, inicia o aplicativo em seu navegador padrão. Para obter mais informações, consulte Publicar um aplicativo Web ASP.NET.

Dica

Você pode baixar um perfil de publicação para o seu aplicativo no painel Visão Geral do seu aplicativo de API no portal do Azure e, em seguida, usar o perfil no Visual Studio para publicar o seu aplicativo.

Validar a API publicada

Para verificar se o aplicativo de API foi publicado corretamente, você deve usar as ferramentas REST de sua escolha para enviar uma solicitação de POST para o seguinte endereço:

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

Observação

O endereço base é https://<app_name>.azurewebsites.net.

Certifique-se de configurar os cabeçalhos de solicitação para incluir a chave apikey e o seu respetivo valor, defina o corpo como não formatado e use o seguinte conteúdo JSON como espaço reservado:

{}

Você deve receber uma resposta 400 Bad Request do serviço.

Observação

Ainda não é possível testar a API usando dados de solicitação válidos, pois isso exigirá informações específicas da plataforma do aplicativo .NET MAUI.

Para obter mais informações sobre como chamar APIs REST, consulte Usar arquivos .http no Visual Studio e Testar APIs da Web com o Http Repl. No Visual Studio Code, REST Client pode ser usado para testar APIs REST.

Criar um aplicativo .NET MAUI

Nesta seção, você criará um aplicativo .NET Multi-platform App UI (.NET MAUI) que permite que você se registre para receber notificações por push de um hub de notificação por meio do serviço de back-end e cancele o registro.

Para criar seu aplicativo .NET MAUI:

  1. No Visual Studio, crie um novo aplicativo .NET MAUI chamado PushNotificationsDemo, usando o .NET MAUI App modelo de projeto.

  2. No Visual Studio, adicione uma nova pasta chamada Models ao projeto .NET MAUI e, em seguida, adicione uma nova classe chamada DeviceInstallation à pasta Models e substitua seu código pelo seguinte código:

    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. No Visual Studio, adicione uma enumeração chamada PushDemoAction à pasta Models e substitua seu código pelo seguinte código:

    namespace PushNotificationsDemo.Models;
    
    public enum PushDemoAction
    {
        ActionA,
        ActionB
    }
    
  4. No Visual Studio, adicione uma nova pasta chamada Services ao projeto .NET MAUI e, em seguida, adicione uma nova interface chamada IDeviceInstallationService à pasta Services e substitua seu código pelo seguinte código:

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

    Esta interface será implementada em cada plataforma posteriormente, para fornecer as informações DeviceInstallation exigidas pelo serviço de back-end.

  5. No Visual Studio, adicione uma interface chamada INotificationRegistrationService à pasta Services e substitua seu código pelo seguinte código:

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

    Essa interface lidará com a interação entre o cliente e o serviço de back-end.

  6. No Visual Studio, adicione uma interface chamada INotificationActionService à pasta Services e substitua seu código pelo seguinte código:

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

    Esta interface será usada como um mecanismo simples para centralizar o tratamento das ações de notificação.

  7. No Visual Studio, adicione uma interface chamada IPushDemoNotificationActionService à pasta Services e substitua seu código pelo seguinte código:

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

    O tipo IPushDemoNotificationActionService é específico desta aplicação e usa a enumeração PushDemoAction para identificar a ação a ser acionada usando uma abordagem fortemente tipada.

  8. No Visual Studio, adicione uma classe chamada NotificationRegistrationService à pasta Services e substitua seu código pelo seguinte código:

    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. No Visual Studio, adicione uma classe chamada PushDemoNotificationActionService à pasta Services e substitua seu código pelo seguinte código:

    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. No Visual Studio, adicione uma classe chamada Config à raiz do projeto e substitua seu código pelo seguinte código:

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

    A classe Config é usada como uma maneira simples de manter seus segredos fora do controle do código-fonte. Você pode substituir esses valores como parte de uma compilação automatizada ou substituí-los usando uma classe parcial local.

    Importante

    Ao especificar o endereço base no aplicativo .NET MAUI, certifique-se de que ele termine com um /.

  11. No Visual Studio, adicione uma classe chamada Config.local_secrets à raiz do projeto. Em seguida, substitua o código no arquivo Config.local_secrets.cs com o seguinte código:

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

    Substitua os valores de marcador pelos valores escolhidos ao criar o serviço de back-end. O URL BackendServiceEndpoint deve usar o formato https://<api_app_name>.azurewebsites.net/.

    Dica

    Lembre-se de adicionar *.local_secrets.* ao seu arquivo .gitignore para evitar comprometer esse arquivo com o controle do código-fonte.

Criar a interface do usuário

Para criar a interface do usuário do aplicativo:

  1. No Visual Studio, abra MainPage.xaml e substitua o VerticalStackLayout e seus filhos pelo seguinte XAML:

    <VerticalStackLayout Margin="20"
                         Spacing="6">
        <Button x:Name="registerButton"
                Text="Register"
                Clicked="OnRegisterButtonClicked" />
        <Button x:Name="deregisterButton"
                Text="Deregister"
                Clicked="OnDeregisterButtonClicked" />
    </VerticalStackLayout>
    
  2. No Visual Studio, abra MainPage.xaml.cs e adicione uma instrução using para o namespace PushNotificationsDemo.Services:

    using PushNotificationsDemo.Services;
    
  3. No arquivo MainPage.xaml.cs, adicione um campo de apoio readonly para armazenar uma referência à implementação INotificationRegistrationService.

    readonly INotificationRegistrationService _notificationRegistrationService;
    
  4. No construtor MainPage, resolva a implementação INotificationRegistrationService e atribua-a ao campo de suporte _notificationRegistrationService:

    public MainPage(INotificationRegistrationService service)
    {
        InitializeComponent();
    
        _notificationRegistrationService = service;
    }
    
  5. Na classe MainPage, implemente os manipuladores de eventos OnRegisterButtonClicked e OnDeregisterButtonClicked, chamando os métodos de registro e cancelamento de registro correspondentes no objeto 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;
                });
        });
    }
    
    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(() =>
        {
            DisplayAlertAsync("Push notifications demo", message, "OK")
                .ContinueWith((task) =>
                {
                    if (task.IsFaulted)
                        throw task.Exception;
                });
        });
    }
    

    Importante

    No aplicativo, o registro e cancelamento de registro é realizado em resposta à entrada do usuário, para permitir que essa funcionalidade seja explorada e testada mais facilmente. Em um aplicativo de produção, você normalmente executaria as ações de registro e cancelamento de registro durante o ponto apropriado do ciclo de vida do aplicativo, sem exigir a entrada explícita do usuário.

  6. No Visual Studio, abra App.xaml.cs e adicione as seguintes instruções using:

    using PushNotificationsDemo.Models;
    using PushNotificationsDemo.Services;
    
  7. No App.xaml.cs, adicione um readonly campo de suporte para armazenar uma referência à implementação IPushDemoNotificationActionService:

    readonly IPushDemoNotificationActionService _actionService;
    
  1. No construtor App, resolva a implementação IPushDemoNotificationActionService e atribua-a ao campo de suporte _actionService e inscreva-se no evento IPushDemoNotificationActionService.ActionTriggered:

    public App(IPushDemoNotificationActionService service)
    {
        InitializeComponent();
    
        _actionService = service;
        _actionService.ActionTriggered += NotificationActionTriggered;
    
        MainPage = new AppShell();
    }
    
  1. No construtor App, resolva a implementação IPushDemoNotificationActionService e atribua-a ao campo de suporte _actionService e inscreva-se no evento IPushDemoNotificationActionService.ActionTriggered:

    public App(IPushDemoNotificationActionService service)
    {
        InitializeComponent();
    
        _actionService = service;
        _actionService.ActionTriggered += NotificationActionTriggered;
    }
    
  1. Na classe App, implemente o manipulador de eventos para o evento IPushDemoNotificationActionService.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;
                });
        });
    }
    
    void NotificationActionTriggered(object sender, PushDemoAction e)
    {
        ShowActionAlert(e);
    }
    
    void ShowActionAlert(PushDemoAction action)
    {
        MainThread.BeginInvokeOnMainThread(() =>
        {
            Windows[0].Page?.DisplayAlertAsync("Push notifications demo", $"{action} action received.", "OK")
                .ContinueWith((task) =>
                {
                    if (task.IsFaulted)
                        throw task.Exception;
                });
        });
    }
    

    O manipulador de eventos para o evento ActionTriggered demonstra o recebimento e a propagação de ações de notificação por push. Normalmente, estes são tratados silenciosamente, por exemplo, navegando para uma vista específica ou atualizando alguns dados em vez de apresentar um alerta.

Configurar a aplicação Android

Para configurar seu aplicativo .NET MAUI no Android para receber e processar notificações por push:

  1. No Visual Studio, adicione o pacote NuGet Xamarin.Firebase.Messaging ao seu projeto de aplicação .NET MAUI.

  2. No Visual Studio, adicione seu arquivo google-services.json à pasta Platforms/Android do seu projeto de aplicativo .NET MAUI. Uma vez que o arquivo foi adicionado ao seu projeto, ele deve ter sido adicionado com uma ação de compilação de GoogleServicesJson:

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

    Dica

    Lembre-se de adicionar google-services.json ao seu arquivo .gitignore para evitar comprometer esse arquivo com o controle do código-fonte.

  3. No Visual Studio, edite o arquivo de projeto (*.csproj) e defina o SupportedOSPlatformVersion para Android como 26.0:

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

    O Google fez alterações nos canais de notificação do Android na API 26. Para mais informações, consulte a seção Canais de notificação no site developer.android.com.

  4. Na pasta Platforms/Android do projeto, adicione uma nova classe chamada DeviceInstallationService e substitua seu código pelo seguinte código:

    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.";
        }
    }
    

    Esta classe fornece um ID exclusivo, usando o valor Secure.AndroidId e o payload de registo do hub de notificações.

  5. Na pasta Platforms/Android do projeto, adicione uma nova classe chamada PushNotificationFirebaseMessagingService e substitua seu código pelo seguinte código:

    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);
        }
    }
    

    Esta classe tem um atributo IntentFilter que inclui o filtro com.google.firebase.MESSAGING_EVENT. Esse filtro permite que o Android passe mensagens recebidas para essa classe para processamento.

    Para obter informações sobre o formato de mensagens do Firebase Cloud Messaging, consulte Sobre mensagens do FCM no developer.android.com.

  6. No Visual Studio, abra o arquivo MainActivity.cs na pasta Platforms/Android e adicione as seguintes instruções using:

    using Android.App;
    using Android.Content;
    using Android.Content.PM;
    using Android.OS;
    using PushNotificationsDemo.Services;
    using Firebase.Messaging;
    
  7. Na classe MainActivity, defina o LaunchMode como SingleTop para que o MainActivity não seja criado novamente quando aberto:

    [Activity(
        Theme = "@style/Maui.SplashTheme",
        MainLauncher = true,
        LaunchMode = LaunchMode.SingleTop,
        ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
    
  8. Na classe MainActivity, adicione campos de suporte para armazenar referências às implementações IPushDemoNotificationActionService e IDeviceInstallationService:

    IPushDemoNotificationActionService _notificationActionService;
    IDeviceInstallationService _deviceInstallationService;
    
  9. Na classe MainActivity, adicione propriedades privadas NotificationActionService e DeviceInstallationService que obtêm as suas implementações concretas do contêiner de injeção de dependência do aplicativo.

    IPushDemoNotificationActionService NotificationActionService =>
        _notificationActionService ?? (_notificationActionService = IPlatformApplication.Current.Services.GetService<IPushDemoNotificationActionService>());
    
    IDeviceInstallationService DeviceInstallationService =>
        _deviceInstallationService ?? (_deviceInstallationService = IPlatformApplication.Current.Services.GetService<IDeviceInstallationService>());
    
  10. Na classe MainActivity, implemente a interface Android.Gms.Tasks.IOnSuccessListener para recuperar e armazenar o token do Firebase:

    public class MainActivity : MauiAppCompatActivity, Android.Gms.Tasks.IOnSuccessListener
    {
        public void OnSuccess(Java.Lang.Object result)
        {
            DeviceInstallationService.Token = result.ToString();
        }
    }
    
  11. Na classe MainActivity, adicione o método ProcessNotificationActions que verificará se um determinado Intent tem um valor extra chamado actione, em seguida, acione condicionalmente esse action usando a implementação IPushDemoNotificationActionService:

    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. Na classe MainActivity, substitua o método OnNewIntent para chamar o método ProcessNotificationActions:

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

    Como o LaunchMode para o Activity está definido como SingleTop, um Intent será enviado para a instância de Activity existente por meio da substituição de OnNewIntent, em vez do método OnCreate. Portanto, deve-se lidar com uma intenção recebida em OnNewIntent e OnCreate.

  13. Na classe MainActivity, substitua o método OnCreate para chamar o método ProcessNotificationActions e recuperar o token do Firebase, adicionando MainActivity como o IOnSuccessListener:

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

    Observação

    A aplicação deve ser registada novamente cada vez que o utilizador a executa e a interrompe a partir de uma sessão de depuração para continuar a receber notificações push.

  14. No Visual Studio, adicione a permissão POST_NOTIFICATIONS ao arquivo AndroidManifest.xml na pasta Platforms/Android:

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

    Para obter mais informações sobre esta permissão, consulte permissões de tempo de execução de notificação no developer.android.com.

  15. No Visual Studio, abra MainPage.xaml.cs e adicione o seguinte código à classe MainPage:

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

    Esse código é executado no Android quando o MainPage aparece e solicita que o usuário conceda a permissão de POST_NOTIFICATIONS. Para obter mais informações sobre permissões do .NET MAUI, consulte Permissions.

Configurar a aplicação iOS

O simulador iOS suporta notificações remotas no iOS 16+ quando executado no macOS 13+ em computadores Mac com processadores de silício ou T2 da Apple. Cada simulador gera tokens de registro que são exclusivos para a combinação desse simulador e do hardware do Mac em que ele está sendo executado.

Importante

O simulador suporta o ambiente sandbox do Apple Push Notification Service.

As instruções a seguir pressupõem que você esteja usando um hardware compatível com o recebimento de notificações remotas em um simulador do iOS. Se esse não for o caso, você terá que executar o aplicativo iOS em um dispositivo físico, o que exigirá que você crie um perfil de provisionamento para seu aplicativo que inclua o recurso de Notificações por Push. Em seguida, você precisará garantir que seu aplicativo seja criado usando seu perfil de certificado e provisionamento. Para obter mais informações sobre como fazer isso, consulte Configurar seu aplicativo iOS para funcionar com os Hubs de Notificação do Azuree siga as instruções abaixo.

Para configurar seu aplicativo .NET MAUI no iOS para receber e processar notificações por push:

  1. No Visual Studio, edite o arquivo de projeto (*.csproj) e defina o SupportedOSPlatformVersion para iOS como 13.0:

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

    A Apple fez alterações em seu serviço de push no iOS 13. Para mais informações, consulte atualizações do Azure Notification Hubs para iOS 13.

  2. No Visual Studio, adicione um ficheiro Entitlements.plist à pasta Platforms/iOS do projeto e adicione o seguinte XML ao ficheiro:

    <?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>
    

    Isto configura a concessão do ambiente APS e especifica o uso do ambiente de desenvolvimento do serviço Apple Push Notification. Em aplicações de produção, esse valor de permissão deve ser definido como production. Para obter mais informações sobre esse direito, consulte APS Environment Entitlement on developer.apple.com.

    Para obter mais informações sobre como adicionar um ficheiro de permissões, consulte permissões do iOS.

  3. No Visual Studio, adicione uma nova classe chamada DeviceInstallationService à pasta Platforms/iOS do projeto e adicione o seguinte código ao arquivo:

    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";
        }
    }
    

    Essa classe fornece uma ID exclusiva, usando o valor UIDevice.IdentifierForVendor e a carga útil de registro do hub de notificação.

  4. No Visual Studio, adicione uma nova classe chamada NSDataExtensions à pasta Platforms/iOS do projeto e adicione o seguinte código ao arquivo:

    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();
        }
    }
    

    O método de extensão ToHexString será consumido pelo código que você adicionará que analisa o token de dispositivo recuperado.

  5. No Visual Studio, abra o arquivo AppDelegate.cs na pasta Platforms/iOS e adicione as seguintes instruções using:

    using System.Diagnostics;
    using Foundation;
    using PushNotificationsDemo.Platforms.iOS;
    using PushNotificationsDemo.Services;
    using UIKit;
    using UserNotifications;
    
  6. Na classe AppDelegate, adicione campos de suporte para armazenar referências às implementações IPushDemoNotificationActionService, INotificationRegistrationServicee IDeviceInstallationService:

    IPushDemoNotificationActionService _notificationActionService;
    INotificationRegistrationService _notificationRegistrationService;
    IDeviceInstallationService _deviceInstallationService;
    
  7. Na classe AppDelegate, adicione NotificationActionService, NotificationRegistrationServicee DeviceInstallationService propriedades privadas que recuperam suas implementações concretas do contêiner de injeção de dependência do aplicativo:

    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. Na classe AppDelegate, adicione o método CompleteRegistrationAsync para definir o valor da propriedade IDeviceInstallationService.Token:

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

    Esse método também atualiza o registro e armazena em cache o token do dispositivo se ele tiver sido atualizado desde a última vez que foi armazenado.

  9. Na classe AppDelegate, adicione o método ProcessNotificationActions para processar os dados de notificação NSDictionary e chamar condicionalmente NotificationActionService.TriggerAction:

    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. Na classe AppDelegate, adicione o método RegisteredForRemoteNotifications passando o argumento deviceToken para o método CompleteRegistrationAsync:

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

    Esse método será chamado quando o aplicativo for registrado para receber notificação remota e for usado para solicitar o token de dispositivo exclusivo, que é efetivamente o endereço do seu aplicativo no dispositivo.

  11. Na classe AppDelegate, adicione o método ReceivedRemoteNotification passando o argumento userInfo para o método ProcessNotificationActions:

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

    Esse método será chamado quando o aplicativo receber uma notificação remota e for usado para processar a notificação.

  12. Na classe AppDelegate, adicione o método FailedToRegisterForRemoteNotifications para registrar quaisquer erros:

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

    Esse método será chamado quando o aplicativo não conseguir se registrar para receber notificações remotas. O registro pode falhar se o dispositivo não estiver conectado à rede, se o servidor APNS estiver inacessível ou se o aplicativo estiver configurado incorretamente.

    Observação

    Para cenários de produção, convém implementar o registro em log e o tratamento de erros adequados no método FailedToRegisterForRemoteNotifications.

  13. Na classe AppDelegate, adicione o método FinishedLaunching para solicitar condicionalmente permissão para usar notificações e registrar-se para notificações remotas:

    [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);
    }
    

    Para obter informações sobre como pedir permissão para usar notificações, consulte Pedindo permissão para usar notificações no developer.apple.com.

Para obter informações sobre notificações no iOS, consulte Notificações de Usuário no developer.apple.com.

Registrar tipos com o contêiner de injeção de dependência do aplicativo

  1. No Visual Studio, abra MauiProgram.cs e adicione uma instrução using para o namespace PushNotificationsDemo.Services:

    using PushNotificationsDemo.Services;
    
  2. Na classe MauiProgram, adicione código para o método de extensão RegisterServices que registra o DeviceInstallationService em cada plataforma e os serviços de PushDemoNotificationActionService e NotificationRegistrationService entre plataformas e que retorna um objeto MauiAppBuilder:

    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. Na classe MauiProgram, adicione código para o método de extensão RegisterViews que registra o tipo MainPage como um singleton e que retorna um objeto MauiAppBuilder:

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

    O tipo MainPage é registrado porque requer uma dependência INotificationRegistrationService e todos os tipos que exigem uma dependência devem ser registrados com o contêiner de injeção de dependência.

  4. Na classe MauiProgram, modifique o método CreateMauiApp para que ele chame os métodos de extensão RegisterServices 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();
    }
    

Para obter mais informações sobre a injeção de dependência no .NET MAUI, consulte Injeção de Dependência.

Testar a aplicação

Você pode testar seu aplicativo enviando notificações por push para o aplicativo usando o serviço de back-end ou por meio do portal do Azure.

O simulador iOS suporta notificações remotas no iOS 16+ quando executado no macOS 13+ em computadores Mac com processadores de silício ou T2 da Apple. Se você não atender a esses requisitos de hardware, terá que testar seu aplicativo iOS em um dispositivo físico. No Android, você pode testar seu aplicativo em um dispositivo físico desbloqueado pelo desenvolvedor ou em um emulador.

Android e iOS exibem notificações por push em nome do aplicativo quando ele está sendo executado em segundo plano. Se o aplicativo estiver sendo executado em primeiro plano quando a notificação for recebida, o código do aplicativo determinará o comportamento. Por exemplo, você pode atualizar a interface do seu aplicativo para refletir as novas informações contidas na notificação.

Teste usando o serviço de back-end

Para enviar uma notificação por push de teste para seu aplicativo por meio do serviço de back-end publicado no Serviço de Aplicativo do Azure:

  1. No Visual Studio, execute o aplicativo PushNotificationsDemo no Android ou iOS e selecione o botão Registrar.

    Observação

    Se você estiver testando no Android, certifique-se de que não está executando usando a configuração de depuração. Como alternativa, se o aplicativo tiver sido implantado anteriormente, certifique-se de que ele foi fechado à força e, em seguida, inicie-o novamente a partir do iniciador.

  2. Nas ferramentas REST de sua escolha, envie uma solicitação de POST para o seguinte endereço:

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

    Certifique-se de configurar os cabeçalhos de solicitação para incluir a chave apikey e seu valor, definir o corpo como "raw" e usar o seguinte conteúdo JSON:

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

    O pedido global deve ser semelhante ao seguinte exemplo:

    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. Nas ferramentas REST de sua escolha, valide se você recebeu uma resposta 200 OK.

  4. No aplicativo no Android ou iOS, deve aparecer um alerta mostrando ação ActionA recebida.

Para obter mais informações sobre como chamar APIs REST, consulte Usar arquivos .http no Visual Studio e Testar APIs da Web com o Http Repl. No Visual Studio Code, de cliente REST pode ser usada para testar APIs REST.

Teste usando o portal do Azure

Os Hubs de Notificação do Azure permitem que você verifique se seu aplicativo pode receber notificações por push.

Para enviar uma notificação por push de teste para seu aplicativo por meio do portal do Azure:

  1. No Visual Studio, execute o aplicativo PushNotificationsDemo no Android ou iOS e selecione o botão Registrar.

    Observação

    Se estiveres a testar no Android, assegura-te de que não estás a executar usando a configuração de depuração. Como alternativa, se o aplicativo tiver sido implantado anteriormente, certifique-se de que ele foi fechado à força e, em seguida, inicie-o novamente a partir do iniciador.

  2. No portal Azure, navegue até ao hub de notificações e selecione o botão Teste de Envio na folha Visão Geral.

  3. Na folha Test Send, selecione o de plataforma necessário e modifique a carga útil.

    Para a Apple, use a seguinte carga útil:

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

    Para Android, use o seguinte payload:

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

    O portal do Azure deve indicar que a notificação foi enviada com êxito.

    Para obter informações sobre o formato de mensagem do Firebase Cloud Messaging, consulte Sobre mensagens do FCM no developer.android.com.

  4. No aplicativo no Android ou iOS, deve aparecer um alerta mostrando ação ActionA recebida.

Solução de problemas

As seções a seguir discutem os problemas comuns encontrados ao tentar consumir notificações por push em um aplicativo cliente.

Nenhuma resposta do serviço de back-end

Ao testar localmente, verifique se o serviço de back-end está em execução e usando a porta correta.

Se estiver testando no aplicativo de API do Azure, verifique se o serviço está em execução e foi implantado e iniciado sem erros.

Certifique-se de ter especificado o endereço base corretamente em suas ferramentas REST ou na configuração do aplicativo .NET MAUI. O endereço base deve ser https://<api_name>.azurewebsites.net ou https://localhost:7020 ao testar localmente.

Recebendo um código de status 401 do serviço de back-end

Valide se você está definindo o cabeçalho da solicitação apikey corretamente e se esse valor corresponde ao que você configurou para o serviço de back-end.

Se você receber esse erro ao testar localmente, verifique se o valor da chave definida em seu aplicativo .NET MAUI corresponde ao valor Authentication:ApiKey segredos de usuário usado pelo serviço de back-end.

Se você estiver testando com um aplicativo de API do Azure, verifique se o valor da chave definido em seu aplicativo .NET MAUI corresponde ao valor de configuração de aplicativo Authentication:ApiKey definido no portal do Azure. Se você criou ou alterou essa configuração de aplicativo depois de implantar o serviço de back-end, deverá reiniciar o serviço para que o valor entre em vigor.

Recebendo um código de status 404 do serviço de back-end

Valide se o ponto de extremidade e o método HTTP estão corretos:

  • PUT - https://<api_name>.azurewebsites.net/api/notifications/installations
  • EXCLUIR - https://<api_name>.azurewebsites.net/api/notifications/installations/<installation_id>
  • CORREIO - https://<api_name>.azurewebsites.net/api/notifications/requests

Ou ao testar localmente:

  • PUT - https://localhost:7020/api/notifications/installations
  • EXCLUIR - https://localhost:7020/api/notifications/installations/<installation_id>
  • PUBLICAÇÃO - https://localhost:7020/api/notifications/requests

Importante

Ao especificar o endereço base no aplicativo .NET MAUI, certifique-se de que ele termine com um /. O endereço base deve ser https://<api_name>.azurewebsites.net ou https://localhost:7020/ ao testar localmente.

Não receber notificações no Android depois de iniciar ou parar uma sessão de depuração

Certifique-se de se registrar sempre que iniciar uma sessão de depuração. O depurador fará com que um novo token do Firebase seja gerado e, portanto, a instalação do hub de notificação deve ser atualizada.

Não é possível registrar e uma mensagem de erro do hub de notificação é exibida

Verifique se o dispositivo de teste tem conectividade de rede. Em seguida, determine o código de status da resposta HTTP definindo um ponto de interrupção para inspecionar a propriedade StatusCode no HttpResponse.

Analise as sugestões de solução de problemas anteriores, quando aplicável, com base no código de status.

Defina um ponto de interrupção nas linhas que retornam códigos de status específicos para a respetiva API. Em seguida, tente chamar o serviço de back-end ao depurar o código localmente.

Valide se o serviço de back-end está funcionando conforme o esperado pelas ferramentas REST de sua escolha e use a carga criada pelo aplicativo .NET MAUI para a plataforma escolhida.

Revise as seções de configuração específicas da plataforma para garantir que nenhuma etapa tenha sido perdida. Verifique se os valores adequados estão a ser resolvidos para as variáveis InstallationId e Token na plataforma escolhida.

Não é possível resolver um ID para o dispositivo a mensagem de erro do dispositivo

Revise as seções de configuração específicas da plataforma para garantir que nenhuma etapa tenha sido perdida.