Compartilhar via


Tutorial: Enviar notificações por push para aplicativos Xamarin.Forms usando hubs de notificação do Azure por meio de um serviço de back-end

Baixar exemplo Baixar o de exemplo

Neste tutorial, você usará hubs de notificação do Azure para enviar notificações por push para um aplicativo do Xamarin.Forms direcionado Android e iOS.

Um back-end da API Web ASP.NET Core é usado para lidar com de registro de dispositivo para o cliente usando a abordagem mais recente e melhor instalação. O serviço também enviará notificações por push de maneira multiplataforma.

Essas operações são tratadas usando o SDK dos Hubs de Notificação para operações de back-end. Mais detalhes sobre a abordagem geral são fornecidos no Registro da documentação do de back-end do aplicativo.

Este tutorial leva você pelas seguintes etapas:

Pré-requisitos

Para acompanhar, você precisa:

  • Uma assinatura do Azure em que você pode criar e gerenciar recursos.
  • Um Mac com Visual Studio para Mac instalado ou um computador executando Visual Studio 2019.
  • Visual Studio 2019 os usuários também devem ter desenvolvimento móvel com cargas de trabalho de .NET e ASP.NET e desenvolvimento da Web instaladas.
  • A capacidade de executar o aplicativo em Android (dispositivos físicos ou emuladores) ou do iOS (somente dispositivos físicos).

Para Android, você deve ter:

  • Um dispositivo físico desbloqueado pelo desenvolvedor ou um do emulador (executando a API 26 e superior com o Google Play Services instalado).

Para iOS, você deve ter:

  • Uma conta de desenvolvedor ativa Da Apple.
  • Um dispositivo iOS físico registrado em sua conta de desenvolvedor(executando o iOS 13.0 e superior).
  • Um de certificado de desenvolvimento.p12 instalado em seu conjunto de chaves permitindo que você executar um aplicativo em um dispositivo físico.

Nota

O Simulador do iOS não dá suporte a notificações remotas e, portanto, um dispositivo físico é necessário ao explorar esse exemplo no iOS. No entanto, você não precisa executar o aplicativo em android e iOS para concluir este tutorial.

Você pode seguir as etapas neste exemplo de primeiros princípios sem experiência prévia. No entanto, você se beneficiará de ter familiaridade com os seguintes aspectos.

Importante

As etapas fornecidas são específicas para Visual Studio para Mac. É possível acompanhar usando do Visual Studio 2019, mas pode haver algumas diferenças para reconciliar. Por exemplo, descrições de interface do usuário e fluxos de trabalho, nomes de modelo, configuração de ambiente e assim por diante.

Configurar os Serviços de Notificação por Push e o Hub de Notificação do Azure

Nesta seção, você configurará do Firebase Cloud Messaging (FCM) e apns (Serviços de Notificação por Push) da Apple. Em seguida, você cria e configura um hub de notificação para trabalhar com esses serviços.

Criar um projeto do Firebase e habilitar o Firebase Cloud Messaging para Android

  1. Entre no console do Firebase . Crie um novo projeto do Firebase inserindo PushDemo como o nome do projeto .

    Nota

    Um nome exclusivo será gerado para você. Por padrão, isso é composto por uma variante minúscula do nome fornecido mais um número gerado separado por um traço. Você pode alterar isso se quiser, desde que ainda seja globalmente exclusivo.

  2. Depois de criar seu projeto, selecione Adicionar o Firebase ao seu aplicativo Android.

    Adicionar o Firebase ao seu aplicativo Android

  3. Na página Adicionar o Firebase ao aplicativo Android página, siga as etapas a seguir.

    1. Para o nome do pacote do Android, insira um nome para o pacote. Por exemplo: com.<organization_identifier>.<package_name>.

      Especificar o nome do pacote

    2. Selecione Registrardo aplicativo.

    3. Selecione Baixar google-services.json. Em seguida, salve o arquivo em uma pasta local para uso posterior e selecione Próximo.

      Baixar google-services.json

    4. Selecione Próximo.

    5. Selecione Continuar no console

      Nota

      Se o botão Continuar no console não estiver habilitado, devido ao verificar a instalação verificação, escolha Ignorar esta etapa.

  4. No console do Firebase, selecione a engrenagem do projeto. Em seguida, selecione Configurações do Projeto.

    Selecionar Configurações do Projeto

    Nota

    Se você não tiver baixado o arquivo google-services.json, poderá baixá-lo nesta página.

  5. Alterne para a guia do Cloud Messaging na parte superior. Copie e salve o de chave do servidor para uso posterior. Use esse valor para configurar o hub de notificação.

    Copiar chave do servidor

Registrar seu aplicativo iOS para notificações por push

Para enviar notificações por push para um aplicativo iOS, registre seu aplicativo na Apple e também registre-se para notificações por push.

  1. Se você ainda não registrou seu aplicativo, navegue até o portal de provisionamento do iOS no Centro de Desenvolvedores da Apple. Entre no portal com sua ID da Apple, navegue até Certificados, Identificadores & Perfise selecione Identificadores. Clique em + para registrar um novo aplicativo.

    página IDs de Aplicativo do Portal de Provisionamento do iOS

  2. Na tela Registrar um Novo Identificador, selecione o botão de opção IDs do Aplicativo. Em seguida, selecione Continuar.

    Portal de Provisionamento do iOS registrar nova página de ID

  3. Atualize os três valores a seguir para seu novo aplicativo e selecione Continuar:

    • Descrição: digite um nome descritivo para seu aplicativo.

    • ID do pacote: insira uma ID do pacote do formulário com.<organization_identifier>.<product_name> conforme mencionado no guia de distribuição de aplicativos . Na captura de tela a seguir, o valor é usado como um identificador da organização e o valor PushDemo é usado como o nome do produto.

      página de ID do aplicativo de registro do Portal de Provisionamento do iOS

    • de Notificações por Push: verifique a opção de Notificações por Push na seção recursos do .

      Formulário para registrar uma nova ID do aplicativo

      Essa ação gera sua ID do aplicativo e solicita que você confirme as informações. Selecione Continuare selecione Registrar para confirmar a nova ID do aplicativo.

      confirmar nova ID do aplicativo

      Depois de selecionar Registrar, você verá a nova ID do aplicativo como um item de linha na página Certificados , Identificadores & Perfis.

  4. Na página Certificados, Identificadores & Perfis, em Identificadores, localize o item de linha de ID do Aplicativo que você criou. Em seguida, selecione sua linha para exibir a tela Editar a Configuração de ID do Aplicativo.

Criando um certificado para Hubs de Notificação

Um certificado é necessário para permitir que o hub de notificação funcione com do APNS (Serviços de Notificação por Push) da Apple e pode ser fornecido de duas maneiras:

  1. Criar um certificado push p12 que pode ser carregado diretamente no Hub de Notificação (a abordagem original)

  2. Criar um certificado p8 que pode ser usado para de autenticação baseada em token (a abordagem mais recente e recomendada)

A abordagem mais recente tem uma série de benefícios, conforme documentado na autenticação http/2 (baseada em token) para APNS. Menos etapas são necessárias, mas também são obrigatórias para cenários específicos. No entanto, foram fornecidas etapas para ambas as abordagens, pois ambas funcionarão para fins deste tutorial.

OPÇÃO 1: Criando um certificado push p12 que pode ser carregado diretamente no Hub de Notificação
  1. Em seu Mac, execute a ferramenta acesso de conjunto de chaves. Ele pode ser aberto na pasta utilitários ou na pasta Outros no Launchpad.

  2. Selecione de Acesso de Conjunto de Chaves, expanda do Assistente de Certificado e selecione Solicitar um Certificado de uma Autoridade de Certificação.

    usar o Acesso ao Conjunto de Chaves para solicitar um novo certificado

    Nota

    Por padrão, o Keychain Access seleciona o primeiro item na lista. Isso pode ser um problema se você estiver na categoria Certificados e Apple Worldwide Developer Relations Certification Authority não for o primeiro item da lista. Verifique se você tem um item não chave ou se a chave Apple Worldwide Developer Relations Certification Authority chave está selecionada, antes de gerar a CSR (Solicitação de Assinatura de Certificado).

  3. Selecione o Endereço de Email do Usuário, insira o valor de Nome Comum , especifique Salvo em discoe selecione Continuar. Deixe endereço de email da AC em branco, pois ele não é necessário.

    informações de certificado esperadas

  4. Insira um nome para o arquivo CSR (solicitação de assinatura de certificado) em Salvar como, selecione o local em Ondee selecione Salvar.

    Escolha um nome de arquivo para o de certificado

    Essa ação salva o arquivo CSR no local selecionado. O local padrão é Desktop. Lembre-se do local escolhido para o arquivo.

  5. De volta à página Certificados, Identificadores & Perfis no portal de provisionamento do iOS, role para baixo até a opção de Notificações por Push marcada e selecione Configurar para criar o certificado.

    editar da ID do aplicativo

  6. A janela de certificados TLS/SSL do serviço de notificação por push da Apple é exibida. Selecione o botão Criar Certificado na seção do Certificado TLS/SSL de Desenvolvimento .

    botão Criar certificado para ID do aplicativo

    A tela Criar um novo Certificado é exibida.

    Nota

    Este tutorial usa um certificado de desenvolvimento. O mesmo processo é usado ao registrar um certificado de produção. Apenas certifique-se de usar o mesmo tipo de certificado ao enviar notificações.

  7. Selecione Escolherde Arquivo, navegue até o local em que você salvou o arquivo CSR e clique duas vezes no nome do certificado para carregá-lo. Em seguida, selecione Continuar.

  8. Depois que o portal criar o certificado, selecione o botão Baixar. Salve o certificado e lembre-se do local no qual ele foi salvo.

    página de download de certificado gerado

    O certificado é baixado e salvo em seu computador na pasta Downloads.

    Localizar arquivo de certificado na pasta Downloads

    Nota

    Por padrão, o certificado de desenvolvimento baixado é nomeado aps_development.cer.

  9. Clique duas vezes no certificado por push baixado aps_development.cer. Essa ação instala o novo certificado no conjunto de chaves, conforme mostrado na imagem a seguir:

    lista de certificados de acesso de conjunto de chaves mostrando o novo certificado

    Nota

    Embora o nome em seu certificado possa ser diferente, o nome será prefixado com o Apple Development iOS Push Services e terá o identificador de pacote apropriado associado a ele.

  10. No Acesso ao Conjunto de Chaves, ControleClique no novo certificado push que você criou na categoria certificados . Selecione Exportar, nomeie o arquivo, selecione o formato p12 e selecione Salvar.

    Exportar certificado como de formato p12

    Você pode optar por proteger o certificado com uma senha, mas uma senha é opcional. Clique em OK se quiser ignorar a criação de senha. Anote o nome do arquivo e o local do certificado p12 exportado. Eles são usados para habilitar a autenticação com APNs.

    Nota

    O nome e o local do arquivo p12 podem ser diferentes do que é retratado neste tutorial.

