Codelab da Web do AngularFire

1. Visão geral

Neste codelab, você vai aprender a usar o AngularFire para criar aplicativos da Web implementando e implantando um cliente de chat com os produtos e serviços do Firebase.

Um aplicativo de bate-papo em que os usuários discutem o Firebase

O que você vai aprender

  • Criar um app da Web usando o Angular e o Firebase.
  • Sincronizar dados usando o Cloud Firestore e o Cloud Storage para Firebase.
  • Autenticar os usuários usando o Firebase Authentication.
  • Implantar seu app da Web no Firebase App Hosting.
  • Enviar notificações com o Firebase Cloud Messaging
  • Colete os dados de desempenho do seu app da Web.

Pré-requisitos

  • Uma conta no GitHub
  • A capacidade de fazer upgrade do seu projeto do Firebase para o plano de preços Blaze
  • O ambiente de desenvolvimento integrado/editor de texto que você preferir, como WebStorm, Sublime ou VS Code
  • O gerenciador de pacotes npm, que geralmente vem com o Node.js
  • Um terminal/console
  • Um navegador de sua escolha, como o Chrome
  • O exemplo de código do codelab. Consulte a próxima etapa para saber como acessar o código.

2. Acessar o exemplo de código

Crie um repositório do GitHub

O código-fonte do codelab pode ser encontrado em https://github.com/firebase/codelab-friendchat-web (link em inglês). O repositório contém projetos de amostra para várias plataformas. No entanto, este codelab usa apenas o diretório angularfire-start.

Copie a pasta angularfire-start para seu repositório:

  1. Usando um terminal, crie uma pasta no computador e acesse o novo diretório:
    mkdir codelab-friendlyeats-web
    
    cd codelab-friendlyeats-web
    
  2. Use o pacote npm giget para buscar apenas a pasta angularfire-start:
    npx giget@latest gh:firebase/codelab-friendlychat-web/angularfire-start#master . --install
    
  3. Acompanhe as mudanças localmente com o git:
    git init
    
    git add .
    
    git commit -m "codelab starting point"
    
    git branch -M main
    
  4. Crie um novo repositório do GitHub: https://github.com/new. Dê o nome que quiser.
    1. O GitHub vai fornecer um novo URL do repositório que se parece com https://github.com/[user-name]/[repository-name].git ou git@github.com:[user-name]/[repository-name].git. Copie este URL.
  5. Envie as alterações locais para o novo repositório do GitHub. Execute o comando a seguir, substituindo o URL do repositório pelo marcador your-repository-url.
    git remote add origin your-repository-url
    
    git push -u origin main
    
  6. O código inicial vai aparecer no seu repositório do GitHub.

3. Criar e configurar um projeto do Firebase

Criar um projeto do Firebase

  1. Faça login no console do Firebase.
  2. No console do Firebase, clique em Adicionar projeto e nomeie o projeto como FriendlyChat. Lembre-se do ID do projeto do Firebase.
  3. Desmarque a opção Ativar o Google Analytics para este projeto.
  4. Clique em Criar projeto.

O aplicativo que você vai criar usa produtos do Firebase disponíveis para apps da Web:

  • Firebase Authentication: permite que os usuários façam login no app com facilidade.
  • Cloud Firestore: é usado para salvar dados estruturados na nuvem e receber notificações instantâneas quando os dados são alterados.
  • Cloud Storage para Firebase: é usado para salvar arquivos na nuvem.
  • Firebase App Hosting para criar, hospedar e exibir o app.
  • Firebase Cloud Messaging: é usado para enviar notificações push e exibir notificações pop-up do navegador.
  • Monitoramento de desempenho do Firebase para coletar dados de performance do usuário do seu app.

Alguns desses produtos precisam de configuração especial ou precisam ser ativados usando o Console do Firebase.

Fazer upgrade do plano de preços do Firebase

Para usar o Firebase App Hosting e o Cloud Storage para Firebase, seu projeto do Firebase precisa estar no plano de preços pague conforme o uso (Blaze), ou seja, vinculado a uma conta do Cloud Billing.

  • Uma conta do Cloud Billing exige uma forma de pagamento, como cartão de crédito.
  • Se você ainda não conhece o Firebase e o Google Cloud, confira se tem qualificação para receber um crédito de US$ 300 e uma conta de teste gratuito do Cloud Billing.
  • Se você estiver fazendo este codelab como parte de um evento, pergunte ao organizador se há créditos do Cloud disponíveis.

Para fazer upgrade do seu projeto para o plano Blaze, siga estas etapas:

  1. No console do Firebase, selecione Fazer upgrade do seu plano.
  2. Selecione o plano Blaze. Siga as instruções na tela para vincular uma conta do Cloud Billing ao seu projeto.
    Se você precisou criar uma conta do Cloud Billing como parte desse upgrade, talvez seja necessário voltar ao fluxo de upgrade no console do Firebase para concluir o upgrade.

