Partilhar via


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

Exemplo de download Baixe o exemplo

Neste tutorial, você usa Hubs de Notificação do Azure para enviar notificações por push para um aplicativo Flutter direcionado Android e iOS.

Um back-end ASP.NET Core Web API é usado para lidar com de registro de dispositivo para o cliente usando a abordagem de de Instalação mais recente e melhor. O serviço também enviará notificações push de forma 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 Registrando a partir do back-end do seu aplicativo documentação.

Este tutorial leva você pelas seguintes etapas:

Pré-requisitos

Para acompanhar, você precisa:

  • Uma assinatura do Azure onde você pode criar e gerenciar recursos.
  • O Flutter kit de ferramentas (juntamente com seus pré-requisitos).
  • Visual Studio Code com os plug-ins Flutter e Dart instalados.
  • CocoaPods instalados para gerenciar dependências de bibliotecas.
  • A capacidade de executar o aplicativo em Android (dispositivos físicos ou emuladores) ou iOS (apenas dispositivos físicos).

Para Android, você deve ter:

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

Para iOS, você deve ter:

  • Uma conta de desenvolvedor Apple ativa.
  • Um dispositivo iOS físico que está registado na sua conta de programador(com iOS 13.0 e superior).
  • Um certificado de desenvolvimento de.p12 instalado em seu porta-chaves permitindo que você execute um aplicativo em um dispositivo físico.

Observação

O simulador do iOS não suporta notificações remotas e, portanto, um dispositivo físico é necessário ao explorar este exemplo no iOS. No entanto, você não precisa executar o aplicativo no 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 aspetos.

As etapas fornecidas são específicas para macOS. É possível acompanhar do Windows ignorando os aspetos do iOS.

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

Nesta seção, você configura do Firebase Cloud Messaging (FCM) e Apple Push Notification Services (APNS). Em seguida, você cria e configura um hub de notificação para trabalhar com esses serviços.

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

  1. Inicie sessão na consola do Firebase. Crie um novo projeto do Firebase inserindo PushDemo como o nome do projeto .

    Observação

    Um nome exclusivo será gerado para você. Por padrão, isso é composto por uma variante minúscula do nome que você forneceu 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 Firebase ao seu aplicativo Android.

    Adicione o Firebase ao seu aplicativo Android

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

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

      Especifique o nome do pacote

    2. Selecione aplicativo Registrar.

    3. Selecione Download google-services.json. Em seguida, salve o arquivo em uma pasta local para uso posterior e selecione Avançar.

      Download google-services.json

    4. Selecione Avançar.

    5. Selecione Continuar para o console

      Observação

      Se o botão Continuar para console não estiver habilitado, devido à verificação do de instalação verificação, escolha Ignorar esta etapa.

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

    Selecione Configurações do Projeto

    Observação

    Se você não baixou o arquivo google-services.json, você pode baixá-lo nesta página.

  5. Mude para o separador Cloud Messaging na parte superior. Copie e salve a chave do Server para uso posterior. Use esse valor para configurar seu hub de notificação.

    Copiar chave do servidor

Registre seu aplicativo iOS para notificações por push

Para enviar notificações push para uma aplicação iOS, registe a sua aplicação na Apple e registe-se também para receber notificações push.

  1. Se você ainda não registrou seu aplicativo, navegue até o Portal de provisionamento do iOS no Apple Developer Center. Inicie sessão no portal com o seu ID Apple, navegue até Certificados, Identificadores & Perfis e, em seguida, 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 de aplicativo botão de opção. Em seguida, selecione Continuar.

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

  3. Atualize os três valores seguintes para a sua nova aplicação e, em seguida, selecione Continuar:

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

    • ID do pacote: Insira um 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 mobcat é usado como um identificador da organização e o valor PushDemo é usado como o nome do produto.

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

    • de Notificações por Push: Marque a opção Notificações por Push na seção Capabilities.

      Formulário para registar um novo ID de Aplicação

      Essa ação gera sua ID de aplicativo e solicita que você confirme as informações. Selecione Continuare, em seguida, selecione Registar para confirmar o novo ID da aplicação.

      Confirmar novo 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 , emIdentificadores , localize o item de linha ID do aplicativo que você criou. Em seguida, selecione sua linha para exibir a tela Editar a configuração do ID do aplicativo tela.

Criando um certificado para Hubs de Notificação

Um certificado é necessário para permitir que o hub de notificação funcione com Apple Push Notification Services (APNS) e pode ser fornecido de duas maneiras:

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

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

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

OPÇÃO 1: Criando um certificado por push p12 que pode ser carregado diretamente no Hub de Notificação
  1. No Mac, execute a ferramenta Acesso às Chaves. Ele pode ser aberto a partir da pasta Utilities ou da pasta Other na Barra Inicial.

  2. Selecione de Acesso às Chaves, expanda Assistente de Certificadoe, em seguida, selecione Solicitar um Certificado de uma Autoridade de Certificação.

    Usar o Acesso às Chaves para solicitar um novo certificado

    Observação

    Por padrão, o Acesso às Chaves seleciona o primeiro item da lista. Isso pode ser um problema se você estiver na categoria Certificados e Autoridade de Certificação Apple Worldwide Developer Relations não for o primeiro item da lista. Certifique-se de que tem um item não chave ou que a chave Apple Worldwide Developer Relations Certification Authority está selecionada antes de gerar o CSR (Pedido de Assinatura de Certificado).

  3. Selecione seu endereço de e-mail de usuário , insira seu nome comum valor, certifique-se de especificar Salvo em discoe, em seguida, selecione Continuar. Deixe endereço de e-mail da autoridade de certificação em branco, pois não é necessário.

    Informações de certificado esperadas

  4. Introduza um nome para o ficheiro de Pedido de Assinatura de Certificado (CSR) em Guardar Como, selecione a localização em Ondee, em seguida, selecione Guardar.

    Escolha um nome de arquivo para o certificado

    Esta ação salva a do 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 naPortal de Provisionamento do iOS , role para baixo até a opção Notificações por Push do marcada e selecione Configurar para criar o certificado.

    página Editar ID do aplicativo

  6. A janela Apple Push Notification service TLS/SSL Certificates é exibida. Selecione o botão Criar de Certificado na seção de Certificado TLS/SSL de Desenvolvimento .

    botão Criar certificado para ID de aplicativo

    A tela Criar um novo certificado é exibida.

    Observação

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

  7. Selecione Escolher arquivo, navegue até o local onde 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 Download. Salve o certificado e lembre-se do local no qual ele foi salvo.

    Página de download do certificado gerado

    O certificado é transferido e guardado no seu computador na pasta Downloads.

    Localize o arquivo de certificado na pasta Downloads

    Observação

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

  9. Clique duas vezes no certificado push baixado aps_development.cer. Esta ação instala o novo certificado no Porta-chaves, conforme mostrado na imagem a seguir:

    Lista de certificados de acesso às chaves mostrando o novo certificado

    Observação

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

  10. Em Acesso às Chaves, ControleClique em no novo certificado push que você criou na categoria Certificados. Selecione Exportar, nomeie o arquivo, selecione o formato de p12 e selecione Salvar.

    Exportar certificado como 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.

    Observação

    O nome e a localização 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 de ID de aplicativo (Team ID)
    • ID do pacote
  2. De volta ao Certificados, Identificadores & Perfis, clique em Chaves.

    Observação

    Se você já tiver uma chave configurada para APNS, poderá reutilizar o certificado p8 baixado logo após sua criação. Em caso afirmativo, pode ignorar os passos 3 a 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 da Chave de adequado, marque a opção do serviço de Notificações por Push da Apple (APNS) e clique em Continuar, seguido por Registrar na próxima tela.

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

    Observação

    Certifique-se de manter seu arquivo p8 em um lugar seguro (e salvar um backup). Depois de baixar sua chave, ela não pode ser baixada novamente, pois a cópia do servidor é removida.

  6. Em Chaves, clique na chave que criou (ou numa chave existente se tiver optado por utilizá-la).

  7. Anote o valor ID da chave de .

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

    -----COMEÇAR CHAVE PRIVADA-----
    <key_value>
    -----END CHAVE PRIVADA-----

    Observação

    Este é o de valor de token que será usado posteriormente para configurar Hub de Notificação.

No final dessas etapas, você deve ter as seguintes informações para uso posterior em Configurar seu hub de notificação com informações do APNS:

  • de ID de Equipa (ver passo 1)
  • ID do pacote (consulte a etapa 1)
  • ID da chave (consulte a etapa 7)
  • Valor do token (valor da chave p8 obtido na etapa 8)