OPÇÃO 2: Criando um certificado p8 que pode ser usado para autenticação baseada em token
  1. Anote os seguintes detalhes:

    • de prefixo da ID do aplicativo (ID da equipe)
    • ID do pacote
  2. De volta em Certificados, Identificadores & Perfis, clique emChaves.

    Nota

    Se você já tiver uma chave configurada para APNS, poderá reutilize o certificado p8 baixado logo após a criação dele. Nesse caso, você pode ignorar as etapas 3 até 5.

  3. Clique no botão + (ou no botão Criar uma chave) para criar uma nova chave.

  4. Forneça um valor de de nome de chave adequado e, em seguida, verifique a opção apns (serviço de notificações por push) da Apple e clique em Continuar, seguido por Registrar na próxima tela.

  5. Clique em Baixar e, em seguida, mova o arquivo p8 (prefixado com AuthKey_) para um diretório local seguro e clique em Concluído.

    Nota

    Mantenha o arquivo p8 em um local seguro (e salve um backup). Depois de baixar a chave, ela não pode ser baixada novamente, pois a cópia do servidor é removida.

  6. Em Chaves, clique na chave que você criou (ou em uma chave existente, se tiver optado por usá-la).

  7. Anote o valor da ID da Chave .

  8. Abra o certificado p8 em um aplicativo adequado de sua escolha, como do Visual Studio Code. Anote o valor da chave (entre -----BEGIN PRIVATE KEY----- e -----END PRIVATE KEY-----).

    CHAVE PRIVADA -----BEGIN-----
    <key_value>
    -----END PRIVATE KEY-----

    Nota

    Esse é o de valor do token que será usado posteriormente para configurardo Hub de Notificação .

Ao final dessas etapas, você deve ter as seguintes informações para uso posteriormente no Configurar seu hub de notificação com informações de APNS:

  • ID da equipe (consulte a etapa 1)
  • de ID do Pacote (consulte a etapa 1)
  • de ID da chave (consulte a etapa 7)
  • de valor de token (valor de chave p8 obtido na etapa 8)

Criar um perfil de provisionamento para o aplicativo

  1. Retorne ao do Portal de Provisionamento do iOS, selecione Certificados, Identificadores & Perfis, selecione Perfis no menu à esquerda e selecione + para criar um novo perfil. A tela Registrar um Novo Perfil de Provisionamento é exibida.

  2. Selecione de Desenvolvimento de Aplicativos do iOS em de Desenvolvimento como o tipo de perfil de provisionamento e selecione Continuar.

    lista de perfis de provisionamento

  3. Em seguida, selecione a ID do aplicativo que você criou na lista suspensa ID do Aplicativo e selecione Continuar.

    selecione a ID do aplicativo

  4. Na janela Selecionar certificados, selecione o certificado de desenvolvimento que você usa para assinatura de código e selecione Continuar.

    Nota

    Esse certificado não é o certificado push que você criou na etapa anterior. Esse é o certificado de desenvolvimento. Se não existir, você deverá criá-lo, pois esse é um de pré-requisitos para este tutorial. Os certificados de desenvolvedor podem ser criados nodo Portal do Desenvolvedor da Apple, por meio de Xcode ou em do Visual Studio.

  5. Retorne à página Certificados , Identificadores & Perfis, selecione Perfis no menu esquerdo e selecione para criar um novo perfil. A tela Registrar um Novo Perfil de Provisionamento é exibida.

  6. Na janela Selecionar certificados, selecione o certificado de desenvolvimento que você criou. Em seguida, selecione Continuar.

  7. Em seguida, selecione os dispositivos a serem usados para teste e selecione Continuar.

  8. Por fim, escolha um nome para o perfil nonome do perfil de provisionamento e selecione Gerar.

    Escolha um nome de perfil de provisionamento

  9. Quando o novo perfil de provisionamento for criado, selecione Baixar. Lembre-se do local no qual ele foi salvo.

  10. Navegue até o local do perfil de provisionamento e clique duas vezes nele para instalá-lo no computador de desenvolvimento.

Criar um Hub de Notificação

Nesta seção, você criará um hub de notificação e configurará a autenticação com APNS. Você pode usar um certificado push p12 ou autenticação baseada em token. Se você quiser usar um hub de notificação que já criou, poderá pular para a etapa 5.

  1. Entre no do Azure.

  2. Clique em Criar um recurso, pesquise e escolha do Hub de Notificação e clique em Criar.

  3. Atualize os campos a seguir e clique em Criar:

    DETALHES BÁSICOS

    Assinatura : Escolher o de Assinatura de de destino na lista suspensa
    Grupo de Recursos: Criar um novo grupo de recursos (ou escolher um existente)

    DETALHES DO NAMESPACE

    Namespace do Hub de Notificação : Insira um nome globalmente exclusivo para o namespace do Hub de Notificação

    Nota

    Verifique se a opção Criar nova está selecionada para este campo.

    DETALHES DO HUB DE NOTIFICAÇÃO

    Hub de Notificação : Insira um nome para o Hub de Notificação
    Local: Escolher um local adequado na lista suspensa
    tipo de preço : manter a opção de gratuita de padrão

    Nota

    A menos que você tenha atingido o número máximo de hubs na camada gratuita.

  4. Depois que o do Hub de Notificação tiver sido provisionado, navegue até esse recurso.

  5. Navegue até o novodo Hub de Notificação do .

  6. Selecione de Políticas de Acesso na lista (em GERENCIAR).

  7. Anote os valores nome da política juntamente com seus valores de de cadeia de conexão correspondentes.

Configurar o Hub de Notificação com informações de APNS

Em de Serviços de Notificação, selecione Apple siga as etapas apropriadas com base na abordagem que você escolheu anteriormente na seção Criando um Certificado para Hubs de Notificação.

Nota

Use o de Produção para Modo de Aplicativo somente se você quiser enviar notificações por push para os usuários que compraram seu aplicativo da loja.

OPÇÃO 1: Usando um certificado push .p12

  1. Selecione de Certificado.

  2. Selecione o ícone de arquivo.

  3. Selecione o arquivo .p12 exportado anteriormente e selecione Abrir.

  4. Se necessário, especifique a senha correta.

  5. Selecione modo de de área restrita.

  6. Selecione Salvar.

OPÇÃO 2: Usando a autenticação baseada em token

  1. Selecione Token.

  2. Insira os seguintes valores adquiridos anteriormente:

    • de ID da Chave
    • ID do pacote
    • ID da equipe
    • de Token
  3. Escolha de área restrita.

  4. Selecione Salvar.

Configurar seu hub de notificação com informações de FCM

  1. Selecione do Google (GCM/FCM) na seção Configurações do no menu à esquerda.
  2. Insira a chave do servidor anotada no console do Google Firebase.
  3. Selecione Salvar na barra de ferramentas.

Criar um aplicativo de back-end da API Web do ASP.NET Core

Nesta seção, você criará a API Web do ASP.NET Core back-end para lidar com de registro de dispositivo e o envio de notificações para o aplicativo móvel Xamarin.Forms.

Criar um projeto Web

  1. Em do Visual Studio, selecione Arquivo>Nova Solução.

  2. Selecione aplicativo de>do .NET Core>ASP.NET Core>>Próxima.

  3. Na caixa de diálogo Configurar sua nova API Web do ASP.NET Core, selecione do Target Framework de .NET Core 3.1.

  4. Insira PushDemoApi para o de Nome do Projeto e selecione Criar.

  5. Inicie a depuração (Command + Enter) para testar o aplicativo modelo.

    Nota

    O aplicativo modelo está configurado para usar o WeatherForecastController como olaunchUrl . Isso é definido em propriedades >launchSettings.json.

    Se você for solicitado com um certificado de desenvolvimento inválido encontrado mensagem:

    1. Clique em Sim concordar em executar a ferramenta 'dotnet dev-certs https' para corrigir isso. A ferramenta 'dotnet dev-certs https' solicita que você insira uma senha para o certificado e a senha do conjunto de chaves.

    2. Clique em Sim quando solicitado a Instalar e confiar no novo certificadoe, em seguida, insira a senha do conjunto de chaves.

  6. Expanda a pasta controladores de e exclua WeatherForecastController.cs.

  7. Excluir WeatherForecast.cs.

  8. Configurar valores de configuração local usando a ferramenta Secret Manager. A desassociação dos segredos da solução garante que eles não acabem no controle do código-fonte. Abra Terminal vá para o diretório do arquivo de projeto e 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 espaço reservado por seu próprio nome de hub de notificação e valores de cadeia de conexão. Você fez uma anotação deles na seção criar um hub de notificação. Caso contrário, você poderá pesquisá-los no do Azure.

    NotificationHub:Name:
    Consulte Name no resumo do Essentials na parte superior dovisão geral do .

    NotificationHub:ConnectionString:
    Consulte DefaultFullSharedAccessSignature nas políticas de acesso

    Nota

    Para cenários de produção, você pode examinar opções como do Azure KeyVault para armazenar com segurança a cadeia de conexão. Para simplificar, os segredos serão adicionados às configurações do aplicativo Serviço de Aplicativo do Azure.