Adicionar um app da Web do Firebase ao projeto

  1. Clique no ícone da Web 58d6543a156e56f9.png para criar um app da Web do Firebase.
  2. Registre o app com o apelido Friendly Chat. Não marque a caixa ao lado de Também configurar o Firebase Hosting para este app. Clique em Registrar app.
  3. Na próxima etapa, você vai encontrar um objeto de configuração. Você não precisa dele agora. Clique em Continuar para o Console.

Captura de tela do registro do app da Web

Configurar o Authentication

Para permitir que os usuários façam login no app da Web com as Contas do Google deles, você usará o método de login do Google.

  1. No console do Firebase, navegue até Autenticação.
  2. Clique em Começar.
  3. Na coluna Outros provedores, clique em Google > Ativar.
  4. Na caixa de texto Nome voltado ao público do projeto, digite um nome fácil de lembrar, como My Next.js app.
  5. No menu suspenso E-mail de suporte do projeto, selecione seu endereço de e-mail.
  6. Clique em Salvar.

Configurar o Cloud Firestore

O app da Web usa o Cloud Firestore para salvar e receber novas mensagens de chat.

Confira como configurar o Cloud Firestore no seu projeto do Firebase:

  1. No painel esquerdo do Console do Firebase, expanda Build e selecione Banco de dados do Firestore.
  2. Clique em Criar banco de dados.
  3. Deixe o ID do banco de dados definido como (default).
  4. Selecione um local para o banco de dados e clique em Próxima.
    No caso de apps reais, escolha um local próximo aos usuários.
  5. Clique em Iniciar no modo de teste. Leia o aviso sobre as regras de segurança.
    Mais adiante neste codelab, você vai adicionar regras de segurança para proteger seus dados. Não distribua ou exponha um aplicativo publicamente sem adicionar regras de segurança ao seu banco de dados.
  6. Clique em Criar.

Configurar o Cloud Storage para Firebase

O app da Web usa o Cloud Storage para Firebase para armazenar, fazer upload e compartilhar fotos.

Confira como configurar o Cloud Storage para Firebase no seu projeto do Firebase:

  1. No painel esquerdo do Console do Firebase, abra Build e selecione Armazenamento.
  2. Clique em Começar.
  3. Selecione um local para o bucket padrão do Storage.
    Buckets em US-WEST1, US-CENTRAL1 e US-EAST1 podem aproveitar o nível "Sempre sem custo financeiro" do Google Cloud Storage. Os buckets em todos os outros locais seguem os preços e o uso do Google Cloud Storage.
  4. Clique em Iniciar no modo de teste. Leia o aviso sobre as regras de segurança.
    Mais adiante neste codelab, você vai adicionar regras de segurança para proteger seus dados. Não distribua ou exponha um aplicativo publicamente sem adicionar regras de segurança ao bucket do Storage.
  5. Clique em Criar.

4. Instalar a interface de linha de comando do Firebase

A interface de linha de comando (CLI) do Firebase permite usar o Firebase Hosting para disponibilizar seu app da Web localmente e implantar no projeto do Firebase.

  1. Instale a CLI executando o seguinte comando do npm:
npm -g install firebase-tools@latest
  1. Execute o comando a seguir para verificar se a CLI foi instalada corretamente:
firebase --version

A CLI do Firebase precisa estar na versão vv13.9.0 ou mais recente.

  1. Autorize a CLI do Firebase executando o seguinte comando:
firebase login

Você definiu o modelo de app da Web para receber a configuração do seu app para o Firebase Hosting do diretório local do app (o repositório que você clonou anteriormente no codelab). No entanto, para receber a configuração, você precisa associar seu app ao projeto do Firebase.

  1. Verifique se a linha de comando está acessando o diretório local angularfire-start do app.
  2. Associe o app ao projeto do Firebase executando o seguinte comando:
firebase use --add
  1. Quando solicitado, selecione o ID do projeto e atribua um alias ao projeto do Firebase.

Um alias será útil se você tiver vários ambientes (produção, preparo etc.). No entanto, neste codelab, vamos usar apenas o alias de default.

  1. Siga as instruções restantes na linha de comando.

5. Instalar o AngularFire

Antes de executar o projeto, verifique se você configurou o Angular CLI e o AngularFire.

  1. Em um console, execute o seguinte comando:
npm install -g @angular/cli
  1. Em seguida, em um console do diretório angularfire-start, execute o seguinte comando da CLI do Angular:
ng add @angular/fire

Isso vai instalar todas as dependências necessárias para o projeto.

  1. Quando solicitado, desmarque ng deploy -- hosting com a barra de espaço. Selecione os seguintes recursos com as teclas de seta e a barra de espaço:
    • Authentication
    • Firestore
    • Cloud Messaging
    • Cloud Storage
  2. Pressione enter e siga as instruções restantes.
  3. Crie um commit com a mensagem "Install AngularFire" e envie-o ao repositório do GitHub.

6. Criar um back-end do App Hosting

Nesta seção, você vai configurar um back-end do App Hosting para monitorar uma ramificação no seu repositório git.