Criar um perfil de provisionamento para o aplicativo

  1. Regresse aoPortal de Aprovisionamento do iOS , selecione Certificados, Identificadores & Perfis , selecione Perfis no menu esquerdo e, em seguida, selecione para criar um novo perfil. A tela Registrar um novo perfil de provisionamento é exibida.

  2. Selecione iOS App Development em Development como o tipo de perfil de provisionamento e, em seguida, selecione Continue.

    Lista de perfis de provisionamento

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

    Selecione o ID do aplicativo

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

    Observação

    Este certificado não é o certificado push que você criou na etapa anterior . Este é o seu certificado de desenvolvimento. Se não existir, você deve criá-lo, pois este é um pré-requisito para este tutorial. Os certificados de desenvolvedor podem ser criados no Apple Developer Portal, via Xcode ou em Visual Studio.

  5. Regresse à página Certificados, Identificadores & Perfis, selecione Perfis no menu esquerdo e, em seguida, 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 em Nome 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 em sua máquina de desenvolvimento.

Criar um Hub de Notificação

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

  1. Entre no Azure.

  2. Clique em Criar um recursoe, em seguida, procure e escolha Hub de Notificaçãoe, em seguida, clique em Criar.

  3. Atualize os seguintes campos e clique em Criar:

    DETALHES BÁSICOS

    Assinatura: Escolha o de de Assinatura de destino na lista suspensa
    Grupo de Recursos: Criar uma nova
    de Grupo de Recursos (ou escolha uma existente)

    DETALHES DO NAMESPACE

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

    Observação

    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
    Localização: Escolha um local adequado na lista suspensa
    Nível de preço: Manter a opção padrão Free

    Observação

    A menos que você tenha atingido o número máximo de hubs no nível gratuito.

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

  5. Navegue até o novo Hub de Notificação.

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

  7. Anote os valores de Nome da Política de juntamente com seus valores de Cadeia de Conexão correspondentes.

Configure seu Hub de Notificação com informações do APNS

Em Serviços de Notificação, selecione Apple siga as etapas apropriadas com base na abordagem escolhida anteriormente na seção Criando um certificado para Hubs de Notificação.

Observação

Use o Production for Application Mode somente se quiser enviar notificações por push aos usuários que compraram seu aplicativo na loja.

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

  1. Selecione Certificado.

  2. Selecione o ícone do arquivo.

  3. Selecione o ficheiro .p12 que exportou anteriormente e, em seguida, selecione Abrir.

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

  5. Selecione modo Sandbox.

  6. Selecione Salvar.

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

  1. Selecione Token.

  2. Insira os seguintes valores adquiridos anteriormente:

    • ID da chave
    • ID do pacote
    • ID da Equipa
    • Token
  3. Escolha Sandbox.

  4. Selecione Salvar.

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

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

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

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

Criar um projeto Web

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

  2. Selecione Aplicativo .NET Core>>ASP.NET API do Core>>Próximo.

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

  4. Digite PushDemoApi para a Nome do Projeto e selecione Criar.

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

    Observação

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

    Se lhe for pedido um certificado de desenvolvimento Inválido encontrado mensagem:

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

    2. Clique em Sim quando lhe for pedido para Instalar e confiar no novo certificadoe, em seguida, introduza a palavra-passe para o seu Porta-chaves.

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

  7. Excluir WeatherForecast.cs.

  8. Configure valores de configuração local usando a ferramenta Secret Manager. Dissociar os 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 pelo seu próprio nome de hub de notificação e valores de cadeia de conexão. Você anotou eles na seção criar um hub de notificação. Caso contrário, você pode procurá-los no Azure.

    NotificationHub:Nome:
    Consulte Nome no resumo do do Essentials na parte superior Visão geral.

    NotificationHub:ConnectionString:
    Consulte DefaultFullSharedAccessSignature em Políticas de Acesso

    Observação

    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 do 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 os tokens, mas serão suficientes para os fins deste tutorial. Uma chave de API pode ser configurada facilmente através do ASP.NET Middleware.

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

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

    Observação

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

  2. ControleClique no projeto PushDemoApi, escolha Nova Pasta no menu Adicionar e, em seguida, clique em Adicionar usando de Autenticação como oNome da Pasta .

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

  4. Selecione Classe GeralVazia, insira ApiKeyAuthOptions.cs para oNome do e clique em Novo adicionar a seguinte implementação.

    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 Empty Class à pasta Authentication chamada ApiKeyAuthHandler.cse, em seguida, adicione a seguinte implementação.

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

    Observação

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

  6. Adicione outro de Classe Vazio à pasta de Autenticação chamada ApiKeyAuthenticationBuilderExtensions.cse, em seguida, adicione a seguinte implementação.

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

    Observação

    Este 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. No Startup.cs, atualize o método ConfigureServices para configurar a autenticação de chave de API abaixo da chamada para os serviços . AddControllers método.

    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 no Startup.cs, atualize o método Configure para chamar o UseAuthentication e os métodos de extensão UseAuthorization no IApplicationBuilder do aplicativo. Certifique-se de que esses métodos sejam chamados após UseRouting e antes 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();
        });
    }
    

    Observação

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

Adicionar dependências e configurar serviços

O ASP.NET Core suporta a injeção de dependência de (DI) 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 é registado e disponibilizado através de uma abstração adequada.

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

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

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

  4. ControleClique em no projeto PushDemoApi, escolha Nova Pasta no menu Adicionar e, em seguida, clique em Adicionar usando Modelos como o Nome da Pasta .

  5. ControleClique na pasta Modelos e, em seguida, escolha Novo Arquivo... no menu Adicionar .

  6. Selecione Classe GeralVazia, insira PushTemplates.cs para aNome da e clique em Novo adicionar a seguinte implementação.

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

    Observação

    Essa classe contém as cargas úteis de notificação tokenizadas para as notificações genéricas e silenciosas exigidas por esse cenário. As cargas úteis são definidas fora do de Instalação para permitir a experimentação sem ter que atualizar as instalações existentes através do serviço. Lidar com alterações em instalações dessa maneira está fora do escopo deste tutorial. Para produção, considere modelos personalizados.

  7. Adicione outro Classe Vazia à pasta Modelos chamada DeviceInstallation.cse, em seguida, adicione a seguinte implementação.

    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 outro Classe Vazia à pasta Modelos chamada NotificationRequest.cse, em seguida, adicione a seguinte implementação.

    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 Classe Vazia à pasta Models chamada NotificationHubOptions.cse, em seguida, adicione a seguinte implementação.

    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 PushDemoApi chamado Services.

  11. Adicione um de Interface Vazia de à pasta Serviços chamada INotificationService.cse, em seguida, adicione a seguinte implementação.

    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 de à pasta Services chamada NotificationHubsService.cse, em seguida, 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);
            }
        }
    }
    

    Observação

    A expressão de tag fornecida ao SendTemplateNotificationAsync é limitada a 20 tags. Limita-se a 6 para a maioria dos operadores, mas a expressão contém apenas RUP (||) neste caso. Se houver mais de 20 tags na solicitação, elas devem ser divididas em várias solicitações. Consulte a documentação Routing and Tag Expressions para obter mais detalhes.

  13. No Startup.cs, atualize o método ConfigureServices para adicionar o NotificationHubsService como uma implementação singleton do 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 Controllers e, em seguida, escolha Novo Arquivo... no menu Adicionar .

  2. Selecione ASP.NET Core>Web API Controller Class, digite NotificationsController para o Nomee, em seguida, clique em Novo.

    Observação

    Se você estiver seguindo com Visual Studio 2019, escolha o API Controller 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 de modelo para que ele derive de ControllerBase e seja decorado com o atributo ApiController.

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

    Observação

    O Controller classe base fornece suporte para modos de exibição, mas isso não é necessário neste caso e, portanto, ControllerBase pode ser usado em vez disso. Se você estiver seguindo com Visual Studio 2019, poderá ignorar esta etapa.

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

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

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

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

    Observação

    Visual Studio pode não iniciar automaticamente o aplicativo no navegador. Você usará Postman para testar a API a partir deste ponto.

  9. Em uma nova guia Postman, defina a solicitação como GET. Digite o endereço abaixo substituindo o espaço reservado applicationUrl pelo https applicationUrl encontrado em PropertieslaunchSettings.json.

    <applicationUrl>/api/notifications
    

    Observação

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

  10. Se você optar por concluir a seção Autenticar clientes usando uma chave de API, certifique-se de configurar os cabeçalhos de solicitação para incluir seu valor de apikey.

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

    Observação

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

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

  12. Substitua os métodos de classe templated no 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 de Aplicativo de API de no do Serviço de Aplicativo do Azure para hospedar o serviço de back-end.

  1. Entre no portal do Azure.

  2. Clique em Criar um recursoe, em seguida, procure e escolha API Appe, em seguida, clique em Criar.

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

    Nome do aplicativo:
    Insira um nome globalmente exclusivo para o API App

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

    Grupo de Recursos:
    Escolha a mesma Grupo de Recursos você criou o hub de notificação.

    Plano/Localização do Serviço de Aplicativo:
    Criar um novo Plano do Serviço de Aplicativo

    Observação

    Mude da opção padrão para um plano que inclua suporte a SSL. Caso contrário, você precisará tomar as medidas apropriadas ao trabalhar com o aplicativo móvel para evitar 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 do aplicativo de API tiver sido provisionado, navegue até esse recurso.

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

    Observação

    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 (em Configurações).

  7. Para cada uma das configurações abaixo, clique em Nova configuração do aplicativo para inserir a Nome do e umaValor e, em seguida, clique em OK.

    Designação Valor
    Authentication:ApiKey <api_key_value>
    NotificationHub:Name <hub_name_value>
    NotificationHub:ConnectionString <hub_connection_string_value>

    Observação

    Estas 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 é necessária somente se você optar por concluir a seção Autenticar clientes usando uma de chave de API. Para cenários de produção, você pode examinar opções como Azure KeyVault. Estes foram adicionados como configurações de aplicativo para simplicidade neste caso.

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