Autenticar clientes usando uma chave de API (opcional)

As chaves de API não são tão seguras quanto tokens, mas serão suficientes para os fins deste tutorial. Uma chave de API pode ser configurada facilmente por meio dodo middleware ASP.NET.

  1. Adicione a chave de API aos valores de configuração local.

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

    Nota

    Você deve substituir o valor do espaço reservado pelo seu próprio e anotar isso.

  2. ControleClique no projeto PushDemoApi, escolha Novo de Pasta no menu Adicionar e clique em Adicionar usando de Autenticação como onome da pasta .

  3. ControleClique na pasta de Autenticação e escolha Novo Arquivo... no menu Adicionar .

  4. Selecione de Classe Vazia doGeral, insira ApiKeyAuthOptions.cs para ode Nome do e clique em Nova adicionando a implementação a seguir.

    using Microsoft.AspNetCore.Authentication;
    
    namespace PushDemoApi.Authentication
    {
        public class ApiKeyAuthOptions : AuthenticationSchemeOptions
        {
            public const string DefaultScheme = "ApiKey";
            public string Scheme => DefaultScheme;
            public string ApiKey { get; set; }
        }
    }
    
  5. Adicione outro de Classe Vazia à pasta de Autenticação chamada ApiKeyAuthHandler.cse adicione a implementação a seguir.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Claims;
    using System.Text.Encodings.Web;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Options;
    
    namespace PushDemoApi.Authentication
    {
        public class ApiKeyAuthHandler : AuthenticationHandler<ApiKeyAuthOptions>
        {
            const string ApiKeyIdentifier = "apikey";
    
            public ApiKeyAuthHandler(
                IOptionsMonitor<ApiKeyAuthOptions> options,
                ILoggerFactory logger,
                UrlEncoder encoder,
                ISystemClock clock)
                : base(options, logger, encoder, clock) {}
    
            protected override Task<AuthenticateResult> HandleAuthenticateAsync()
            {
                string key = string.Empty;
    
                if (Request.Headers[ApiKeyIdentifier].Any())
                {
                    key = Request.Headers[ApiKeyIdentifier].FirstOrDefault();
                }
                else if (Request.Query.ContainsKey(ApiKeyIdentifier))
                {
                    if (Request.Query.TryGetValue(ApiKeyIdentifier, out var queryKey))
                        key = queryKey;
                }
    
                if (string.IsNullOrWhiteSpace(key))
                    return Task.FromResult(AuthenticateResult.Fail("No api key provided"));
    
                if (!string.Equals(key, Options.ApiKey, StringComparison.Ordinal))
                    return Task.FromResult(AuthenticateResult.Fail("Invalid api key."));
    
                var identities = new List<ClaimsIdentity> {
                    new ClaimsIdentity("ApiKeyIdentity")
                };
    
                var ticket = new AuthenticationTicket(
                    new ClaimsPrincipal(identities), Options.Scheme);
    
                return Task.FromResult(AuthenticateResult.Success(ticket));
            }
        }
    }
    

    Nota

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

  6. Adicione outro de Classe Vazia à pasta de Autenticação chamada ApiKeyAuthenticationBuilderExtensions.cse adicione a implementação a seguir.

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

    Nota

    Esse método de extensão simplifica o código de configuração do middleware em Startup.cs tornando-o mais legível e geralmente mais fácil de seguir.

  7. Em Startup.cs, atualize o método ConfigureServices para configurar a autenticação da Chave de API abaixo da chamada para os serviços de . Método AddControllers.

    using PushDemoApi.Authentication;
    using PushDemoApi.Models;
    using PushDemoApi.Services;
    
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
    
        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = ApiKeyAuthOptions.DefaultScheme;
            options.DefaultChallengeScheme = ApiKeyAuthOptions.DefaultScheme;
        }).AddApiKeyAuth(Configuration.GetSection("Authentication").Bind);
    }
    
  8. Ainda em Startup.cs, atualize o método Configure para chamar os métodos de extensão UseAuthentication e UseAuthorization no do aplicativoIApplicationBuilder. Verifique se esses métodos são chamados após userouting e antes de aplicativo. UseEndpoints.

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
    
        app.UseHttpsRedirection();
    
        app.UseRouting();
    
        app.UseAuthentication();
    
        app.UseAuthorization();
    
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
    

    Nota

    Chamar UseAuthentication registra o middleware que usa os esquemas de autenticação registrados anteriormente (de ConfigureServices). Isso deve ser chamado antes de qualquer middleware que dependa da autenticação dos usuários.

Adicionar dependências e configurar serviços

ASP.NET Core dá suporte à DI (injeção de dependência) padrão de design de software, que é uma técnica para alcançar de inversão de controle (IoC) entre classes e suas dependências.