Ao final desta seção, você terá um back-end de hospedagem de apps conectado ao seu repositório no GitHub. Ele vai recriar e lançar automaticamente uma nova versão do app sempre que você enviar uma nova confirmação para a ramificação main.

  1. Acesse a página "App Hosting" no console do Firebase:

Estado zero do console do App Hosting, com um botão "Começar"

  1. Clique em "Começar" para iniciar o fluxo de criação do back-end. Configure o back-end da seguinte maneira:
  2. Siga as instruções na primeira etapa para conectar o repositório do GitHub que você criou anteriormente.
  3. Defina as configurações de implantação:
    1. Manter o diretório raiz como /
    2. Definir a ramificação ativa como main
    3. Ativar os lançamentos automáticos
  4. Nomeie seu back-end como friendlychat-codelab.
  5. Em "Criar ou associar um app da Web do Firebase", escolha o app da Web que você configurou anteriormente no menu suspenso "Selecionar um app da Web atual do Firebase".
  6. Clique em "Concluir e implantar". Depois de um momento, você vai ser direcionado a uma nova página com o status do seu novo back-end do App Hosting.
  7. Quando o lançamento for concluído, clique no seu domínio sem custo financeiro em "domains". Isso pode levar alguns minutos para começar a funcionar devido à propagação do DNS.

Você implantou o app da Web inicial. Sempre que você enviar uma nova confirmação para a ramificação main do repositório do GitHub, um novo build e lançamento serão iniciados no console do Firebase, e seu site será atualizado automaticamente após a conclusão do lançamento.

Estado zero do console do App Hosting, com um botão "Começar"

Você verá a tela de login do app FriendlyChat, que (ainda) não está funcionando.

No momento, o app não pode fazer nada, mas com sua ajuda, isso vai mudar em breve.

Agora vamos criar um app de chat em tempo real.

7. Importar e configurar o Firebase

Configurar o Firebase

Você vai precisar configurar o SDK do Firebase para informar qual projeto do Firebase você está usando.

  1. Acesse as Configurações do projeto no Console do Firebase.
  2. No card "Seus apps", selecione o apelido do app em que você precisa de um objeto de configuração.
  3. Selecione "Config" no painel do snippet do SDK do Firebase.

Você verá que um arquivo de ambiente /angularfire-start/src/environments/environment.ts foi gerado.

  1. Copie o snippet do objeto de configuração e adicione-o a angularfire-start/src/firebase-config.js.

environment.ts

export const environment = {
  firebase: {
    apiKey: "API_KEY",
    authDomain: "PROJECT_ID.firebaseapp.com",
    projectId: "PROJECT_ID",
    storageBucket: "PROJECT_ID.firebasestorage.app",
    messagingSenderId: "SENDER_ID",
    appId: "APP_ID",
  },
};

Ver a configuração do AngularFire

Os recursos selecionados no console foram adicionados automaticamente ao arquivo /angularfire-start/src/app/app.config.ts. Isso permite que o app use os recursos e as funcionalidades do Firebase.

8. Configurar o login do usuário

O AngularFire agora está pronto para uso, porque foi importado e inicializado em app.config.ts. Agora você vai implementar o login do usuário com o Firebase Authentication.

Adicione um domínio autorizado

O Firebase Authentication só permite logins de uma lista definida de domínios controlados por você. Adicione o domínio de hospedagem de apps sem custo financeiro à lista de domínios:

  1. Navegue até App Hosting.
  2. Copie o domínio do seu back-end.
  3. Navegue até Configurações de autenticação.
  4. Escolha a guia Domínios autorizados.
  5. Clique em Adicionar domínio e cole o domínio do back-end do App Hosting.

Autenticar seus usuários com o Login do Google

No app, quando um usuário clica no botão Fazer login com o Google, a função login é acionada. Neste codelab, você vai autorizar o Firebase a usar o Google como provedor de identidade. Você vai usar um pop-up, mas vários outros métodos estão disponíveis no Firebase.

  1. No subdiretório /src/app/services/, abra chat.service.ts.
  2. Encontre a função login.
  3. Substitua a função inteira pelo código a seguir.

chat.service.ts

// Signs-in Friendly Chat.
login() {
    signInWithPopup(this.auth, this.provider).then((result) => {
        const credential = GoogleAuthProvider.credentialFromResult(result);
        this.router.navigate(['/', 'chat']);
        return credential;
    })
}

A função logout é acionada quando o usuário clica no botão Sair.

  1. Volte para o arquivo src/app/services/chat.service.ts.
  2. Encontre a função logout.
  3. Substitua a função inteira por este código:

chat.service.ts

// Logout of Friendly Chat.
logout() {
    signOut(this.auth).then(() => {
        this.router.navigate(['/', 'login'])
        console.log('signed out');
    }).catch((error) => {
        console.log('sign out error: ' + error);
    })
}

Acompanhar o estado de autenticação

Para atualizar nossa IU de acordo com isso, você precisa de uma maneira de verificar se o usuário está ou não conectado. O AngularFire oferece uma função para gerar um observável que é atualizado sempre que o estado de autenticação muda. Isso já foi implementado, mas vale a pena dar uma olhada.

  1. Volte para o arquivo src/app/services/chat.service.ts.
  2. Encontre a atribuição de variável user$.