Publicar o serviço de back-end

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

Observação

As etapas a seguir são específicas para Visual Studio para Mac. Se você estiver seguindo com 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 Debug para Release se ainda não tiver feito isso.

  2. ControleClique projeto de PushDemoApi e escolha Publicar no Azure... no menu Publicar.

  3. Siga o fluxo de autenticação se solicitado a fazê-lo. Use a conta que você usou 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 seu destino de publicação e clique em Publicar.

Depois de concluir o assistente, ele publica o aplicativo no Azure e abre o aplicativo. Anote o URL se ainda não o tiver feito. Este URL é o seu de ponto de extremidade de back-end que é usado posteriormente neste tutorial.

Validando a API publicada

  1. No Postman abrir um novo separador, defina o pedido para PUT e introduza o endereço abaixo. Substitua o espaço reservado pelo endereço base que você anotou na seção anterior publique a seção do serviço de back-end.

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

    Observação

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

  2. Se você optar por concluir a seção Autenticar clientes usando uma chave de API, certifique-se de configurar os cabeçalhos de solicitação para incluir seu valor de apikey.

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

    {}
    
  4. Clique Enviar.

    Observação

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

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

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

Observação

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

Crie um aplicativo Flutter multiplataforma

Nesta seção, você cria um Flutter aplicativo móvel implementando notificações por push de maneira multiplataforma.

Ele permite que você registre e cancele o registro 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 na central de notificações.

Observação

Normalmente, você executaria as ações de registro (e cancelamento de registro) 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/cancelamento de registro do usuário. No entanto, este exemplo exigirá a entrada explícita do usuário para permitir que essa funcionalidade seja explorada e testada mais facilmente.

Crie a solução Flutter

  1. Abra uma nova instância do Visual Studio Code.

  2. Abra o Paleta de Comandos (Shift + Command + P).

  3. Selecione o comando Flutter: New Project e pressione Enter.

  4. Introduza push_demo para o Nome do Projeto e, em seguida, selecione uma localização Projeto.

  5. Quando solicitado a fazê-lo, escolha Obter pacotes.

  6. Controle + Clique na pasta kotlin (em aplicativo>src>principal ), em seguida, escolha Revelar no Finder. Em seguida, renomeie as pastas filho (sob a pasta kotlin) para com, <your_organization>e pushdemo respectivamente.

    Observação

    Ao usar o modelo Visual Studio Code essas pastas padrão para com, exemplo, <project_name>. Supondo mobcat é usado para a organização , a estrutura de pastas deve aparecer indicativamente como:

    • Kotlin
      • com
        • mafioso
          • Pushdemo
  7. De volta ao Visual Studio Code, atualize o valor applicationId em aplicativo Android>>build.gradle para com.<your_organization>.pushdemo.

    Observação

    Você deve usar seu próprio nome de organização para o espaço reservado <your_organization>. Por exemplo, usar mobcat como a organização resultará em um nome de pacote valor de com.mobcat.pushdemo.

  8. Atualize o atributo do pacote nos arquivos AndroidManifest.xml, em de depuração dosrc, srcprincipal e srcperfil respectivamente. Verifique se os valores correspondem ao applicationId você usou na etapa anterior.

    <manifest
        xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.<your_organization>.pushdemo>">
        ...
    </manifest>
    
  9. Atualize o atributo android:label no arquivo AndroidManifest.xml em src> principal para PushDemo. Em seguida, adicione o atributo android:allowBackup, diretamente em android:label, definindo seu valor como false.

    <application
        android:name="io.flutter.app.FlutterApplication"
        android:label="PushDemo"
        android:allowBackup="false"
        android:icon="@mipmap/ic_launcher">
        ...
    </application>
    
  10. Abra o arquivo de build.gradle no nível do aplicativo (aplicativo Androidbuild.gradle), em seguida, atualize o compileSdkVersion (da seção android) para usar a API 29. Em seguida, atualize os valores minSdkVersion e targetSdkVersion (da seção defaultConfig), para 26 e 29 respectivamente.

    Observação

    Apenas os dispositivos que executam nível de API 26 e superior são suportados para os fins deste tutorial, no entanto, você pode estendê-lo para suportar dispositivos que executam versões mais antigas.

  11. ControleClique em na pasta ios e, em seguida, escolha Abrir no Xcode.

  12. No Xcode, clique em Runner (o xcodeproj na parte superior, não na pasta). Em seguida, selecione o destino Runner e selecione a guia Geral. Com a configuração All build selecionada, atualize o Bundle Identifier para .

    Observação

    Você deve usar seu próprio nome de organização para o espaço reservado <your_organization>. Por exemplo, usar mobcat como a organização resultará em um Bundle Identifier valor de com.mobcat.PushDemo.

  13. Clique Info.plist atualize o nome do Bundle valor para PushDemo

  14. Feche Xcode e retorne ao Visual Studio Code.

  15. De volta ao Visual Studio Code, abra pubspec.yaml, adicione o http e flutter_secure_storagepacotes Dart como dependências. Em seguida, salve o arquivo e clique em obter pacotes quando solicitado.

    dependencies:
      flutter:
        sdk: flutter
    
      http: ^0.12.1
      flutter_secure_storage: ^3.3.3
    
  16. No Terminal , altere o diretório para a pasta ios (para seu projeto Flutter). Em seguida, execute o comando pod install para instalar novos pods (exigido pelo pacote flutter_secure_storage).

  17. + de controle Clique na pasta lib e, em seguida, escolha Novo Arquivo no menu usando main_page.dart como nome do arquivo. Em seguida, adicione o seguinte código.

    import 'package:flutter/material.dart';
    
    class MainPage extends StatefulWidget {
      @override
      _MainPageState createState() => _MainPageState();
    }
    
    class _MainPageState extends State<MainPage> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: SafeArea(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: <Widget>[],
            )
          )
        );
      }
    }
    
  18. No main.dart, substitua o código do modelo pelo seguinte.

    import 'package:flutter/material.dart';
    import 'package:push_demo/main_page.dart';
    
    final navigatorKey = GlobalKey<NavigatorState>();
    
    void main() => runApp(MaterialApp(home: MainPage(), navigatorKey: navigatorKey));
    
  19. No Terminal, crie e execute o aplicativo em cada plataforma de destino para testar o aplicativo modelo executado no(s) seu(s) dispositivo(s). Certifique-se de que os dispositivos suportados estão ligados.

    flutter run
    