O uso do hub de notificação e do SDK dos Hubs de Notificação para operações de back-end é encapsulado em um serviço. O serviço é registrado e disponibilizado por meio de uma abstração adequada.

  1. ControleClique em na pasta dependências do e escolha Gerenciar Pacotes NuGet....

  2. Pesquise Microsoft.Azure.NotificationHubs e verifique se ele está marcado.

  3. Clique em Adicionar Pacotese, em seguida, clique em Aceitar quando solicitado a aceitar os termos de licença.

  4. ControleClique no projeto PushDemoApi, escolha novo de pasta no menu Adicionar e clique em Adicionar usando modelos de como onome da pasta .

  5. ControleClique na pasta modelos de e escolha Novo Arquivo... no menu Adicionar .

  6. Selecione de Classe VaziaGeral, insira PushTemplates.cs para ode Nome do e clique em Nova adicionando a implementação a seguir.

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

    Nota

    Essa classe contém as cargas de notificação tokenizadas para as notificações genéricas e silenciosas exigidas por esse cenário. Os conteúdos são definidos fora do Instalação para permitir a experimentação sem precisar atualizar as instalações existentes por meio do serviço. O tratamento de alterações nas instalações dessa maneira está fora do escopo deste tutorial. Para produção, considere modelos personalizados.

  7. Adicione outra de Classe Vazia à pasta modelos chamada DeviceInstallation.cse adicione a implementação a seguir.

    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    
    namespace PushDemoApi.Models
    {
        public class DeviceInstallation
        {
            [Required]
            public string InstallationId { get; set; }
    
            [Required]
            public string Platform { get; set; }
    
            [Required]
            public string PushChannel { get; set; }
    
            public IList<string> Tags { get; set; } = Array.Empty<string>();
        }
    }
    
  8. Adicione outra de Classe Vazia à pasta modelos de chamada NotificationRequest.cse adicione a implementação a seguir.

    using System;
    
    namespace PushDemoApi.Models
    {
        public class NotificationRequest
        {
            public string Text { get; set; }
            public string Action { get; set; }
            public string[] Tags { get; set; } = Array.Empty<string>();
            public bool Silent { get; set; }
        }
    }
    
  9. Adicione outro de Classe Vazia à pasta modelos chamada NotificationHubOptions.cse adicione a implementação a seguir.

    using System.ComponentModel.DataAnnotations;
    
    namespace PushDemoApi.Models
    {
        public class NotificationHubOptions
        {
            [Required]
            public string Name { get; set; }
    
            [Required]
            public string ConnectionString { get; set; }
        }
    }
    
  10. Adicione uma nova pasta ao projeto de PushDemoApi chamado Services.

  11. Adicione um de Interface Vazia à pasta Services chamada INotificationService.cse adicione a implementação a seguir.

    using System.Threading;
    using System.Threading.Tasks;
    using PushDemoApi.Models;
    
    namespace PushDemoApi.Services
    {
        public interface INotificationService
        {
            Task<bool> CreateOrUpdateInstallationAsync(DeviceInstallation deviceInstallation, CancellationToken token);
            Task<bool> DeleteInstallationByIdAsync(string installationId, CancellationToken token);
            Task<bool> RequestNotificationAsync(NotificationRequest notificationRequest, CancellationToken token);
        }
    }
    
  12. Adicione um de Classe Vazia à pasta serviços chamado NotificationHubsService.cse adicione o seguinte código para implementar a interface INotificationService :

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.Azure.NotificationHubs;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Options;
    using PushDemoApi.Models;
    
    namespace PushDemoApi.Services
    {
        public class NotificationHubService : INotificationService
        {
            readonly NotificationHubClient _hub;
            readonly Dictionary<string, NotificationPlatform> _installationPlatform;
            readonly ILogger<NotificationHubService> _logger;
    
            public NotificationHubService(IOptions<NotificationHubOptions> options, ILogger<NotificationHubService> logger)
            {
                _logger = logger;
                _hub = NotificationHubClient.CreateClientFromConnectionString(
                    options.Value.ConnectionString,
                    options.Value.Name);
    
                _installationPlatform = new Dictionary<string, NotificationPlatform>
                {
                    { nameof(NotificationPlatform.Apns).ToLower(), NotificationPlatform.Apns },
                    { nameof(NotificationPlatform.Fcm).ToLower(), NotificationPlatform.Fcm }
                };
            }
    
            public async Task<bool> CreateOrUpdateInstallationAsync(DeviceInstallation deviceInstallation, CancellationToken token)
            {
                if (string.IsNullOrWhiteSpace(deviceInstallation?.InstallationId) ||
                    string.IsNullOrWhiteSpace(deviceInstallation?.Platform) ||
                    string.IsNullOrWhiteSpace(deviceInstallation?.PushChannel))
                    return false;
    
                var installation = new Installation()
                {
                    InstallationId = deviceInstallation.InstallationId,
                    PushChannel = deviceInstallation.PushChannel,
                    Tags = deviceInstallation.Tags
                };
    
                if (_installationPlatform.TryGetValue(deviceInstallation.Platform, out var platform))
                    installation.Platform = platform;
                else
                    return false;
    
                try
                {
                    await _hub.CreateOrUpdateInstallationAsync(installation, token);
                }
                catch
                {
                    return false;
                }
    
                return true;
            }
    
            public async Task<bool> DeleteInstallationByIdAsync(string installationId, CancellationToken token)
            {
                if (string.IsNullOrWhiteSpace(installationId))
                    return false;
    
                try
                {
                    await _hub.DeleteInstallationAsync(installationId, token);
                }
                catch
                {
                    return false;
                }
    
                return true;
            }
    
            public async Task<bool> RequestNotificationAsync(NotificationRequest notificationRequest, CancellationToken token)
            {
                if ((notificationRequest.Silent &&
                    string.IsNullOrWhiteSpace(notificationRequest?.Action)) ||
                    (!notificationRequest.Silent &&
                    (string.IsNullOrWhiteSpace(notificationRequest?.Text)) ||
                    string.IsNullOrWhiteSpace(notificationRequest?.Action)))
                    return false;
    
                var androidPushTemplate = notificationRequest.Silent ?
                    PushTemplates.Silent.Android :
                    PushTemplates.Generic.Android;
    
                var iOSPushTemplate = notificationRequest.Silent ?
                    PushTemplates.Silent.iOS :
                    PushTemplates.Generic.iOS;
    
                var androidPayload = PrepareNotificationPayload(
                    androidPushTemplate,
                    notificationRequest.Text,
                    notificationRequest.Action);
    
                var iOSPayload = PrepareNotificationPayload(
                    iOSPushTemplate,
                    notificationRequest.Text,
                    notificationRequest.Action);
    
                try
                {
                    if (notificationRequest.Tags.Length == 0)
                    {
                        // This will broadcast to all users registered in the notification hub
                        await SendPlatformNotificationsAsync(androidPayload, iOSPayload, token);
                    }
                    else if (notificationRequest.Tags.Length <= 20)
                    {
                        await SendPlatformNotificationsAsync(androidPayload, iOSPayload, notificationRequest.Tags, token);
                    }
                    else
                    {
                        var notificationTasks = notificationRequest.Tags
                            .Select((value, index) => (value, index))
                            .GroupBy(g => g.index / 20, i => i.value)
                            .Select(tags => SendPlatformNotificationsAsync(androidPayload, iOSPayload, tags, token));
    
                        await Task.WhenAll(notificationTasks);
                    }
    
                    return true;
                }
                catch (Exception e)
                {
                    _logger.LogError(e, "Unexpected error sending notification");
                    return false;
                }
            }
    
            string PrepareNotificationPayload(string template, string text, string action) => template
                .Replace("$(alertMessage)", text, StringComparison.InvariantCulture)
                .Replace("$(alertAction)", action, StringComparison.InvariantCulture);
    
            Task SendPlatformNotificationsAsync(string androidPayload, string iOSPayload, CancellationToken token)
            {
                var sendTasks = new Task[]
                {
                    _hub.SendFcmNativeNotificationAsync(androidPayload, token),
                    _hub.SendAppleNativeNotificationAsync(iOSPayload, token)
                };
    
                return Task.WhenAll(sendTasks);
            }
    
            Task SendPlatformNotificationsAsync(string androidPayload, string iOSPayload, IEnumerable<string> tags, CancellationToken token)
            {
                var sendTasks = new Task[]
                {
                    _hub.SendFcmNativeNotificationAsync(androidPayload, tags, token),
                    _hub.SendAppleNativeNotificationAsync(iOSPayload, tags, token)
                };
    
                return Task.WhenAll(sendTasks);
            }
        }
    }
    

    Nota

    A expressão de marca fornecida para SendTemplateNotificationAsync é limitada a 20 marcas. Ela é limitada a 6 para a maioria dos operadores, mas a expressão contém apenas ORs (||) nesse caso. Se houver mais de 20 marcas na solicitação, elas deverão ser divididas em várias solicitações. Consulte a documentação expressões de roteamento e marca para obter mais detalhes.

  13. Em Startup.cs, atualize o método ConfigureServices para adicionar o NotificationHubsService como uma implementação singleton de INotificationService.

    
    using PushDemoApi.Models;
    using PushDemoApi.Services;
    
    public void ConfigureServices(IServiceCollection services)
    {
        ...
    
        services.AddSingleton<INotificationService, NotificationHubService>();
    
        services.AddOptions<NotificationHubOptions>()
            .Configure(Configuration.GetSection("NotificationHub").Bind)
            .ValidateDataAnnotations();
    }
    

Criar a API de notificações

  1. ControleClique em na pasta controladores de e escolha Novo Arquivo... no menu Adicionar .

  2. Selecione ASP.NETde Classe do Controlador de API Web do Core, insira NotificationsController para o nome e clique em Nova.

    Nota

    Se você estiver acompanhando do Visual Studio 2019, escolha o controlador de API com ações de leitura/gravação modelo.

  3. Adicione os namespaces a seguir à parte superior do arquivo.

    using System.ComponentModel.DataAnnotations;
    using System.Net;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using PushDemoApi.Models;
    using PushDemoApi.Services;
    
  4. Atualize o controlador modelo para que ele deriva de ControllerBase e seja decorado com o atributo ApiController.

    [ApiController]
    [Route("api/[controller]")]
    public class NotificationsController : ControllerBase
    {
        // Templated methods here
    }
    

    Nota

    A classe base Controller fornece suporte para exibições, mas isso não é necessário nesse caso e, portanto, ControllerBase podem ser usados. Se você estiver acompanhando do Visual Studio 2019, ignore esta etapa.

  5. Se você optar por concluir os clientes do Authenticate usando uma seção de chave de API, decore o NotificationsController com o atributo de Autorização também.

    [Authorize]
    
  6. Atualize o construtor para aceitar a instância registrada de INotificationService como um argumento e atribuí-lo a um membro somente leitura.

    readonly INotificationService _notificationService;
    
    public NotificationsController(INotificationService notificationService)
    {
        _notificationService = notificationService;
    }
    
  7. Em launchSettings.json (dentro da pasta propriedades do ), altere o launchUrl de para de api/notificações para corresponder à URL especificada no atributo RegistrationsControllerRoute.

  8. Inicie a depuração (CommandEnter) para validar se o aplicativo está trabalhando com o novo notificationsController e retorna um status de 401 não autorizado.

    Nota

    O Visual Studio pode não iniciar automaticamente o aplicativo no navegador. Você usará postman para testar a API deste ponto em diante.

  9. Em uma nova guia do Postman , defina a solicitação para get. Insira o endereço abaixo substituindo o espaço reservado applicationUrl pelo applicationUrl de https encontrado emlaunchSettings.jsonpropriedades do .

    <applicationUrl>/api/notifications
    

    Nota

    O applicationUrl deve ser '' para o perfil padrão. Se você estiver usando do IIS (padrão no do Visual Studio 2019 no Windows), deverá usar o applicationUrl especificado no item iisSettings. Você receberá uma resposta 404 se o endereço estiver incorreto.

  10. Se você optou por concluir os clientes Authenticate usando uma seção de chave de API, configure os cabeçalhos de solicitação para incluir seu valor de apikey .

    Chave Valor
    apikey <your_api_key>
  11. Clique no botão Enviar.

    Nota

    Você deve receber um status de 200 OK com algum conteúdo de JSON .

    Se você receber um aviso de verificação de certificado SSL , poderá alternar a verificação de certificado SSL de solicitação postman configuração noconfigurações do .

  12. Substitua os métodos de classe modelo em NotificationsController.cs pelo código a seguir.

    [HttpPut]
    [Route("installations")]
    [ProducesResponseType((int)HttpStatusCode.OK)]
    [ProducesResponseType((int)HttpStatusCode.BadRequest)]
    [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)]
    public async Task<IActionResult> UpdateInstallation(
        [Required]DeviceInstallation deviceInstallation)
    {
        var success = await _notificationService
            .CreateOrUpdateInstallationAsync(deviceInstallation, HttpContext.RequestAborted);
    
        if (!success)
            return new UnprocessableEntityResult();
    
        return new OkResult();
    }
    
    [HttpDelete()]
    [Route("installations/{installationId}")]
    [ProducesResponseType((int)HttpStatusCode.OK)]
    [ProducesResponseType((int)HttpStatusCode.BadRequest)]
    [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)]
    public async Task<ActionResult> DeleteInstallation(
        [Required][FromRoute]string installationId)
    {
        var success = await _notificationService
            .DeleteInstallationByIdAsync(installationId, CancellationToken.None);
    
        if (!success)
            return new UnprocessableEntityResult();
    
        return new OkResult();
    }
    
    [HttpPost]
    [Route("requests")]
    [ProducesResponseType((int)HttpStatusCode.OK)]
    [ProducesResponseType((int)HttpStatusCode.BadRequest)]
    [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)]
    public async Task<IActionResult> RequestPush(
        [Required]NotificationRequest notificationRequest)
    {
        if ((notificationRequest.Silent &&
            string.IsNullOrWhiteSpace(notificationRequest?.Action)) ||
            (!notificationRequest.Silent &&
            string.IsNullOrWhiteSpace(notificationRequest?.Text)))
            return new BadRequestResult();
    
        var success = await _notificationService
            .RequestNotificationAsync(notificationRequest, HttpContext.RequestAborted);
    
        if (!success)
            return new UnprocessableEntityResult();
    
        return new OkResult();
    }
    