chat.service.ts

// observable that is updated when the auth state changes
user$ = user(this.auth);

O código acima chama a função user do AngularFire, que retorna um usuário observável. Ele será acionado sempre que o estado de autenticação mudar (quando o usuário fizer login ou sair). Os componentes de modelos do Angular no FriendlyChat usam esse observável para atualizar a interface para redirecionar, exibir o usuário na navegação do cabeçalho e assim por diante.

Testar o login no app

  1. Crie uma confirmação com a mensagem "Adicionar autenticação do Google" e envie para o repositório do GitHub.
  2. Abra a página "Hospedagem de apps" no Console do Firebase e aguarde a conclusão do novo lançamento.
  3. No app da Web, atualize a página e faça login usando o botão de login e sua Conta do Google. Se você receber uma mensagem de erro informando auth/operation-not-allowed, verifique se ativou o Login do Google como provedor de autenticação no console do Firebase.
  4. Depois de fazer login, sua foto do perfil e o nome de usuário vão aparecer: angularfire-3.png

9. Grave mensagens no Cloud Firestore

Nesta seção, você vai gravar alguns dados no Cloud Firestore para preencher a IU do app. Isso pode ser feito manualmente com o Console do Firebase, mas você vai fazer isso no próprio app para demonstrar uma gravação básica do Cloud Firestore.

Modelo de dados

Os dados do Cloud Firestore são divididos em coleções, documentos, campos e subcoleções. Você armazenará cada mensagem do chat como um documento em uma coleção de nível superior chamada messages.

688d7bc5fb662b57.png

Adicionar mensagens ao Cloud Firestore

Para armazenar as mensagens de chat escritas pelos usuários, use o Cloud Firestore.

Nesta seção, você vai adicionar a funcionalidade para os usuários gravarem novas mensagens no seu banco de dados. Quando o usuário clica no botão ENVIAR, o snippet de código abaixo é acionado. Ele adiciona um objeto de mensagem com o conteúdo dos campos da mensagem à sua instância do Cloud Firestore na coleção messages. O método add() adiciona à coleção um novo documento com um ID gerado automaticamente.

  1. Volte para o arquivo src/app/services/chat.service.ts.
  2. Encontre a função addMessage.
  3. Substitua a função inteira pelo código a seguir.

chat.service.ts

// Adds a text or image message to Cloud Firestore.
addMessage = async (
  textMessage: string | null,
  imageUrl: string | null,
): Promise<void | DocumentReference<DocumentData>> => {
  // ignore empty messages
  if (!textMessage && !imageUrl) {
    console.log(
      "addMessage was called without a message",
      textMessage,
      imageUrl,
    );
    return;
  }

  if (this.currentUser === null) {
    console.log("addMessage requires a signed-in user");
    return;
  }

  const message: ChatMessage = {
    name: this.currentUser.displayName,
    profilePicUrl: this.currentUser.photoURL,
    timestamp: serverTimestamp(),
    uid: this.currentUser?.uid,
  };

  textMessage && (message.text = textMessage);
  imageUrl && (message.imageUrl = imageUrl);

  try {
    const newMessageRef = await addDoc(
      collection(this.firestore, "messages"),
      message,
    );
    return newMessageRef;
  } catch (error) {
    console.error("Error writing new message to Firebase Database", error);
    return;
  }
};

Teste o envio de mensagens

  1. Crie uma confirmação com a mensagem "Post new chats to Firestore" e a envie para seu repositório do GitHub.
  2. Abra a página "App Hosting" no Console do Firebase e aguarde a conclusão do novo lançamento.
  3. Atualize o FriendlyChat. Depois de fazer login, digite uma mensagem como "Olá!" e clique em ENVIAR. Isso vai gravar a mensagem no Cloud Firestore. No entanto, você ainda não verá os dados no seu app da Web real porque ainda será necessário implementar a recuperação dos dados (a próxima seção do codelab).
  4. Você pode ver a mensagem recém-adicionada no Console do Firebase. Abra a interface do Pacote de emuladores. Na seção Build, clique em Banco de dados do Firestore (ou clique aqui). Você vai encontrar a coleção messages com a mensagem recém-adicionada:

6812efe7da395692.png

10. Leia mensagens

Sincronizar mensagens

Para ler mensagens no app, adicione um observável que será acionado quando os dados mudarem e, em seguida, crie um elemento da interface que mostre novas mensagens.

Você vai adicionar um código que detecta mensagens recém-adicionadas do app. Nele, você vai recuperar o snapshot da coleção messages. Você vai mostrar apenas as últimas 12 mensagens do chat para evitar um histórico muito longo no carregamento.

  1. Volte para o arquivo src/app/services/chat.service.ts.
  2. Encontre a função loadMessages.
  3. Substitua a função inteira por este código:

chat.service.ts