Implementar os componentes multiplataforma

  1. ControleClique em na pasta lib e, em seguida, escolha Nova Pasta no menu usando modelos como oNome da Pasta .

  2. ControleClique em na pasta modelos e, em seguida, escolha Nova de arquivo no menu usando device_installation.dart como nome do arquivo. Em seguida, adicione o seguinte código.

    class DeviceInstallation {
        final String deviceId;
        final String platform;
        final String token;
        final List<String> tags;
    
        DeviceInstallation(this.deviceId, this.platform, this.token, this.tags);
    
        DeviceInstallation.fromJson(Map<String, dynamic> json)
          : deviceId = json['installationId'],
            platform = json['platform'],
            token = json['pushChannel'],
            tags = json['tags'];
    
        Map<String, dynamic> toJson() =>
        {
          'installationId': deviceId,
          'platform': platform,
          'pushChannel': token,
          'tags': tags,
        };
    }
    
  3. Adicione um novo arquivo ao models pasta chamada push_demo_action.dart definir a enumeração de ações que estão sendo suportadas neste exemplo.

    enum PushDemoAction {
      actionA,
      actionB,
    }
    
  4. Adicione uma nova pasta ao projeto chamada services adicione um novo arquivo a essa pasta chamada device_installation_service.dart com a seguinte implementação.

    import 'package:flutter/services.dart';
    
    class DeviceInstallationService {
      static const deviceInstallation = const MethodChannel('com.<your_organization>.pushdemo/deviceinstallation');
      static const String getDeviceIdChannelMethod = "getDeviceId";
      static const String getDeviceTokenChannelMethod = "getDeviceToken";
      static const String getDevicePlatformChannelMethod = "getDevicePlatform";
    
      Future<String> getDeviceId() {
        return deviceInstallation.invokeMethod(getDeviceIdChannelMethod);
      }
    
      Future<String> getDeviceToken() {
        return deviceInstallation.invokeMethod(getDeviceTokenChannelMethod);
      }
    
      Future<String> getDevicePlatform() {
        return deviceInstallation.invokeMethod(getDevicePlatformChannelMethod);
      }
    }
    

    Observação

    Você deve usar seu próprio nome de organização para o espaço reservado <your_organization>. Por exemplo, usar mobcat como a organização resultará em um MethodChannel nome de com.mobcat.pushdemo/deviceinstallation.

    Essa classe encapsula o trabalho com a plataforma nativa subjacente para adquirir os detalhes de instalação do dispositivo necessários. Um MethodChannel facilita a comunicação assíncrona bidirecional com as plataformas nativas subjacentes. A contrapartida específica da plataforma para este canal será criada em etapas posteriores.

  5. Adicione outro arquivo a essa pasta chamado notification_action_service.dart com a seguinte implementação.

    import 'package:flutter/services.dart';
    import 'dart:async';
    import 'package:push_demo/models/push_demo_action.dart';
    
    class NotificationActionService {
      static const notificationAction =
          const MethodChannel('com.<your_organization>.pushdemo/notificationaction');
      static const String triggerActionChannelMethod = "triggerAction";
      static const String getLaunchActionChannelMethod = "getLaunchAction";
    
      final actionMappings = {
        'action_a' : PushDemoAction.actionA,
        'action_b' : PushDemoAction.actionB
      };
    
      final actionTriggeredController = StreamController.broadcast();
    
      NotificationActionService() {
        notificationAction
            .setMethodCallHandler(handleNotificationActionCall);
      }
    
      Stream get actionTriggered => actionTriggeredController.stream;
    
      Future<void> triggerAction({action: String}) async {
    
        if (!actionMappings.containsKey(action)) {
          return;
        }
    
        actionTriggeredController.add(actionMappings[action]);
      }
    
      Future<void> checkLaunchAction() async {
        final launchAction = await notificationAction.invokeMethod(getLaunchActionChannelMethod) as String;
    
        if (launchAction != null) {
          triggerAction(action: launchAction);
        }
      }
    
      Future<void> handleNotificationActionCall(MethodCall call) async {
        switch (call.method) {
          case triggerActionChannelMethod:
            return triggerAction(action: call.arguments as String);
          default:
            throw MissingPluginException();
            break;
        }
      }
    }
    

    Observação

    Isso é usado como um mecanismo simples para centralizar o processamento de ações de notificação para que elas possam ser tratadas de maneira multiplataforma usando uma enumeração fortemente tipada. O serviço permite que a plataforma nativa subjacente acione uma ação, quando uma é especificada na carga útil de notificação. Ele também permite que o código comum verifique retrospetivamente se uma ação foi especificada durante a inicialização do aplicativo assim que o Flutter estiver pronto para processá-la. Por exemplo, quando o aplicativo é iniciado tocando em uma notificação da central de notificações.

  6. Adicione um novo arquivo à pasta de serviços chamada notification_registration_service.dart com a seguinte implementação.

    import 'dart:convert';
    import 'package:flutter/services.dart';
    import 'package:http/http.dart' as http;
    import 'package:push_demo/services/device_installation_service.dart';
    import 'package:push_demo/models/device_installation.dart';
    import 'package:flutter_secure_storage/flutter_secure_storage.dart';
    
    class NotificationRegistrationService {
      static const notificationRegistration =
          const MethodChannel('com.<your_organization>.pushdemo/notificationregistration');
    
      static const String refreshRegistrationChannelMethod = "refreshRegistration";
      static const String installationsEndpoint = "api/notifications/installations";
      static const String cachedDeviceTokenKey = "cached_device_token";
      static const String cachedTagsKey = "cached_tags";
    
      final deviceInstallationService = DeviceInstallationService();
      final secureStorage = FlutterSecureStorage();
    
      String baseApiUrl;
      String apikey;
    
      NotificationRegistrationService(this.baseApiUrl, this.apikey) {
        notificationRegistration
            .setMethodCallHandler(handleNotificationRegistrationCall);
      }
    
      String get installationsUrl => "$baseApiUrl$installationsEndpoint";
    
      Future<void> deregisterDevice() async {
        final cachedToken = await secureStorage.read(key: cachedDeviceTokenKey);
        final serializedTags = await secureStorage.read(key: cachedTagsKey);
    
        if (cachedToken == null || serializedTags == null) {
          return;
        }
    
        var deviceId = await deviceInstallationService.getDeviceId();
    
        if (deviceId.isEmpty) {
          throw "Unable to resolve an ID for the device.";
        }
    
        var response = await http
            .delete("$installationsUrl/$deviceId", headers: {"apikey": apikey});
    
        if (response.statusCode != 200) {
          throw "Deregister request failed: ${response.reasonPhrase}";
        }
    
        await secureStorage.delete(key: cachedDeviceTokenKey);
        await secureStorage.delete(key: cachedTagsKey);
      }
    
      Future<void> registerDevice(List<String> tags) async {
        try {
          final deviceId = await deviceInstallationService.getDeviceId();
          final platform = await deviceInstallationService.getDevicePlatform();
          final token = await deviceInstallationService.getDeviceToken();
    
          final deviceInstallation =
              DeviceInstallation(deviceId, platform, token, tags);
    
          final response = await http.put(installationsUrl,
              body: jsonEncode(deviceInstallation),
              headers: {"apikey": apikey, "Content-Type": "application/json"});
    
          if (response.statusCode != 200) {
            throw "Register request failed: ${response.reasonPhrase}";
          }
    
          final serializedTags = jsonEncode(tags);
    
          await secureStorage.write(key: cachedDeviceTokenKey, value: token);
          await secureStorage.write(key: cachedTagsKey, value: serializedTags);
        } on PlatformException catch (e) {
          throw e.message;
        } catch (e) {
          throw "Unable to register device: $e";
        }
      }
    
      Future<void> refreshRegistration() async {
        final currentToken = await deviceInstallationService.getDeviceToken();
        final cachedToken = await secureStorage.read(key: cachedDeviceTokenKey);
        final serializedTags = await secureStorage.read(key: cachedTagsKey);
    
        if (currentToken == null ||
            cachedToken == null ||
            serializedTags == null ||
            currentToken == cachedToken) {
          return;
        }
    
        final tags = jsonDecode(serializedTags);
    
        return registerDevice(tags);
      }
    
      Future<void> handleNotificationRegistrationCall(MethodCall call) async {
        switch (call.method) {
          case refreshRegistrationChannelMethod:
            return refreshRegistration();
          default:
            throw MissingPluginException();
            break;
        }
      }
    }
    

    Observação

    Essa classe encapsula o uso do DeviceInstallationService e as solicitações para o serviço de back-end para executar as ações de registro, cancelamento de registro e atualização necessárias. O argumento apiKey só é necessário se você optar por concluir a seção Autenticar clientes usando uma chave de API.

  7. Adicione um novo arquivo à pasta lib chamada config.dart com a seguinte implementação.

    class Config {
      static String apiKey = "API_KEY";
      static String backendServiceEndpoint = "BACKEND_SERVICE_ENDPOINT";
    }
    

    Observação

    Isso é usado como uma maneira simples de definir segredos do aplicativo. Substitua os valores de espaço reservado pelos seus. Você deve ter anotado isso quando criou o serviço de back-end. O de URL do aplicativo de API deve ser . A apiKey membro só é necessária se você optar por concluir a seção Autenticar clientes usando uma de chave de API.

    Certifique-se de adicionar isso ao seu arquivo gitignore para evitar comprometer esses segredos no controle do código-fonte.