Criar o aplicativo de API

Agora você cria um aplicativo de API no do Serviço de Aplicativo do Azure para hospedar o serviço de back-end.

  1. Entre no portal do do Azure.

  2. Clique em Criar um recurso, pesquise e escolha de Aplicativo de API e clique em Criar.

  3. Atualize os campos a seguir e clique em Criar.

    Nome do aplicativo:
    Insira um nome global exclusivo para o aplicativo de API

    Assinatura :
    Escolha o mesmo destino Assinatura você criou o hub de notificação.

    grupo de recursos :
    Escolha o mesmo Grupo de Recursos você criou o hub de notificação.

    Plano/Local do Serviço de Aplicativo:
    Criar um novo plano do Serviço de Aplicativo

    Nota

    Altere da opção padrão para um plano que inclua suporte ao SSL. Caso contrário, você precisará tomar as etapas apropriadas ao trabalhar com o aplicativo móvel para impedir que solicitações http sejam bloqueadas.

    Application Insights:
    Mantenha a opção sugerida (um novo recurso será criado usando esse nome) ou escolha um recurso existente.

  4. Depois que o aplicativo de API tiver sido provisionado, navegue até esse recurso.

  5. Anote a propriedade de URL no resumo do Essentials na parte superior dovisão geral do . Essa URL é o de ponto de extremidade de back-end que será usado posteriormente neste tutorial.

    Nota

    A URL usa o nome do aplicativo de API especificado anteriormente, com o formato https://<app_name>.azurewebsites.net.

  6. Selecione de Configuração na lista (emde Configurações de ).

  7. Para cada uma das configurações abaixo, clique em Nova configuração de aplicativo para inserir o nome e umde valor de e, em seguida, clique em OK.

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

    Nota

    Essas são as mesmas configurações que você definiu anteriormente nas configurações do usuário. Você deve ser capaz de copiá-los. A configuração Authentication:ApiKey será necessária somente se você optar por concluir os clientes Authenticate usando uma seção de chave de API. Para cenários de produção, você pode examinar opções como do Azure KeyVault. Elas foram adicionadas como configurações de aplicativo para simplificar nesse caso.

  8. Depois que todas as configurações do aplicativo tiverem sido adicionadas, clique em Salvare, em seguida, Continuar.

Publicar o serviço de back-end

Em seguida, você implanta o aplicativo no Aplicativo de API para torná-lo acessível de todos os dispositivos.

Nota

As etapas a seguir são específicas para Visual Studio para Mac. Se você estiver acompanhando do Visual Studio 2019 no Windows, o fluxo de publicação será diferente. Consulte Publicar no Serviço de Aplicativo do Azure no Windows.

  1. Altere sua configuração de de depuração para de versão, caso ainda não tenha feito isso.

  2. ControleClique o projeto PushDemoApi e escolha Publicar no Azure... no menu Publicar do .

  3. Siga o fluxo de autenticação se solicitado a fazê-lo. Use a conta usada no anterior para criar a seção do Aplicativo de API.

  4. Selecione o Aplicativo de API do Serviço de Aplicativo do Azure você criou anteriormente na lista como destino de publicação e clique em Publicar.

Depois de concluir o assistente, ele publicará o aplicativo no Azure e abrirá o aplicativo. Anote a URL se você ainda não fez isso. Essa URL é o de ponto de extremidade de back-end usado posteriormente neste tutorial.

Validando a API publicada

  1. Em Postman abrir uma nova guia, defina a solicitação para PUT e insira o endereço abaixo. Substitua o espaço reservado pelo endereço base do qual você anotou no anterior, publique o serviço de back-end seção.

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

    Nota

    O endereço base deve estar no formato https://<app_name>.azurewebsites.net/

  2. Se você optou por concluir os clientes Authenticate usando uma seção de chave de API, configure os cabeçalhos de solicitação para incluir seu valor de apikey .

    Chave Valor
    apikey <your_api_key>
  3. Escolha a opção bruta para ocorpo do , escolha JSON na lista de opções de formato e, em seguida, inclua algum espaço reservado conteúdo de JSON:

    {}
    
  4. Clique em Enviar.

    Nota

    Você deve receber um status 422 UnprocessableEntity do serviço.

  5. Execute as etapas 1 a 4 novamente, mas desta vez especificando o ponto de extremidade de solicitações para validar se você recebe uma resposta 400 solicitações inválidas.

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

Nota

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 móvel cliente.

Criar um aplicativo Xamarin.Forms multiplataforma

Nesta seção, você criará um aplicativo Xamarin.Forms móvel implementando notificações por push de maneira multiplataforma.

Ele permite que você registre e desregistre de um hub de notificação por meio do serviço de back-end que você criou.

Um alerta é exibido quando uma ação é especificada e o aplicativo está em primeiro plano. Caso contrário, as notificações aparecerão no centro de notificação.

Nota

Normalmente, você executaria as ações de registro (e desregistração) durante o ponto apropriado no ciclo de vida do aplicativo (ou como parte de sua experiência de primeira execução, talvez) sem entradas explícitas de registro/desregistro de usuário. No entanto, este exemplo exigirá uma entrada explícita do usuário para permitir que essa funcionalidade seja explorada e testada com mais facilidade.

Criar a solução Xamarin.Forms

  1. Em do Visual Studio, crie uma nova solução de Xamarin.Forms usando do aplicativo Formulários Em Branco como o modelo e inserindo PushDemo para onome do projeto .

    Nota

    Na caixa de diálogo Configurar o Aplicativo em Formulários Em Branco, verifique se o identificador da organização corresponde ao valor usado anteriormente e se destinos do Android e iOS estão verificados.

  2. ControleClique na solução PushDemo e escolha Atualizar Pacotes NuGet.

  3. ControleClique em na solução PushDemo e escolha Gerenciar Pacotes NuGet...

  4. Procure Newtonsoft.Json e verifique se está marcada.

  5. Clique em Adicionar Pacotese, em seguida, clique em Aceitar quando solicitado a aceitar os termos de licença.

  6. Crie e execute o aplicativo em cada plataforma de destino (Command + Enter) para testar as execuções do aplicativo modelo em seus dispositivos.

Implementar os componentes multiplataforma

  1. ControleClique no projeto PushDemo, escolha Nova Pasta no menu Adicionar e clique em Adicionar usando modelos como o nome da pasta .

  2. ControleClique na pasta modelos de e escolha Novo Arquivo... no menu Adicionar .

  3. Selecione Geral>de Classe Vazia, insira DeviceInstallation.cse adicione a implementação a seguir.

    using System.Collections.Generic;
    using Newtonsoft.Json;
    
    namespace PushDemo.Models
    {
        public class DeviceInstallation
        {
            [JsonProperty("installationId")]
            public string InstallationId { get; set; }
    
            [JsonProperty("platform")]
            public string Platform { get; set; }
    
            [JsonProperty("pushChannel")]
            public string PushChannel { get; set; }
    
            [JsonProperty("tags")]
            public List<string> Tags { get; set; } = new List<string>();
        }
    }
    
  4. Adicione uma de Enumeração Vazia à pasta modelos de chamada PushDemoAction.cs com a implementação a seguir.

    namespace PushDemo.Models
    {
        public enum PushDemoAction
        {
            ActionA,
            ActionB
        }
    }
    
  5. Adicione uma nova pasta ao projeto PushDemo chamado Services, em seguida, adicione um de Classe Vazia à pasta chamada ServiceContainer.cs com a implementação a seguir.

    using System;
    using System.Collections.Generic;
    
    namespace PushDemo.Services
    {
       public static class ServiceContainer
       {
           static readonly Dictionary<Type, Lazy<object>> services
               = new Dictionary<Type, Lazy<object>>();
    
           public static void Register<T>(Func<T> function)
               => services[typeof(T)] = new Lazy<object>(() => function());
    
           public static T Resolve<T>()
               => (T)Resolve(typeof(T));
    
           public static object Resolve(Type type)
           {
               {
                   if (services.TryGetValue(type, out var service))
                       return service.Value;
    
                   throw new KeyNotFoundException($"Service not found for type '{type}'");
               }
           }
       }
    }
    

    Nota

    Esta é uma versão reduzida da classe ServiceContainer do repositório do XamCAT. Ele será usado como um contêiner de IoC (Inversão de Controle) leve.

  6. Adicione um de Interface Vazia à pasta serviços chamado IDeviceInstallationService.cse adicione o código a seguir.

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

    Nota

    Essa interface será implementada e inicializada por cada destino posteriormente para fornecer a funcionalidade específica da plataforma e deviceInstallation informações exigidas pelo serviço de back-end.

  7. Adicione outro de Interface Vazia à pasta serviços chamada INotificationRegistrationService.cse adicione o código a seguir.

    using System.Threading.Tasks;
    
    namespace PushDemo.Services
    {
        public interface INotificationRegistrationService
        {
            Task DeregisterDeviceAsync();
            Task RegisterDeviceAsync(params string[] tags);
            Task RefreshRegistrationAsync();
        }
    }
    

    Nota

    Isso manipulará a interação entre o cliente e o serviço de back-end.

  8. Adicione outro de Interface Vazia à pasta dos Serviços chamada INotificationActionService.cse adicione o código a seguir.

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

    Nota

    Isso é usado como um mecanismo simples para centralizar o tratamento de ações de notificação.

  9. Adicione uma interface vazia à pasta serviços chamada IPushDemoNotificationActionService.cs derivada doINotificationActionService, com a implementação a seguir.

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

    Nota

    Esse tipo é específico para o aplicativo PushDemo e usa a enumeração PushDemoAction para identificar a ação que está sendo disparada de maneira fortemente tipada.

  10. Adicione um de Classe Vazia à pasta serviços chamado NotificationRegistrationService.cs implementando o INotificationRegistrationService com o código a seguir.

    using System;
    using System.Net.Http;
    using System.Text;
    using System.Threading.Tasks;
    using Newtonsoft.Json;
    using PushDemo.Models;
    using Xamarin.Essentials;
    
    namespace PushDemo.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;
    
            public NotificationRegistrationService(string baseApiUri, string apiKey)
            {
                _client = new HttpClient();
                _client.DefaultRequestHeaders.Add("Accept", "application/json");
                _client.DefaultRequestHeaders.Add("apikey", apiKey);
    
                _baseApiUrl = baseApiUri;
            }
    
            IDeviceInstallationService DeviceInstallationService
                => _deviceInstallationService ??
                    (_deviceInstallationService = ServiceContainer.Resolve<IDeviceInstallationService>());
    
            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, JsonConvert.SerializeObject(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 = JsonConvert.DeserializeObject<string[]>(serializedTags);
    
                await RegisterDeviceAsync(tags);
            }
    
            async Task SendAsync<T>(HttpMethod requestType, string requestUri, T obj)
            {
                string serializedContent = null;
    
                await Task.Run(() => serializedContent = JsonConvert.SerializeObject(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();
            }
        }
    }
    

    Nota

    O argumento apiKey só será necessário se você optar por concluir os clientes Authenticate usando uma seção de Chave de API.

  11. Adicione um de Classe Vazia à pasta dos Serviços chamado PushDemoNotificationActionService.cs implementando o IPushDemoNotificationActionService com o código a seguir.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using PushDemo.Models;
    
    namespace PushDemo.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);
            }
        }
    }
    
  12. Adicione um de Classe Vazia ao projeto PushDemo chamado Config.cs com a implementação a seguir.

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

    Nota

    Isso é usado como uma maneira simples de manter segredos fora do controle do código-fonte. Você pode substituir esses valores como parte de um build automatizado ou substituí-los usando uma classe parcial local. Você fará isso na próxima etapa.

    O campo ApiKey só será necessário se você optar por concluir os clientes Authenticate usando uma seção de chave de API.

  13. Adicione outro de Classe Vazia ao projeto PushDemo desta vez chamado Config.local_secrets.cs com a implementação a seguir.

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

    Nota

    Substitua os valores de espaço reservado pelos seus próprios. Você deve ter anotado isso quando criou o serviço de back-end. A URL do aplicativo de API deve ser . Lembre-se de adicionar *.local_secrets.* ao arquivo gitignore para evitar a confirmação desse arquivo.

    O campo ApiKey só será necessário se você optar por concluir os clientes Authenticate usando uma seção de chave de API.

  14. Adicione um de Classe Vazia ao projeto pushDemo chamado Bootstrap.cs com a implementação a seguir.

    using System;
    using PushDemo.Services;
    
    namespace PushDemo
    {
        public static class Bootstrap
        {
            public static void Begin(Func<IDeviceInstallationService> deviceInstallationService)
            {
                ServiceContainer.Register(deviceInstallationService);
    
                ServiceContainer.Register<IPushDemoNotificationActionService>(()
                    => new PushDemoNotificationActionService());
    
                ServiceContainer.Register<INotificationRegistrationService>(()
                    => new NotificationRegistrationService(
                        Config.BackendServiceEndpoint,
                        Config.ApiKey));
            }
        }
    }
    

    Nota

    O método Begin será chamado por cada plataforma quando o aplicativo iniciar a passagem de uma implementação específica da plataforma de IDeviceInstallationService.

    O argumento construtor NotificationRegistrationServiceapiKey só será necessário se você optar por concluir os clientes Authenticate usando uma seção de chave de API.