// Loads chat message history and listens for upcoming ones.
loadMessages = () => {
  // Create the query to load the last 12 messages and listen for new ones.
  const recentMessagesQuery = query(collection(this.firestore, 'messages'), orderBy('timestamp', 'desc'), limit(12));
  // Start listening to the query.
  return collectionData(recentMessagesQuery);
}

Para detectar as mensagens no banco de dados, crie uma consulta em uma coleção. Use a função collection para especificar em qual coleção estão os dados que você quer detectar. No código acima, você está detectando as mudanças na coleção messages, onde as mensagens de chat são armazenadas. Você também está aplicando um limite detectando apenas as últimas 12 mensagens usando limit(12) e ordenando as mensagens por data usando orderBy('timestamp', 'desc') para receber as 12 mensagens mais recentes.

A função collectionData usa snapshots. A função de retorno de chamada será acionada quando houver alterações nos documentos que correspondam à consulta. Isso pode acontecer se uma mensagem for excluída, modificada ou adicionada. Leia mais sobre isso na documentação do Cloud Firestore.

Testar a sincronização de mensagens

  1. Crie uma confirmação com a mensagem "Mostrar novos chats na interface" e envie para o repositório do GitHub.
  2. Abra a página "Hospedagem de apps" no Console do Firebase e aguarde a conclusão do novo lançamento.
  3. Atualize o FriendlyChat. As mensagens que você criou anteriormente no banco de dados serão exibidas na interface do FriendlyChat (confira abaixo). Sinta-se à vontade para escrever novas mensagens; elas devem aparecer instantaneamente.
  4. (Opcional) Tente excluir, modificar ou adicionar manualmente novas mensagens diretamente na seção Firestore do pacote do Emulator. As alterações vão aparecer na interface.

Parabéns! Você está lendo documentos do Cloud Firestore no seu app.

angularfire-2.png

11. Adicionar recursos de IA

Você vai usar a IA do Google para adicionar recursos de assistência úteis ao app de chat.

Gerar uma chave de API da IA do Google

  1. Acesse o Google AI Studio e clique em Criar chave de API.
  2. Selecione o projeto do Firebase que você criou para este codelab. O comando é referente a um projeto do Google Cloud, mas todo projeto do Firebase é um projeto do Google Cloud.
  3. Clique em Criar chave de API em um projeto atual.
  4. Copie a chave de API resultante

Instalar uma extensão

Esta extensão implantará uma função do Cloud que é acionada sempre que um novo documento for adicionado à coleção messages no Firestore. A função vai chamar o Gemini e gravar a resposta no campo response do documento.

  1. Clique em Instalar no console do Firebase na página de extensão Criar um chatbot com a API Gemini.
  2. Siga as instruções. Na etapa Configurar extensão, defina os seguintes valores de parâmetro:
    • Provedor da API Gemini: Google AI
    • Chave de API da IA do Google: cole a chave que você criou anteriormente e clique em Criar secret.
    • Caminho da coleção do Firestore: messages
    • Campo de comando: text
    • Campo de resposta: response
    • Campo do pedido: timestamp
    • Contexto: Keep your answers short, informal, and helpful. Use emojis when possible.
  3. Clique em Instalar extensão.
  4. Aguarde a instalação da extensão.

Testar o recurso de IA

O FriendlyChat já tem um código para ler respostas da extensão de IA. Basta enviar uma nova mensagem de chat para testar.

  1. Abra o FriendlyChat e envie uma mensagem.
  2. Depois de um momento, uma resposta vai aparecer ao lado da sua mensagem. Ela tem uma observação ✨ ai generated no final para deixar claro que foi criada com IA generativa, não por um usuário real.

12. Enviar imagens

Agora você vai adicionar um recurso de compartilhamento de imagens.

O Cloud Firestore é bom para armazenar dados estruturados, mas o Cloud Storage é mais adequado para arquivos. O Cloud Storage para Firebase é um serviço de armazenamento de arquivos/blobs para armazenar todas as imagens compartilhadas por um usuário por meio do nosso app.

Salve imagens no Cloud Storage

Para este codelab, você já adicionou um botão que aciona uma caixa de diálogo do seletor de arquivos. Depois que um arquivo é selecionado, a função saveImageMessage é chamada, e você pode receber uma referência do arquivo selecionado. A função saveImageMessage faz o seguinte:

  1. Cria uma mensagem de chat como um "marcador" no feed de chat para que os usuários vejam uma animação "Carregando" enquanto você faz upload da imagem.
  2. Faz upload do arquivo de imagem no Cloud Storage para este caminho: /<uid>/<file_name>
  3. gera um URL legível publicamente para o arquivo de imagem;
  4. atualiza a mensagem de chat com o URL do arquivo de imagem recém-enviado no lugar da imagem temporária de carregamento.

Agora você vai adicionar a funcionalidade de enviar uma imagem:

  1. Volte para o arquivo src/chat.service.ts.
  2. Encontre a função saveImageMessage.
  3. Substitua a função inteira por este código:

chat.service.ts (link em inglês)