Implementar a interface do usuário entre plataformas

  1. Nomain_page.dart, substitua a função compilação pelo seguinte.

    @override
    Widget build(BuildContext context) {
    return Scaffold(
        body: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 40.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.end,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              FlatButton(
                child: Text("Register"),
                onPressed: registerButtonClicked,
              ),
              FlatButton(
                child: Text("Deregister"),
                onPressed: deregisterButtonClicked,
              ),
            ],
          ),
        ),
      );
    }
    
  2. Adicione as importações necessárias à parte superior do arquivo main_page.dart.

    import 'package:push_demo/services/notification_registration_service.dart';
    import 'config.dart';
    
  3. Adicione um campo à classe _MainPageState para armazenar uma referência ao NotificationRegistrationService.

    final notificationRegistrationService = NotificationRegistrationService(Config.backendServiceEndpoint, Config.apiKey);
    
  4. Na classe _MainPageState, implemente os manipuladores de eventos para os botões Registrar e Cancelar registroeventos onPressed. Chame os métodos correspondentes Register/Cancele o registro e mostre um alerta para indicar o resultado.

    void registerButtonClicked() async {
        try {
          await notificationRegistrationService.registerDevice(List<String>());
          await showAlert(message: "Device registered");
        }
        catch (e) {
          await showAlert(message: e);
        }
      }
    
      void deregisterButtonClicked() async {
        try {
          await notificationRegistrationService.deregisterDevice();
          await showAlert(message: "Device deregistered");
        }
        catch (e) {
          await showAlert(message: e);
        }
      }
    
      Future<void> showAlert({ message: String }) async {
        return showDialog<void>(
          context: context,
          barrierDismissible: false,
          builder: (BuildContext context) {
            return AlertDialog(
              title: Text('PushDemo'),
              content: SingleChildScrollView(
                child: ListBody(
                  children: <Widget>[
                    Text(message),
                  ],
                ),
              ),
              actions: <Widget>[
                FlatButton(
                  child: Text('OK'),
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                ),
              ],
            );
          },
        );
      }
    
  5. Agora, em main.dart, verifique se as seguintes importações estão presentes na parte superior do arquivo.

    import 'package:flutter/material.dart';
    import 'package:push_demo/models/push_demo_action.dart';
    import 'package:push_demo/services/notification_action_service.dart';
    import 'package:push_demo/main_page.dart';
    
  6. Declare uma variável para armazenar referência a uma instância de NotificationActionService e inicialize-a.

    final notificationActionService = NotificationActionService();
    
  7. Adicione funções para manipular a exibição de um alerta quando uma ação é acionada.

    void notificationActionTriggered(PushDemoAction action) {
      showActionAlert(message: "${action.toString().split(".")[1]} action received");
    }
    
    Future<void> showActionAlert({ message: String }) async {
      return showDialog<void>(
        context: navigatorKey.currentState.overlay.context,
        barrierDismissible: false,
        builder: (BuildContext context) {
          return AlertDialog(
            title: Text('PushDemo'),
            content: SingleChildScrollView(
              child: ListBody(
                children: <Widget>[
                  Text(message),
                ],
              ),
            ),
            actions: <Widget>[
              FlatButton(
                child: Text('OK'),
                onPressed: () {
                  Navigator.of(context).pop();
                },
              ),
            ],
          );
        },
      );
    }
    
  8. Atualize o função principal para observar o fluxo de NotificationActionServiceactionTriggered e verifique se há ações capturadas durante a inicialização do aplicativo.

    void main() async {
      runApp(MaterialApp(home: MainPage(), navigatorKey: navigatorKey,));
      notificationActionService.actionTriggered.listen((event) { notificationActionTriggered(event as PushDemoAction); });
      await notificationActionService.checkLaunchAction();
    }
    

    Observação

    Isso é simplesmente para demonstrar o recebimento e a propagação de ações de notificação por push. Normalmente, eles seriam tratados silenciosamente, por exemplo, navegando para uma exibição específica ou atualizando alguns dados, em vez de exibir um alerta nesse caso.

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

Adicionar o arquivo JSON dos Serviços Google

  1. ControleClique na pasta Android e, em seguida, escolha Abrir no Android Studio. Em seguida, alterne para o modo de exibição Project (se ainda não estiver).

  2. Localize o arquivo google-services.json que você baixou anteriormente ao configurar o projeto PushDemo noFirebase Console . Em seguida, arraste-o para o aplicativo diretório raiz do módulo (android>android>app).

Definir configurações e permissões de compilação

  1. Mude a vista Project para Android.

  2. Abra AndroidManifest.xmle, em seguida, adicione as permissões INTERNET e READ_PHONE_STATE após o elemento aplicativo antes do fechamento tag.

    <manifest>
        <application>...</application>
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    </manifest>
    

Adicionar os SDKs do Firebase

  1. No Android Studio, abra o arquivo de build.gradle no nível do projeto (Gradle Scripts>build.gradle (Project: android)). e certifique-se de ter o classpath 'com.google.gms:google-services' no nó dependências do .

    buildscript {
    
      repositories {
        // Check that you have the following line (if not, add it):
        google()  // Google's Maven repository
      }
    
      dependencies {
        // ...
    
        // Add the following line:
        classpath 'com.google.gms:google-services:4.3.3'  // Google Services plugin
      }
    }
    
    allprojects {
      // ...
    
      repositories {
        // Check that you have the following line (if not, add it):
        google()  // Google's Maven repository
        // ...
      }
    }
    

    Observação

    Certifique-se de fazer referência à versão mais recente de acordo com as instruções fornecidas no Firebase Console quando criou o Android Project.

  2. No arquivo de build.gradle no nível do aplicativo (Gradle Scripts>build.gradle (Módulo: aplicativo)), aplique o plug-in Google Services Gradle. Aplique o plugin logo acima do nó android.

    // ...
    
    // Add the following line:
    apply plugin: 'com.google.gms.google-services'  // Google Services plugin
    
    android {
      // ...
    }
    
  3. No mesmo arquivo, no nó dependências , adicione a dependência para a biblioteca Cloud Messaging Android.

    dependencies {
        // ...
        implementation 'com.google.firebase:firebase-messaging:20.2.0'
    }
    

    Observação

    Certifique-se de fazer referência à versão mais recente de acordo com a documentação do cliente Android do Cloud Messaging.

  4. Salve as alterações e clique no botão Sincronizar agora (no prompt da barra de ferramentas) ou Sincronizar projeto com arquivos Gradle.