Implementar a interface do usuário multiplataforma

  1. No projeto PushDemo, abra MainPage.xaml e substitua o controle StackLayout pelo seguinte.

    <StackLayout VerticalOptions="EndAndExpand"  
                 HorizontalOptions="FillAndExpand"
                 Padding="20,40">
        <Button x:Name="RegisterButton"
                Text="Register"
                Clicked="RegisterButtonClicked" />
        <Button x:Name="DeregisterButton"
                Text="Deregister"
                Clicked="DeregisterButtonClicked" />
    </StackLayout>
    
  2. Agora, em MainPage.xaml.cs, adicione uma campo de backup somente leitura para armazenar uma referência à implementação de INotificationRegistrationService .

    readonly INotificationRegistrationService _notificationRegistrationService;
    
  3. No construtor MainPage, resolva a implementação INotificationRegistrationService usando a ServiceContainer e atribua-a ao campo de backup notificationRegistrationService .

    public MainPage()
    {
        InitializeComponent();
    
        _notificationRegistrationService =
            ServiceContainer.Resolve<INotificationRegistrationService>();
    }
    
  4. Implemente os manipuladores de eventos para os botões RegisterButton e DeregisterButton eventos clicados chamando os métodos de de Registrocorrespondentes.

    void RegisterButtonClicked(object sender, EventArgs e)
        => _notificationRegistrationService.RegisterDeviceAsync().ContinueWith((task)
            => { ShowAlert(task.IsFaulted ?
                    task.Exception.Message :
                    $"Device registered"); });
    
    void DeregisterButtonClicked(object sender, EventArgs e)
        => _notificationRegistrationService.DeregisterDeviceAsync().ContinueWith((task)
            => { ShowAlert(task.IsFaulted ?
                    task.Exception.Message :
                    $"Device deregistered"); });
    
    void ShowAlert(string message)
        => MainThread.BeginInvokeOnMainThread(()
            => DisplayAlert("PushDemo", message, "OK").ContinueWith((task)
                => { if (task.IsFaulted) throw task.Exception; }));
    
  5. Agora, em App.xaml.cs, verifique se os namespaces a seguir são referenciados.

    using PushDemo.Models;
    using PushDemo.Services;
    using Xamarin.Essentials;
    using Xamarin.Forms;
    
  6. Implemente o manipulador de eventos para o evento IPushDemoNotificationActionServiceActionTriggered.

    void NotificationActionTriggered(object sender, PushDemoAction e)
        => ShowActionAlert(e);
    
    void ShowActionAlert(PushDemoAction action)
        => MainThread.BeginInvokeOnMainThread(()
            => MainPage?.DisplayAlert("PushDemo", $"{action} action received", "OK")
                .ContinueWith((task) => { if (task.IsFaulted) throw task.Exception; }));
    
  7. No construtor App, resolva a implementação IPushNotificationActionService usando o ServiceContainer e assine o evento IPushDemoNotificationActionServiceActionTriggered.

    public App()
    {
        InitializeComponent();
    
        ServiceContainer.Resolve<IPushDemoNotificationActionService>()
            .ActionTriggered += NotificationActionTriggered;
    
        MainPage = new MainPage();
    }
    

    Nota

    Isso é simplesmente para demonstrar o recebimento e a propagação de ações de notificação por push. Normalmente, elas seriam tratadas silenciosamente, por exemplo, navegando para uma exibição específica ou atualizando alguns dados em vez de exibir um alerta por meio dode Página de raiz, mainPage nesse caso.

Configurar o projeto nativo do Android para notificações por push

Validar o nome e as permissões do pacote

  1. Em PushDemo.Android, abra as opções de projeto e, em seguida, do aplicativo Android na seção build.

  2. Verifique se o nome do pacote corresponde ao valor usado no do Console do Firebase . O nome do pacote estava no formato com.<organization>.pushdemo.

  3. Defina o mínimo de versão do Android para android 8.0 (nível de API 26) e a versão do Android de destino para o nível de API mais recente.

    Nota

    Somente os dispositivos que executam nível de API 26 e acima têm suporte para fins deste tutorial, no entanto, você pode estendê-lo para dar suporte a dispositivos que executam versões mais antigas.

  4. Verifique se as permissões internet e READ_PHONE_STATE estão habilitadas em permissões necessárias.

  5. Clique em OK

Adicionar a base do Xamarin Google Play Services e os pacotes Xamarin.Firebase.Messaging

  1. Em PushDemo.Android, ControlClique em na pasta pacotes e escolha Gerenciar Pacotes NuGet....

  2. Pesquise Xamarin.GooglePlayServices.Base (não Basement) e verifique se está marcada.

  3. Pesquise Xamarin.Firebase.Messaging e verifique se está marcada.

  4. Clique em Adicionar Pacotese, em seguida, clique em Aceitar quando solicitado a aceitar os termos de licença .

Adicionar o arquivo JSON do Google Services

  1. ControleClique no projeto e escolha Arquivo Existente... no menu Adicionar .

  2. Escolha o arquivo google-services.json que você baixou anteriormente ao configurar o projeto PushDemo no do Console do Firebase e clique em Abrir.

  3. Quando solicitado, escolha Copiar o arquivo para o diretório.

  4. ControlClique no arquivo google-services.json de dentro do projeto e verifique se GoogleServicesJson está definido como ode Ação de Build .