// Saves a new message containing an image in Firestore.
// This first saves the image in Firebase storage.
saveImageMessage = async(file: any) => {
  try {
    // 1 - Add a message with a loading icon that will get updated with the shared image.
    const messageRef = await this.addMessage(null, this.LOADING_IMAGE_URL);

    // 2 - Upload the image to Cloud Storage.
    const filePath = `${this.auth.currentUser?.uid}/${file.name}`;
    const newImageRef = ref(this.storage, filePath);
    const fileSnapshot = await uploadBytesResumable(newImageRef, file);

    // 3 - Generate a public URL for the file.
    const publicImageUrl = await getDownloadURL(newImageRef);

    // 4 - Update the chat message placeholder with the image's URL.
    messageRef ?
    await updateDoc(messageRef, {
      imageUrl: publicImageUrl,
      storageUri: fileSnapshot.metadata.fullPath
    }): null;
  } catch (error) {
    console.error('There was an error uploading a file to Cloud Storage:', error);
  }
}

Teste o envio de imagens

  1. Crie uma confirmação com a mensagem "Adicione a capacidade de postar imagens" e a envie por push ao repositório do GitHub.
  2. Abra a página "App Hosting" no Console do Firebase e aguarde a conclusão do novo lançamento.
  3. Atualize o FriendlyChat. Depois de fazer login, clique no botão de upload de imagem no canto inferior esquerdo angularfire-4.png e selecione um arquivo de imagem usando o seletor de arquivos. Se você está procurando uma imagem, sinta-se à vontade para usar esta boa foto de uma xícara de café.
  4. Uma nova mensagem vai aparecer na interface do app com a imagem selecionada: angularfire-2.png

Se você tentar adicionar uma imagem sem fazer login, vai aparecer um erro informando que é necessário fazer login para adicionar imagens.

13. Mostrar notificações

Agora você vai adicionar suporte às notificações do navegador. O app vai notificar os usuários quando novas mensagens forem postadas no chat. O Firebase Cloud Messaging (FCM) é uma solução de mensagens entre plataformas que permite a entrega confiável de mensagens e notificações sem custos.

Adicionar o service worker do FCM

O app da Web precisa de um service worker que receba e mostre as notificações da Web.

O provedor de mensagens já deveria ter sido configurado quando o AngularFire foi adicionado. Verifique se o código a seguir existe na seção de importações do /angularfire-start/src/app/app.config.ts.

provideMessaging(() => {
    return getMessaging();
}),

app/app.config.ts

O service worker simplesmente precisa carregar e inicializar o SDK do Firebase Cloud Messaging, que é responsável por mostrar as notificações.

Acessar os tokens de dispositivo do FCM

Quando as notificações são ativadas em um dispositivo ou navegador, você recebe um token de dispositivo. Esse token é usado para enviar uma notificação a um dispositivo ou navegador específico.

Quando o usuário faz login, você chama a função saveMessagingDeviceToken. É para isso que você receberá o token do dispositivo do FCM do navegador e o salvará no Cloud Firestore.

chat.service.ts

  1. Encontre a função saveMessagingDeviceToken.
  2. Substitua a função inteira por este código:

chat.service.ts

// Saves the messaging device token to Cloud Firestore.
saveMessagingDeviceToken= async () => {
    try {
      const currentToken = await getToken(this.messaging);
      if (currentToken) {
        console.log('Got FCM device token:', currentToken);
        // Saving the Device Token to Cloud Firestore.
        const tokenRef = doc(this.firestore, 'fcmTokens', currentToken);
        await setDoc(tokenRef, { uid: this.auth.currentUser?.uid });
 
        // This will fire when a message is received while the app is in the foreground.
        // When the app is in the background, firebase-messaging-sw.js will receive the message instead.
        onMessage(this.messaging, (message) => {
          console.log(
            'New foreground notification from Firebase Messaging!',
            message.notification
          );
        });
      } else {
        // Need to request permissions to show notifications.
        this.requestNotificationsPermissions();
      }
    } catch(error) {
      console.error('Unable to get messaging token.', error);
    };
}

No entanto, esse código não vai funcionar inicialmente. Para que o app consiga recuperar o token do dispositivo, o usuário precisa conceder ao app a permissão para mostrar notificações (a próxima etapa do codelab).

Solicitar permissões para mostrar notificações

Quando o usuário ainda não concedeu ao app a permissão para mostrar notificações, você não vai receber um token do dispositivo. Nesse caso, você chama o método requestPermission(), que exibe uma caixa de diálogo solicitando essa permissão ( em navegadores compatíveis).

8b9d0c66dc36153d.png

  1. Volte para o arquivo src/app/services/chat.service.ts.
  2. Encontre a função requestNotificationsPermissions.
  3. Substitua a função inteira por este código:

chat.service.ts

// Requests permissions to show notifications.
requestNotificationsPermissions = async () => {
    console.log('Requesting notifications permission...');
    const permission = await Notification.requestPermission();
    
    if (permission === 'granted') {
      console.log('Notification permission granted.');
      // Notification permission granted.
      await this.saveMessagingDeviceToken();
    } else {
      console.log('Unable to get permission to notify.');
    }
}