Lidar com notificações push para Android

  1. No Android Studio, Control + Clique no com.<your_organization>pasta do pacote de .pushdemo (app>src>principal>kotlin), escolha Pacote no menu Novo. Introduza serviços como o nome e, em seguida, prima Return.

  2. ControleClique na pasta serviços, escolha Arquivo/Classe Kotlin no menu Novo . Digite DeviceInstallationService como o nome e pressione Return.

  3. Implemente o DeviceInstallationService usando o código a seguir.

    package com.<your_organization>.pushdemo.services
    
    import android.annotation.SuppressLint
    import android.content.Context
    import android.provider.Settings.Secure
    import com.google.android.gms.common.ConnectionResult
    import com.google.android.gms.common.GoogleApiAvailability
    import io.flutter.embedding.engine.FlutterEngine
    import io.flutter.plugin.common.MethodCall
    import io.flutter.plugin.common.MethodChannel
    
    @SuppressLint("HardwareIds")
    class DeviceInstallationService {
    
        companion object {
            const val DEVICE_INSTALLATION_CHANNEL = "com.<your_organization>.pushdemo/deviceinstallation"
            const val GET_DEVICE_ID = "getDeviceId"
            const val GET_DEVICE_TOKEN = "getDeviceToken"
            const val GET_DEVICE_PLATFORM = "getDevicePlatform"
        }
    
        private var context: Context
        private var deviceInstallationChannel : MethodChannel
    
        val playServicesAvailable
            get() = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS
    
        constructor(context: Context, flutterEngine: FlutterEngine) {
            this.context = context
            deviceInstallationChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, DEVICE_INSTALLATION_CHANNEL)
            deviceInstallationChannel.setMethodCallHandler { call, result -> handleDeviceInstallationCall(call, result) }
        }
    
        fun getDeviceId() : String
            = Secure.getString(context.applicationContext.contentResolver, Secure.ANDROID_ID)
    
        fun getDeviceToken() : String {
            if(!playServicesAvailable) {
                throw Exception(getPlayServicesError())
            }
    
            // TODO: Revisit once we have created the PushNotificationsFirebaseMessagingService
            val token = "Placeholder_Get_Value_From_FirebaseMessagingService_Implementation"
    
            if (token.isNullOrBlank()) {
                throw Exception("Unable to resolve token for FCM.")
            }
    
            return token
        }
    
        fun getDevicePlatform() : String = "fcm"
    
        private fun handleDeviceInstallationCall(call: MethodCall, result: MethodChannel.Result) {
            when (call.method) {
                GET_DEVICE_ID -> {
                    result.success(getDeviceId())
                }
                GET_DEVICE_TOKEN -> {
                    getDeviceToken(result)
                }
                GET_DEVICE_PLATFORM -> {
                    result.success(getDevicePlatform())
                }
                else -> {
                    result.notImplemented()
                }
            }
        }
    
        private fun getDeviceToken(result: MethodChannel.Result) {
            try {
                val token = getDeviceToken()
                result.success(token)
            }
            catch (e: Exception) {
                result.error("ERROR", e.message, e)
            }
        }
    
        private fun getPlayServicesError(): String {
            val resultCode = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context)
    
            if (resultCode != ConnectionResult.SUCCESS) {
                return if (GoogleApiAvailability.getInstance().isUserResolvableError(resultCode)){
                    GoogleApiAvailability.getInstance().getErrorString(resultCode)
                } else {
                    "This device is not supported"
                }
            }
    
            return "An error occurred preventing the use of push notifications"
        }
    }
    

    Observação

    Essa classe implementa a contraparte específica da plataforma para o canal com.<your_organization>.pushdemo/deviceinstallation. Isso foi definido na parte Flutter do aplicativo dentro DeviceInstallationService.dart. Neste caso, as chamadas são feitas a partir do código comum para o host nativo. Certifique-se de substituir <your_organization> por sua própria organização onde quer que ela seja usada.

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

  4. Adicione outro Kotlin File/Class à pasta de de serviços chamada NotificationRegistrationServicee, em seguida, adicione o código a seguir.

    package com.<your_organization>.pushdemo.services
    
    import io.flutter.embedding.engine.FlutterEngine
    import io.flutter.plugin.common.MethodChannel
    
    class NotificationRegistrationService {
    
        companion object {
            const val NOTIFICATION_REGISTRATION_CHANNEL = "com.<your_organization>.pushdemo/notificationregistration"
            const val REFRESH_REGISTRATION = "refreshRegistration"
        }
    
        private var notificationRegistrationChannel : MethodChannel
    
        constructor(flutterEngine: FlutterEngine) {
            notificationRegistrationChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, NotificationRegistrationService.NOTIFICATION_REGISTRATION_CHANNEL)
        }
    
        fun refreshRegistration() {
            notificationRegistrationChannel.invokeMethod(REFRESH_REGISTRATION, null)
        }
    }
    

    Observação

    Essa classe implementa a contraparte específica da plataforma para o canal com.<your_organization>.pushdemo/notificationregistration. Isso foi definido na parte Flutter do aplicativo dentro NotificationRegistrationService.dart. Nesse caso, as chamadas são feitas do host nativo para o código comum. Novamente, tome cuidado para substituir <your_organization> por sua própria organização onde quer que ela seja usada.

  5. Adicione outro Kotlin File/Class à pasta services chamada NotificationActionServicee, em seguida, adicione o código a seguir.

    package com.<your_organization>.pushdemo.services
    
    import io.flutter.embedding.engine.FlutterEngine
    import io.flutter.plugin.common.MethodCall
    import io.flutter.plugin.common.MethodChannel
    
    class NotificationActionService {
        companion object {
            const val NOTIFICATION_ACTION_CHANNEL = "com.<your_organization>.pushdemo/notificationaction"
            const val TRIGGER_ACTION = "triggerAction"
            const val GET_LAUNCH_ACTION = "getLaunchAction"
        }
    
        private var notificationActionChannel : MethodChannel
        var launchAction : String? = null
    
        constructor(flutterEngine: FlutterEngine) {
            notificationActionChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, NotificationActionService.NOTIFICATION_ACTION_CHANNEL)
            notificationActionChannel.setMethodCallHandler { call, result -> handleNotificationActionCall(call, result) }
        }
    
        fun triggerAction(action: String) {
            notificationActionChannel.invokeMethod(NotificationActionService.TRIGGER_ACTION, action)
        }
    
        private fun handleNotificationActionCall(call: MethodCall, result: MethodChannel.Result) {
            when (call.method) {
                NotificationActionService.GET_LAUNCH_ACTION -> {
                    result.success(launchAction)
                }
                else -> {
                    result.notImplemented()
                }
            }
        }
    }
    

    Observação

    Essa classe implementa a contraparte específica da plataforma para o canal com.<your_organization>.pushdemo/notificationaction. Isso foi definido na parte Flutter do aplicativo dentro NotificationActionService.dart. Neste caso, as chamadas podem ser feitas em ambos os sentidos. Certifique-se de substituir <your_organization> por sua própria organização onde quer que ela seja usada.

  6. Adicione um novo de Arquivo/Classe Kotlin ao com.<your_organization>pacote de .pushdemo chamado PushNotificationsFirebaseMessagingServicee, em seguida, implemente usando o código a seguir.

    package com.<your_organization>.pushdemo
    
    import android.os.Handler
    import android.os.Looper
    import com.google.firebase.messaging.FirebaseMessagingService
    import com.google.firebase.messaging.RemoteMessage
    import com.<your_organization>.pushdemo.services.NotificationActionService
    import com.<your_organization>.pushdemo.services.NotificationRegistrationService
    
    class PushNotificationsFirebaseMessagingService : FirebaseMessagingService() {
    
        companion object {
            var token : String? = null
            var notificationRegistrationService : NotificationRegistrationService? = null
            var notificationActionService : NotificationActionService? = null
        }
    
        override fun onNewToken(token: String) {
            PushNotificationsFirebaseMessagingService.token = token
            notificationRegistrationService?.refreshRegistration()
        }
    
        override fun onMessageReceived(message: RemoteMessage) {
            message.data.let {
                Handler(Looper.getMainLooper()).post {
                    notificationActionService?.triggerAction(it.getOrDefault("action", null))
                }
            }
        }
    }
    

    Observação

    Essa classe é responsável por lidar com notificações quando o aplicativo está sendo executado em primeiro plano. Ele chamará condicionalmente o triggerAction no NotificationActionService do se uma ação for incluída na carga de notificação recebida em onMessageReceived . Isso também chamará refreshRegistration no NotificationRegistrationService quando o token Firebase for regenerado substituindo a função onNewToken .

    Mais uma vez, tenha o cuidado de substituir <your_organization> pela sua própria organização onde quer que seja utilizada.

  7. No AndroidManifest.xml (appsrcprincipal ), adicione o PushNotificationsFirebaseMessagingService à parte inferior do elemento aplicativo com o filtro de intenção .

    <manifest>
        <application>
            <!-- EXISTING MANIFEST CONTENT -->
             <service
                android:name="com.<your_organization>.pushdemo.PushNotificationsFirebaseMessagingService"
                android:exported="false">
                <intent-filter>
                    <action android:name="com.google.firebase.MESSAGING_EVENT" />
                </intent-filter>
            </service>
        </application>
    </manifest>
    
  8. De volta ao DeviceInstallationService, verifique se as seguintes importações estão presentes na parte superior do arquivo.

    package com.<your_organization>.pushdemo
    import com.<your_organization>.pushdemo.services.PushNotificationsFirebaseMessagingService
    

    Observação

    Substitua <your_organization> pelo valor da sua própria organização.

  9. Atualize o Placeholder_Get_Value_From_FirebaseMessagingService_Implementation de texto do espaço reservado para obter o valor do token do PushNotificationFirebaseMessagingService.

    fun getDeviceToken() : String {
        if(!playServicesAvailable) {
            throw Exception(getPlayServicesError())
        }
    
        // Get token from the PushNotificationsFirebaseMessagingService.token field.
        val token = PushNotificationsFirebaseMessagingService.token
    
        if (token.isNullOrBlank()) {
            throw Exception("Unable to resolve token for FCM.")
        }
    
        return token
    }
    
  10. NoMainActivity , verifique se as seguintes importações estão presentes na parte superior do arquivo.

    package com.<your_organization>.pushdemo
    
    import android.content.Intent
    import android.os.Bundle
    import com.google.android.gms.tasks.OnCompleteListener
    import com.google.firebase.iid.FirebaseInstanceId
    import com.<your_organization>.pushdemo.services.DeviceInstallationService
    import com.<your_organization>.pushdemo.services.NotificationActionService
    import com.<your_organization>.pushdemo.services.NotificationRegistrationService
    import io.flutter.embedding.android.FlutterActivity
    

    Observação

    Substitua <your_organization> pelo valor da sua própria organização.

  11. Adicione uma variável para armazenar uma referência ao DeviceInstallationService.

    private lateinit var deviceInstallationService: DeviceInstallationService
    
  12. Adicione uma função chamada processNotificationActions para verificar se um de intenção de tem um valor extra chamado ação. Acione condicionalmente essa ação ou armazene-a para uso posterior se a ação estiver sendo processada durante a inicialização do aplicativo.

     private fun processNotificationActions(intent: Intent, launchAction: Boolean = false) {
        if (intent.hasExtra("action")) {
            var action = intent.getStringExtra("action");
    
            if (action.isNotEmpty()) {
                if (launchAction) {
                    PushNotificationsFirebaseMessagingService.notificationActionService?.launchAction = action
                }
                else {
                    PushNotificationsFirebaseMessagingService.notificationActionService?.triggerAction(action)
                }
            }
        }
    }
    
  13. Substitua a função onNewIntent para chamar processNotificationActions.

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        processNotificationActions(intent)
    }
    

    Observação

    Como o LaunchMode do para MainActivity está definido como SingleTop , um de Intenção será enviado para a instância de Atividade do existente por meio da função onNewIntent em vez da função onCreate e, portanto, você deve lidar com um de Intenção de de entrada nas funções onCreate e onNewIntent.

  14. Substitua o função onCreate, defina o deviceInstallationService para uma nova instância do DeviceInstallationService.

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        flutterEngine?.let {
            deviceInstallationService = DeviceInstallationService(context, it)
        }
    }
    
  15. Defina o notificationActionService e propriedades notificationRegistrationServicePushNotificationFirebaseMessagingServices.

    flutterEngine?.let {
      deviceInstallationService = DeviceInstallationService(context, it)
      PushNotificationsFirebaseMessagingService.notificationActionService = NotificationActionService(it)
      PushNotificationsFirebaseMessagingService.notificationRegistrationService = NotificationRegistrationService(it)
    }
    
  16. Na mesma função, chame condicionalmente FirebaseInstanceId.getInstance().instanceId. Implemente o OnCompleteListener para definir o valor de token resultante em PushNotificationFirebaseMessagingService antes de chamar refreshRegistration .

    if(deviceInstallationService?.playServicesAvailable) {
        FirebaseInstanceId.getInstance().instanceId
            .addOnCompleteListener(OnCompleteListener { task ->
                if (!task.isSuccessful)
                    return@OnCompleteListener
    
                PushNotificationsFirebaseMessagingService.token = task.result?.token
                PushNotificationsFirebaseMessagingService.notificationRegistrationService?.refreshRegistration()
            })
    }
    
  17. Ainda em emCriar, chame processNotificationActions no final da função. Use true para o argumento launchAction para indicar que essa ação está sendo processada durante a inicialização do aplicativo.

    processNotificationActions(this.intent, true)
    