Manipular notificações por push para Android

  1. ControleClique em no projeto , escolha Nova Pasta no menu Adicionar e, em seguida, clique em Adicionar usando de Serviços como onome da pasta .

  2. ControleClique na pasta dos Serviços e escolha Novo Arquivo... no menu Adicionar .

  3. Selecione de Classe VaziaGeral, insira DeviceInstallationService.cs para ode Nome do e clique em Nova adicionando a implementação a seguir.

    using System;
    using Android.App;
    using Android.Gms.Common;
    using PushDemo.Models;
    using PushDemo.Services;
    using static Android.Provider.Settings;
    
    namespace PushDemo.Droid.Services
    {
        public class DeviceInstallationService : IDeviceInstallationService
        {
            public string Token { get; set; }
    
            public bool NotificationsSupported
                => GoogleApiAvailability.Instance
                    .IsGooglePlayServicesAvailable(Application.Context) == ConnectionResult.Success;
    
            public string GetDeviceId()
                => Secure.GetString(Application.Context.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 FCM");
    
                var installation = new DeviceInstallation
                {
                    InstallationId = GetDeviceId(),
                    Platform = "fcm",
                    PushChannel = Token
                };
    
                installation.Tags.AddRange(tags);
    
                return installation;
            }
    
            string GetPlayServicesError()
            {
                int resultCode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(Application.Context);
    
                if (resultCode != ConnectionResult.Success)
                    return GoogleApiAvailability.Instance.IsUserResolvableError(resultCode) ?
                               GoogleApiAvailability.Instance.GetErrorString(resultCode) :
                               "This device is not supported";
    
                return "An error occurred preventing the use of push notifications";
            }
        }
    }
    

    Nota

    Essa classe fornece uma ID exclusiva (usando Secure.AndroidId) como parte do conteúdo de registro do hub de notificação.

  4. Adicione outra de Classe Vazia à pasta serviços chamada PushNotificationFirebaseMessagingService.cse adicione a implementação a seguir.

    using Android.App;
    using Android.Content;
    using Firebase.Messaging;
    using PushDemo.Services;
    
    namespace PushDemo.Droid.Services
    {
        [Service]
        [IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
        public class PushNotificationFirebaseMessagingService : FirebaseMessagingService
        {
            IPushDemoNotificationActionService _notificationActionService;
            INotificationRegistrationService _notificationRegistrationService;
            IDeviceInstallationService _deviceInstallationService;
    
            IPushDemoNotificationActionService NotificationActionService
                => _notificationActionService ??
                    (_notificationActionService =
                    ServiceContainer.Resolve<IPushDemoNotificationActionService>());
    
            INotificationRegistrationService NotificationRegistrationService
                => _notificationRegistrationService ??
                    (_notificationRegistrationService =
                    ServiceContainer.Resolve<INotificationRegistrationService>());
    
            IDeviceInstallationService DeviceInstallationService
                => _deviceInstallationService ??
                    (_deviceInstallationService =
                    ServiceContainer.Resolve<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)
            {
                if(message.Data.TryGetValue("action", out var messageAction))
                    NotificationActionService.TriggerAction(messageAction);
            }
        }
    }
    
  5. Em MainActivity.cs, verifique se os namespaces a seguir foram adicionados à parte superior do arquivo.

    using System;
    using Android.App;
    using Android.Content;
    using Android.Content.PM;
    using Android.OS;
    using Android.Runtime;
    using Firebase.Iid;
    using PushDemo.Droid.Services;
    using PushDemo.Services;
    
  6. Em MainActivity.cs, defina o LaunchMode como SingleTop para que MainActivity não seja criado novamente quando aberto.

    [Activity(
        Label = "PushDemo",
        LaunchMode = LaunchMode.SingleTop,
        Icon = "@mipmap/icon",
        Theme = "@style/MainTheme",
        MainLauncher = true,
        ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    
  7. Adicione propriedades privadas e campos de backup correspondentes para armazenar uma referência às implementações IPushNotificationActionService e IDeviceInstallationService.

    IPushDemoNotificationActionService _notificationActionService;
    IDeviceInstallationService _deviceInstallationService;
    
    IPushDemoNotificationActionService NotificationActionService
        => _notificationActionService ??
            (_notificationActionService =
            ServiceContainer.Resolve<IPushDemoNotificationActionService>());
    
    IDeviceInstallationService DeviceInstallationService
        => _deviceInstallationService ??
            (_deviceInstallationService =
            ServiceContainer.Resolve<IDeviceInstallationService>());
    
  8. Implemente a interface IOnSuccessListener para recuperar e armazenar o token do Firebase .

    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, Android.Gms.Tasks.IOnSuccessListener
    {
        ...
    
        public void OnSuccess(Java.Lang.Object result)
            => DeviceInstallationService.Token =
                result.Class.GetMethod("getToken").Invoke(result).ToString();
    }
    
  9. Adicione um novo método chamado ProcessNotificationActions que verificará se um determinado de intenção de tem um valor extra chamado ação. Dispare condicionalmente essa ação usando a implementação de IPushDemoNotificationActionService .

    void ProcessNotificationActions(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);
        }
    }
    
  10. Substitua o método OnNewIntent para chamar método ProcessNotificationActions.

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

    Nota

    Como o LaunchMode para o de Atividade de está definido como SingleTop, um de Intenção de será enviado para a instância de Atividade existente por meio da de atividades do método onNewIntent em vez do método OnCreate e, portanto, você deve lidar com uma intenção de entrada em métodos OnCreate e OnNewIntent.

  11. Atualize o método OnCreate para chamar Bootstrap.Begin logo após a chamada para base.OnCreate passando a implementação específica da plataforma de IDeviceInstallationService.

    Bootstrap.Begin(() => new DeviceInstallationService());
    
  12. No mesmo método, chame condicionalmente GetInstanceId na instância FirebaseApp, logo após a chamada para , adicionando MainActivity como o IOnSuccessListener.

    if (DeviceInstallationService.NotificationsSupported)
    {
        FirebaseInstanceId.GetInstance(Firebase.FirebaseApp.Instance)
            .GetInstanceId()
            .AddOnSuccessListener(this);
    }
    
  13. Ainda no OnCreate, chame ProcessNotificationActions imediatamente após a chamada para passando ode Intenção atual.

    ...
    
    LoadApplication(new App());
    
    ProcessNotificationActions(Intent);
    

Nota

Você deve registrar novamente o aplicativo sempre que o executar e interrompê-lo de uma sessão de depuração para continuar recebendo notificações por push.

Configurar o projeto iOS nativo para notificações por push

Configurar Info.plist e Entitlements.plist

  1. Verifique se você entrou no da Conta de Desenvolvedor da Apple em Preferências dedo Visual Studio...Contas de Desenvolvedor da Apple e o de Certificado e Perfil de Provisionamento apropriados foram baixados. Você deve ter criado esses ativos como parte das etapas anteriores.

  2. Em PushDemo.iOS, abra Info.plist e verifique se o BundleIdentifier corresponde ao valor usado para o respectivo perfil de provisionamento no do Portal do Desenvolvedor da Apple. O BundleIdentifier estava no formato .

  3. No mesmo arquivo, defina versão mínima do sistema como 13.0.

    Nota

    Somente os dispositivos que executam iOS 13.0 e acima têm suporte para fins deste tutorial, no entanto, você pode estendê-lo para dar suporte a dispositivos que executam versões mais antigas.

  4. Abra o Opções do Projeto para PushDemo.iOS (clique duas vezes no projeto).

  5. Em opções de projeto, em Criar >de Assinatura de Pacote do iOS, verifique se sua conta de Desenvolvedor está selecionada em Team. Em seguida, verifique se "Gerenciar automaticamente a assinatura" está selecionado e se o Certificado de Autenticação e o Perfil de Provisionamento são selecionados automaticamente.

    Nota

    Se o de Certificado de Assinatura e perfil de provisionamento não tiverem sido selecionados automaticamente, escolha de Provisionamento Manual e clique em Opções de Assinatura do Pacote. Verifique se o da equipe de está selecionado para de Identidade de Assinatura e seu perfil de provisionamento PushDemo está selecionado para de Perfil de Provisionamento para configurações de de depuração e versão, garantindo que iPhone esteja selecionado para o da Plataforma em ambos os casos.

  6. Em PushDemo.iOS, abra Entitlements.plist e verifique se habilitar notificações por push é verificado quando exibido na guia direitos de . Em seguida, verifique se a configuração de de Ambiente do APS está definida como de desenvolvimento quando exibida na guia de Origem do .

Manipular notificações por push para iOS

  1. ControleClique em no projeto PushDemo.iOS, escolha novo de Pasta no menu Adicionar e clique em Adicionar usando de Serviços como onome da pasta .

  2. ControleClique na pasta dos Serviços e escolha Novo Arquivo... no menu Adicionar .

  3. Selecione de Classe VaziaGeral, insira DeviceInstallationService.cs para ode Nome do e clique em Nova adicionando a implementação a seguir.

    using System;
    using PushDemo.Models;
    using PushDemo.Services;
    using UIKit;
    
    namespace PushDemo.iOS.Services
    {
        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";
            }
        }
    }
    

    Nota

    Essa classe fornece uma ID exclusiva (usando o UIDevice.IdentifierForVendor valor) e o conteúdo de registro do hub de notificação.

  4. Adicione uma nova pasta ao projeto PushDemo.iOS chamado extensões e adicione um de Classe Vazia à pasta chamada NSDataExtensions.cs com a implementação a seguir.

    using System.Text;
    using Foundation;
    
    namespace PushDemo.iOS.Extensions
    {
        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();
            }
        }
    }
    
  5. Em AppDelegate.cs, verifique se os namespaces a seguir foram adicionados à parte superior do arquivo.

    using System;
    using System.Diagnostics;
    using System.Threading.Tasks;
    using Foundation;
    using PushDemo.iOS.Extensions;
    using PushDemo.iOS.Services;
    using PushDemo.Services;
    using UIKit;
    using UserNotifications;
    using Xamarin.Essentials;
    
  6. Adicione propriedades privadas e seus respectivos campos de backup para armazenar uma referência às implementações IPushDemoNotificationActionService, INotificationRegistrationServicee IDeviceInstallationService.

    IPushDemoNotificationActionService _notificationActionService;
    INotificationRegistrationService _notificationRegistrationService;
    IDeviceInstallationService _deviceInstallationService;
    
    IPushDemoNotificationActionService NotificationActionService
        => _notificationActionService ??
            (_notificationActionService =
            ServiceContainer.Resolve<IPushDemoNotificationActionService>());
    
    INotificationRegistrationService NotificationRegistrationService
        => _notificationRegistrationService ??
            (_notificationRegistrationService =
            ServiceContainer.Resolve<INotificationRegistrationService>());
    
    IDeviceInstallationService DeviceInstallationService
        => _deviceInstallationService ??
            (_deviceInstallationService =
            ServiceContainer.Resolve<IDeviceInstallationService>());
    
  7. Adicione o método RegisterForRemoteNotifications para registrar as configurações de notificação do usuário e, em seguida, para notificações remotas com APNS.

    void RegisterForRemoteNotifications()
    {
        MainThread.BeginInvokeOnMainThread(() =>
        {
            var pushSettings = UIUserNotificationSettings.GetSettingsForTypes(
                UIUserNotificationType.Alert |
                UIUserNotificationType.Badge |
                UIUserNotificationType.Sound,
                new NSSet());
    
            UIApplication.SharedApplication.RegisterUserNotificationSettings(pushSettings);
            UIApplication.SharedApplication.RegisterForRemoteNotifications();
        });
    }
    
  8. Adicione o método CompleteRegistrationAsync para definir o valor da propriedade . Atualize o registro e armazene o token do dispositivo em cache se ele tiver sido atualizado desde a última vez que ele foi armazenado.

    Task CompleteRegistrationAsync(NSData deviceToken)
    {
        DeviceInstallationService.Token = deviceToken.ToHexString();
        return NotificationRegistrationService.RefreshRegistrationAsync();
    }
    
  9. Adicione o método ProcessNotificationActions para processar os dados de notificação de do NSDictionary e chamar condicionalmente NotificationActionService.TriggerAction.

    void ProcessNotificationActions(NSDictionary userInfo)
    {
        if (userInfo == null)
            return;
    
        try
        {
            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. Substitua o método RegisteredForRemoteNotifications passando o argumento deviceToken para o método CompleteRegistrationAsync.

    public override void RegisteredForRemoteNotifications(
        UIApplication application,
        NSData deviceToken)
        => CompleteRegistrationAsync(deviceToken).ContinueWith((task)
            => { if (task.IsFaulted) throw task.Exception; });
    
  11. Substitua o método ReceivedRemoteNotification passando o argumento userInfo para o método ProcessNotificationActions.

    public override void ReceivedRemoteNotification(
        UIApplication application,
        NSDictionary userInfo)
        => ProcessNotificationActions(userInfo);
    
  12. Substitua o método FailedToRegisterForRemoteNotifications para registrar o erro em log.

    public override void FailedToRegisterForRemoteNotifications(
        UIApplication application,
        NSError error)
        => Debug.WriteLine(error.Description);
    

    Nota

    Este é um espaço reservado. Você desejará implementar o registro em log e o tratamento de erros adequados para cenários de produção.

  13. Atualize o método finishedLaunching para chamar logo após a chamada para passando a implementação específica da plataforma de IDeviceInstallationService.

    Bootstrap.Begin(() => new DeviceInstallationService());
    
  14. No mesmo método, solicite condicionalmente a autorização e registre-se para notificações remotas imediatamente após Bootstrap.Begin.

    if (DeviceInstallationService.NotificationsSupported)
    {
        UNUserNotificationCenter.Current.RequestAuthorization(
                UNAuthorizationOptions.Alert |
                UNAuthorizationOptions.Badge |
                UNAuthorizationOptions.Sound,
                (approvalGranted, error) =>
                {
                    if (approvalGranted && error == null)
                        RegisterForRemoteNotifications();
                });
    }
    
  15. Ainda em FinishedLaunching, chame ProcessNotificationActions imediatamente após a chamada para se as opções de argumento contiverem o UIApplication.LaunchOptionsRemoteNotificationKey passando o objeto userInfo resultante.

    using (var userInfo = options?.ObjectForKey(
        UIApplication.LaunchOptionsRemoteNotificationKey) as NSDictionary)
            ProcessNotificationActions(userInfo);
    

Testar a solução

Agora você pode testar o envio de notificações por meio do serviço de back-end.

Enviar uma notificação de teste

  1. Abra uma nova guia no Postman.

  2. Defina a solicitação para poste insira o seguinte endereço:

    https://<app_name>.azurewebsites.net/api/notifications/requests
    
  3. Se você optou por concluir os clientes Authenticate usando uma seção de chave de API, configure os cabeçalhos de solicitação para incluir seu valor de apikey .

    Chave Valor
    apikey <your_api_key>
  4. Escolha a opção bruta para ocorpo do , escolha JSON na lista de opções de formato e, em seguida, inclua algum espaço reservado conteúdo de JSON:

    {
        "text": "Message from Postman!",
        "action": "action_a"
    }
    
  5. Selecione o botão Código, que está sob o botão salvar no canto superior direito da janela. A solicitação deve ser semelhante ao exemplo a seguir quando exibida para HTML (dependendo se você incluiu um cabeçalho apikey):

    POST /api/notifications/requests HTTP/1.1
    Host: https://<app_name>.azurewebsites.net
    apikey: <your_api_key>
    Content-Type: application/json
    
    {
        "text": "Message from backend service",
        "action": "action_a"
    }
    
  6. Execute o aplicativo PushDemo em uma ou ambas as plataformas de destino (Android e iOS).

    Nota

    Se você estiver testando em Android verifique se não está em execução no de depuraçãoou se o aplicativo foi implantado executando o aplicativo, então force fechar o aplicativo e iniciá-lo novamente do inicializador.

  7. No aplicativo PushDemo, toque no botão Registrar.

  8. De volta ao do Postman, feche a janela Gerar Snippets de Código (se você ainda não fez isso) e clique no botão Enviar.

  9. Valide se você obtém uma resposta 200 OK no postman e o alerta aparece no aplicativo mostrando ação ActionA recebida.

  10. Feche o aplicativo PushDemo e clique no botão Enviar novamente no Postman.

  11. Valide se você obtém uma resposta 200 OK no Postman novamente. Valide se uma notificação aparece na área de notificação do aplicativo PushDemo com a mensagem correta.

  12. Toque na notificação para confirmar se ele abre o aplicativo e exibe a ação ActionA recebida alerta.

  13. De volta ao postman, modifique o corpo da solicitação anterior para enviar uma notificação silenciosa especificando action_b em vez de action_a para o valor da ação .

    {
        "action": "action_b",
        "silent": true
    }
    
  14. Com o aplicativo ainda aberto, clique no botão Enviar em Postman.

  15. Valide se você obtém uma resposta 200 OK em postman e que o alerta aparece no aplicativo mostrando ação do ActionB recebida em vez de ação ActionA recebida.

  16. Feche o aplicativo PushDemo e clique no botão Enviar novamente no Postman.

  17. Valide se você obtém uma resposta 200 OK no postman e que a notificação silenciosa não aparece na área de notificação.

Solucionando problemas

Nenhuma resposta do serviço de back-end

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

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

Verifique se você especificou o endereço base corretamente no postman ou na configuração do aplicativo móvel ao testar por meio do cliente. O endereço base deve ser https://<api_name>.azurewebsites.net/ ou https://localhost:5001/ ao testar localmente.

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

Verifique se você se registrou novamente depois de iniciar ou interromper uma sessão de depuração. O depurador fará com que um novo token de do Firebase seja gerado. A instalação do hub de notificação também deve ser atualizada.

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

Valide se você está definindo o cabeçalho apikey solicitação e 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 definido na configuração do cliente corresponde ao valor de configuração de usuário Authentication:ApiKey usado peloda API .

Se você estiver testando com um aplicativo de API , verifique se o valor da chave no arquivo de configuração do cliente corresponde à configuração de aplicativo Authentication:ApiKey que você está usando no aplicativo de API .

Nota

Se você tiver criado ou alterado essa configuração depois de implantar o serviço de back-end, deverá reiniciar o serviço para que ele entre em vigor.

Se você optou por não concluir os clientes Authenticate usando uma seção de chave de API, verifique se você não aplicou o atributo Authorize à classe NotificationsController.

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

Valide se o ponto de extremidade e o método de solicitação HTTP estão corretos. Por exemplo, os pontos de extremidade devem ser:

  • [PUT]https://<api_name>.azurewebsites.net/api/notifications/installations
  • [DELETE]https://<api_name>.azurewebsites.net/api/notifications/installations/<installation_id>
  • [POST]https://<api_name>.azurewebsites.net/api/notifications/requests

Ou ao testar localmente:

  • [PUT]https://localhost:5001/api/notifications/installations
  • [DELETE]https://localhost:5001/api/notifications/installations/<installation_id>
  • [POST]https://localhost:5001/api/notifications/requests

Ao especificar o endereço base no aplicativo cliente, verifique se ele termina com um /. O endereço base deve ser https://<api_name>.azurewebsites.net/ ou https://localhost:5001/ ao testar localmente.

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 de resposta Http definindo um ponto de interrupção para inspecionar o valor da propriedade StatusCode nohttpResponse .

Examine 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 esses códigos de status específicos para a respectiva API. Em seguida, tente chamar o serviço de back-end ao depurar localmente.

Valide se o serviço de back-end está funcionando conforme o esperado por meio de postman usando o conteúdo apropriado. Use o conteúdo real criado pelo código do cliente para a plataforma em questão.

Examine 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 sendo resolvidos para variáveis installation id e token para a plataforma apropriada.

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

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

Próximas etapas

Agora você deve ter um aplicativo Xamarin.Forms básico conectado a um hub de notificação por meio de um serviço de back-end e pode enviar e receber notificações.

Provavelmente, você precisará adaptar o exemplo usado neste tutorial para se ajustar ao seu próprio cenário. Também é recomendável implementar tratamento de erros, lógica de repetição e registro em log mais robustos.

do Visual Studio App Center pode ser rapidamente incorporado em aplicativos móveis, fornecendo de análise de e de diagnóstico de para ajudar na solução de problemas.