Acessar o token do dispositivo

  1. Crie uma confirmação com a mensagem "Adicionar a capacidade de postar imagens" e envie para o repositório do GitHub.
  2. Abra a página "App Hosting" no Console do Firebase e aguarde a conclusão do novo lançamento.
  3. Atualize o FriendlyChat. Depois de fazer login, a caixa de diálogo de permissão de notificações vai aparecer: bd3454e6dbfb6723.png
  4. Clique em Permitir.
  5. Abra o console JavaScript do seu navegador. A seguinte mensagem vai aparecer: Got FCM device token: cWL6w:APA91bHP...4jDPL_A-wPP06GJp1OuekTaTZI5K2Tu
  6. Copie o token do dispositivo. Você vai precisar dele na próxima etapa do codelab.

Enviar uma notificação para o dispositivo

Agora que você tem o token do dispositivo, pode enviar uma notificação.

  1. Abra a guia Cloud Messaging no Console do Firebase.
  2. Clique em "Nova notificação".
  3. Insira um título e um texto de notificação.
  4. No lado direito da tela, clique em "Enviar uma mensagem de teste"
  5. Insira o token do dispositivo copiado do console JavaScript do navegador e clique no sinal de adição ("+").
  6. Clique em "Testar".

Se o app estiver em primeiro plano, você verá a notificação no Console JavaScript.

Se o app estiver em segundo plano, uma notificação vai aparecer no navegador, como neste exemplo:

de79e8638a45864c.png

14. Regras de segurança do Cloud Firestore

Conferir as regras de segurança do banco de dados

O Cloud Firestore usa uma linguagem de regras específica para definir direitos de acesso, segurança e validações de dados.

Ao configurar o projeto do Firebase no início deste codelab, você optou por usar as regras de segurança padrão do "Modo de teste" para não restringir o acesso ao repositório de dados. No Console do Firebase, na guia Regras da seção Banco de dados, é possível visualizar e modificar essas regras.

No momento, você vai ver as regras padrão, que não restringem o acesso ao repositório de dados. Isso significa que qualquer usuário pode ler e gravar em qualquer coleção no seu repositório de dados.

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write;
    }
  }
}

Você vai atualizar as regras para restringir as coisas usando as seguintes regras:

firestore.rules (em inglês)

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    // Messages:
    //   - Anyone can read.
    //   - Authenticated users can add and edit messages.
    //   - Validation: Check name is same as auth token and text length below 300 char or that imageUrl is a URL.
    //   - Deletes are not allowed.
    match /messages/{messageId} {
      allow read;
      allow create, update: if request.auth != null
                    && request.resource.data.name == request.auth.token.name
                    && (request.resource.data.text is string
                      && request.resource.data.text.size() <= 300
                      || request.resource.data.imageUrl is string
                      && request.resource.data.imageUrl.matches('https?://.*'));
      allow delete: if false;
    }
    // FCM Tokens:
    //   - Anyone can write their token.
    //   - Reading list of tokens is not allowed.
    match /fcmTokens/{token} {
      allow read: if false;
      allow write;
    }
  }
}

As regras de segurança serão atualizadas automaticamente no pacote do emulador.

Veja as regras de segurança do Cloud Storage

O Cloud Storage para Firebase usa uma linguagem de regras específica para definir direitos de acesso, segurança e validações de dados.

Ao configurar o projeto do Firebase no início deste codelab, você optou por usar a regra de segurança padrão do Cloud Storage, que permite o uso do Cloud Storage somente por usuários autenticados. No Console do Firebase, na guia Regras da seção Armazenamento, é possível visualizar e modificar as regras. Você verá a regra padrão que permite que qualquer usuário conectado leia e grave qualquer arquivo no seu bucket de armazenamento.

rules_version = '2';

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if request.auth != null;
    }
  }
}

Você atualizará as regras para fazer o seguinte:

  • Permitir que cada usuário grave apenas em suas próprias pastas específicas
  • Permitir que qualquer pessoa faça leituras no Cloud Storage
  • verificar se os arquivos enviados são imagens;
  • Restringir o tamanho das imagens que podem ser enviadas a, no máximo, 5 MB.

Isso pode ser implementado usando as seguintes regras:

storage.rules

rules_version = '2';

// Returns true if the uploaded file is an image and its size is below the given number of MB.
function isImageBelowMaxSize(maxSizeMB) {
  return request.resource.size < maxSizeMB * 1024 * 1024
      && request.resource.contentType.matches('image/.*');
}

service firebase.storage {
  match /b/{bucket}/o {
    match /{userId}/{messageId}/{fileName} {
      allow write: if request.auth != null && request.auth.uid == userId && isImageBelowMaxSize(5);
      allow read;
    }
  }
}

15. Parabéns!

Você usou o Firebase para criar um aplicativo da Web para bate-papo em tempo real.

Conteúdo abordado

  • Firebase App Hosting
  • Firebase Authentication
  • Cloud Firestore
  • Firebase SDK para Cloud Storage
  • Firebase Cloud Messaging
  • Monitoramento de desempenho do Firebase