Observação

Você deve registrar novamente o aplicativo sempre que executá-lo 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 o destino do corredor e Info.plist

  1. No Visual Studio Code, ControlClique em na pasta ios e escolha Abrir no Xcode.

  2. No Xcode, clique em Runner (o xcodeproj na parte superior, não na pasta) e selecione o destino Runner e, em seguida, Assinando & Capabilities. Com a configuração All build selecionada, escolha sua conta de desenvolvedor para o Team. Verifique se a opção "Gerenciar assinatura automaticamente" está marcada e se o certificado de assinatura e o perfil de provisionamento são selecionados automaticamente.

    Observação

    Se você não vir o novo valor de Perfil de Provisionamento, tente atualizar os perfis para a Identidade de Assinatura selecionando XcodePreferênciasConta selecione o botão Download Manual de Perfis para baixar os perfis.

  3. Clique em + Capacidadee, em seguida, procure Notificações push. Clique duas vezes em em de Notificações por Push para adicionar esse recurso.

  4. Abra Info.plist e defina versão mínima do sistema como 13.0.

    Observação

    Apenas os dispositivos que executam iOS 13.0 e superior são suportados para os fins deste tutorial, no entanto, você pode estendê-lo para suportar dispositivos que executam versões mais antigas.

  5. Abra Runner.entitlements e verifique se a configuração APS Environment está definida para de desenvolvimento.