Próximas etapas

Saiba mais

16. [Opcional] Aplicar com o App Check

O App Check do Firebase ajuda a proteger seus serviços contra tráfego indesejado e protege seu back-end contra abuso. Nesta etapa, você vai adicionar a validação de credenciais e bloquear clientes não autorizados com o App Check e o reCAPTCHA Enterprise.

Primeiro, ative o App Check e o reCAPTCHA.

Como ativar o reCAPTCHA Enterprise

  1. No console do Cloud, encontre e selecione reCAPTCHA Enterprise em "Segurança".
  2. Ative o serviço quando solicitado e clique em Criar chave.
  3. Insira um nome de exibição conforme solicitado e selecione Site como o tipo de plataforma.
  4. Adicione os URLs implantados à lista de domínios e verifique se a opção "Usar desafio da caixa de seleção" está desmarcada.
  5. Clique em Criar chave e armazene a chave gerada em algum lugar para protegê-la. Você vai precisar dele mais tarde nesta etapa.

Como ativar o App Check

  1. No Console do Firebase, localize a seção Build no painel à esquerda.
  2. Clique em Verificação de app e na guia Método de login para acessar a Verificação de app.
  3. Clique em Register e digite sua chave reCAPTCHA Enterprise quando solicitado e clique em Save.
  4. Na visualização "APIs", selecione Armazenamento e clique em Aplicar. Faça o mesmo para o Cloud Firestore.

O App Check agora é obrigatório. Atualize o app e tente visualizar ou enviar mensagens de chat. Você vai receber a seguinte mensagem de erro:

Uncaught Error in snapshot listener: FirebaseError: [code=permission-denied]: Missing or insufficient permissions.

Isso significa que o App Check está bloqueando solicitações não validadas por padrão. Agora, vamos adicionar a validação ao app.

Navegue até o arquivo environment.ts e adicione reCAPTCHAEnterpriseKey ao objeto environment.

export const environment = {
  firebase: {
    apiKey: 'API_KEY',
    authDomain: 'PROJECT_ID.firebaseapp.com',
    databaseURL: 'https://PROJECT_ID.firebaseio.com',
    projectId: 'PROJECT_ID',
    storageBucket: 'PROJECT_ID.firebasestorage.app',
    messagingSenderId: 'SENDER_ID',
    appId: 'APP_ID',
    measurementId: 'G-MEASUREMENT_ID',
  },
  reCAPTCHAEnterpriseKey: {
    key: "Replace with your recaptcha enterprise site key"
  },
};

Substitua o valor de key pelo seu token reCAPTCHA Enterprise.

Em seguida, navegue até o arquivo app.config.ts e adicione as seguintes importações:

import { getApp } from '@angular/fire/app';
import {
  ReCaptchaEnterpriseProvider,
  initializeAppCheck,
  provideAppCheck,
} from '@angular/fire/app-check';

No mesmo arquivo app.config.ts, adicione a seguinte declaração de variável global:

declare global {
  var FIREBASE_APPCHECK_DEBUG_TOKEN: boolean;
}

@NgModule({ ...

Nas importações, adicione a inicialização do App Check com ReCaptchaEnterpriseProvider e defina isTokenAutoRefreshEnabled como true para permitir que os tokens sejam atualizados automaticamente.

imports: [
BrowserModule,
AppRoutingModule,
CommonModule,
FormsModule,
provideFirebaseApp(() => initializeApp(environment.firebase)),
provideAppCheck(() => {
const appCheck = initializeAppCheck(getApp(), {
  provider: new ReCaptchaEnterpriseProvider(
  environment.reCAPTCHAEnterpriseKey.key
  ),
  isTokenAutoRefreshEnabled: true,
  });
  if (location.hostname === 'localhost') {
    self.FIREBASE_APPCHECK_DEBUG_TOKEN = true;
  }
  return appCheck;
}),

Para permitir testes locais, defina self.FIREBASE_APPCHECK_DEBUG_TOKEN como true. Quando você atualizar o app no localhost, isso vai registrar um token de depuração no console semelhante a este:

App Check debug token: CEFC0C76-7891-494B-B764-349BDFD00D00. You will need to add it to your app's App Check settings in the Firebase console for it to work.

Agora, acesse a Visualização de apps do App Check no console do Firebase.

Clique no menu de contexto e selecione Gerenciar tokens de depuração.

Em seguida, clique em Adicionar token de depuração e cole o token do console quando solicitado.

Navegue até o arquivo chat.service.ts e adicione a seguinte importação:

import { AppCheck } from '@angular/fire/app-check';

No mesmo arquivo chat.service.ts, injete o App Check com os outros serviços do Firebase.

export class ChatService {
appCheck: AppCheck = inject(AppCheck);
...
  1. Crie uma confirmação com a mensagem "Bloquear clientes não autorizados com o App Check" e a envie por push ao repositório do GitHub.
  2. Abra a página "Hospedagem de apps" no Console do Firebase e aguarde a conclusão do novo lançamento.

Parabéns! Agora, o App Check deve estar funcionando no seu app.