Lidar com notificações por push para iOS

  1. Controle + Clique em na pasta Runner (dentro do projeto Runner) e escolha Novo Grupo usando Services como o nome.

  2. ControleClique em na pasta Serviços e, em seguida, escolha Novo Arquivo.... Em seguida, escolha Swift File e clique em Next. Especifique DeviceInstallationService para o nome e clique em Criar.

  3. Implemente DeviceInstallationService.swift usando o código a seguir.

    import Foundation
    
    class DeviceInstallationService {
    
        enum DeviceRegistrationError: Error {
            case notificationSupport(message: String)
        }
    
        var token : Data? = nil
    
        let DEVICE_INSTALLATION_CHANNEL = "com.<your_organization>.pushdemo/deviceinstallation"
        let GET_DEVICE_ID = "getDeviceId"
        let GET_DEVICE_TOKEN = "getDeviceToken"
        let GET_DEVICE_PLATFORM = "getDevicePlatform"
    
        private let deviceInstallationChannel : FlutterMethodChannel
    
        var notificationsSupported : Bool {
            get {
                if #available(iOS 13.0, *) {
                    return true
                }
                else {
                    return false
                }
            }
        }
    
        init(withBinaryMessenger binaryMessenger : FlutterBinaryMessenger) {
            deviceInstallationChannel = FlutterMethodChannel(name: DEVICE_INSTALLATION_CHANNEL, binaryMessenger: binaryMessenger)
            deviceInstallationChannel.setMethodCallHandler(handleDeviceInstallationCall)
        }
    
        func getDeviceId() -> String {
            return UIDevice.current.identifierForVendor!.description
        }
    
        func getDeviceToken() throws -> String {
            if(!notificationsSupported) {
                let notificationSupportError = getNotificationsSupportError()
                throw DeviceRegistrationError.notificationSupport(message: notificationSupportError)
            }
    
            if (token == nil) {
                throw DeviceRegistrationError.notificationSupport(message: "Unable to resolve token for APNS.")
            }
    
            return token!.reduce("", {$0 + String(format: "%02X", $1)})
        }
    
        func getDevicePlatform() -> String {
            return "apns"
        }
    
        private func handleDeviceInstallationCall(call: FlutterMethodCall, result: @escaping FlutterResult) {
            switch call.method {
            case GET_DEVICE_ID:
                result(getDeviceId())
            case GET_DEVICE_TOKEN:
                getDeviceToken(result: result)
            case GET_DEVICE_PLATFORM:
                result(getDevicePlatform())
            default:
                result(FlutterMethodNotImplemented)
            }
        }
    
        private func getDeviceToken(result: @escaping FlutterResult) {
            do {
                let token = try getDeviceToken()
                result(token)
            }
            catch let error {
                result(FlutterError(code: "UNAVAILABLE", message: error.localizedDescription, details: nil))
            }
        }
    
        private func getNotificationsSupportError() -> String {
    
            if (!notificationsSupported) {
                return "This app only supports notifications on iOS 13.0 and above. You are running \(UIDevice.current.systemVersion)"
            }
    
            return "An error occurred preventing the use of push notifications."
        }
    }
    

    Observação

    Essa classe implementa a contraparte específica da plataforma para o canal com.<your_organization>.pushdemo/deviceinstallation. Isso foi definido na parte Flutter do aplicativo dentro DeviceInstallationService.dart. Neste caso, as chamadas são feitas a partir do código comum para o host nativo. Certifique-se de substituir <your_organization> por sua própria organização onde quer que ela seja usada.

    Essa classe fornece uma ID exclusiva (usando o valor UIDevice.identifierForVendor) como parte da carga útil de registro do hub de notificação.

  4. Adicione outro de arquivo Swift à pasta Services chamada NotificationRegistrationServicee, em seguida, adicione o código a seguir.

    import Foundation
    
    class NotificationRegistrationService {
    
        let NOTIFICATION_REGISTRATION_CHANNEL = "com.<your_organization>.pushdemo/notificationregistration"
        let REFRESH_REGISTRATION = "refreshRegistration"
    
        private let notificationRegistrationChannel : FlutterMethodChannel
    
        init(withBinaryMessenger binaryMessenger : FlutterBinaryMessenger) {
           notificationRegistrationChannel = FlutterMethodChannel(name: NOTIFICATION_REGISTRATION_CHANNEL, binaryMessenger: binaryMessenger)
        }
    
        func refreshRegistration() {
            notificationRegistrationChannel.invokeMethod(REFRESH_REGISTRATION, arguments: nil)
        }
    }
    

    Observação

    Essa classe implementa a contraparte específica da plataforma para o canal com.<your_organization>.pushdemo/notificationregistration. Isso foi definido na parte Flutter do aplicativo dentro NotificationRegistrationService.dart. Nesse caso, as chamadas são feitas do host nativo para o código comum. Novamente, tome cuidado para substituir <your_organization> por sua própria organização onde quer que ela seja usada.

  5. Adicione outro de arquivo Swift à pasta Services chamada NotificationActionServicee, em seguida, adicione o código a seguir.

    import Foundation
    
    class NotificationActionService {
    
        let NOTIFICATION_ACTION_CHANNEL = "com.<your_organization>.pushdemo/notificationaction"
        let TRIGGER_ACTION = "triggerAction"
        let GET_LAUNCH_ACTION = "getLaunchAction"
    
        private let notificationActionChannel: FlutterMethodChannel
    
        var launchAction: String? = nil
    
        init(withBinaryMessenger binaryMessenger: FlutterBinaryMessenger) {
            notificationActionChannel = FlutterMethodChannel(name: NOTIFICATION_ACTION_CHANNEL, binaryMessenger: binaryMessenger)
            notificationActionChannel.setMethodCallHandler(handleNotificationActionCall)
        }
    
        func triggerAction(action: String) {
           notificationActionChannel.invokeMethod(TRIGGER_ACTION, arguments: action)
        }
    
        private func handleNotificationActionCall(call: FlutterMethodCall, result: @escaping FlutterResult) {
            switch call.method {
            case GET_LAUNCH_ACTION:
                result(launchAction)
            default:
                result(FlutterMethodNotImplemented)
            }
        }
    }
    

    Observação

    Essa classe implementa a contraparte específica da plataforma para o canal com.<your_organization>.pushdemo/notificationaction. Isso foi definido na parte Flutter do aplicativo dentro NotificationActionService.dart. Neste caso, as chamadas podem ser feitas em ambos os sentidos. Certifique-se de substituir <your_organization> por sua própria organização onde quer que ela seja usada.

  6. Em AppDelegate.swift, adicione variáveis para armazenar uma referência aos serviços criados anteriormente.

    var deviceInstallationService : DeviceInstallationService?
    var notificationRegistrationService : NotificationRegistrationService?
    var notificationActionService : NotificationActionService?
    
  7. Adicione uma função chamada processNotificationActions para processar os dados de notificação. Acione condicionalmente essa ação ou armazene-a para uso posterior se a ação estiver sendo processada durante a inicialização do aplicativo.

    func processNotificationActions(userInfo: [AnyHashable : Any], launchAction: Bool = false) {
        if let action = userInfo["action"] as? String {
            if (launchAction) {
                notificationActionService?.launchAction = action
            }
            else {
                notificationActionService?.triggerAction(action: action)
            }
        }
    }
    
  8. Substitua a função de didRegisterForRemoteNotificationsWithDeviceToken definindo o valor do token de para oDeviceInstallationService. Em seguida, chame refreshRegistration no NotificationRegistrationService.

    override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
      deviceInstallationService?.token = deviceToken
      notificationRegistrationService?.refreshRegistration()
    }
    
  9. Substitua o função didReceiveRemoteNotification passando o argumento userInfo para a função processNotificationActions.

    override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
        processNotificationActions(userInfo: userInfo)
    }
    
  10. Substitua o função didFailToRegisterForRemoteNotificationsWithError para registrar o erro.

    override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print(error);
    }
    

    Observação

    Trata-se, em grande medida, de um espaço reservado. Você desejará implementar o registro em log e o tratamento de erros adequados para cenários de produção.

  11. Em didFinishLaunchingWithOptions, instancie o deviceInstallationService, notificationRegistrationServicee notificationActionService variáveis.

    let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
    
    deviceInstallationService = DeviceInstallationService(withBinaryMessenger: controller.binaryMessenger)
    notificationRegistrationService = NotificationRegistrationService(withBinaryMessenger: controller.binaryMessenger)
    notificationActionService = NotificationActionService(withBinaryMessenger: controller.binaryMessenger)
    
  12. Na mesma função, solicite condicionalmente a autorização e registre-se para notificações remotas.

    if #available(iOS 13.0, *) {
      UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {
          (granted, error) in
    
          if (granted)
          {
              DispatchQueue.main.async {
                  let pushSettings = UIUserNotificationSettings(types: [.alert, .sound, .badge], categories: nil)
                  application.registerUserNotificationSettings(pushSettings)
                  application.registerForRemoteNotifications()
              }
          }
      }
    }
    
  13. Se a launchOptions contiver a tecla de remoteNotification, chame processNotificationActions no final da função didFinishFinishingWithOptions . Passe o objeto resultante userInfo e use true para o argumento launchAction. Um valor true indica que a ação está sendo processada durante a inicialização do aplicativo.

    if let userInfo = launchOptions?[.remoteNotification] as? [AnyHashable : Any] {
        processNotificationActions(userInfo: userInfo, launchAction: true)
    }
    

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 um novo separador no Postman.

  2. Defina a solicitação como POSTe digite o seguinte endereço:

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

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

    {
        "text": "Message from Postman!",
        "action": "action_a"
    }
    
  5. Selecione o botão Code, 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).

    Observação

    Se você estiver testando em Android certifique-se de que não está executando em de depuração , ou se o aplicativo foi implantado executando o aplicativo, force o fechamento do aplicativo e inicie-o novamente a partir do iniciador.

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

  8. De volta ao Postman, feche a janela Gerar trechos de código (se ainda não tiver feito isso) e clique no botão Enviar.

  9. Valide que você recebe 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 noPostman.

  11. Valide que você recebe uma resposta 200 OK em 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 que ela abre o aplicativo e exibiu o ação ActionA recebeu 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 a ação valor.

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

  15. Valide se você recebe uma resposta 200 OK no Postman e que o alerta aparece no aplicativo mostrando ação ActionB recebida em vez de ação ActionA recebida.

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

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

Solução de 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 usando a porta correta.

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

Certifique-se de verificar se você especificou o endereço base corretamente em Postman ou na configuração do aplicativo móvel ao testar através 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 parar uma sessão de depuração

Certifique-se de se registrar novamente depois de iniciar ou parar uma sessão de depuração. O depurador fará com que um novo token 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 de solicitação de apikey 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 definida na configuração do cliente corresponde ao valor de configuração do usuário Authentication:ApiKey usado pela 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 do aplicativo de Authentication:ApiKey que você está usando noAPI App .

Observação

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 a seção Autenticar clientes usando uma chave de API, certifique-se de não aplicar o atributo Authorize à classe NotificationsController.

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

Valide se o método de ponto de extremidade e solicitação HTTP está correto. Por exemplo, os parâmetros de avaliação devem ser, a título indicativo:

  • [PUT]https://<api_name>.azurewebsites.net/api/notifications/installations
  • [EXCLUIR]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
  • [EXCLUIR]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 da resposta Http definindo um ponto de interrupção para inspecionar o StatusCode valor da propriedade no HttpResponse.

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

Defina um ponto de interrupção nas linhas que retornam esses códigos de status específicos para a respetiva 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 do Postman usando a carga útil apropriada. Use a carga real criada pelo código do cliente para a plataforma em questão.

Revise as seções de configuração específicas da plataforma para garantir que nenhuma etapa tenha sido perdida. Verifique se os valores adequados estão sendo resolvidos para installation id e token variáveis para a plataforma apropriada.

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

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

Próximos passos

Agora você deve ter um aplicativo Flutter 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.

Você provavelmente precisará adaptar o exemplo usado neste tutorial para se adequar ao seu próprio cenário. A implementação de tratamento de erros mais robusto, lógica de repetição e registro em log também é recomendada.

do Visual Studio App Center podem ser rapidamente incorporados a aplicativos móveis fornecendo de análise e diagnósticos para ajudar na solução de problemas.