Codelab da Web do AngularFire

1. Visão geral

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

angularfire-2.png

Conteúdo

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

Pré-requisitos

  • O ambiente de desenvolvimento integrado/editor de texto que você escolher, como WebStorm, Atom, Sublime ou VS Code
  • O npm do gerenciador de pacotes, que normalmente vem com o Node.js
  • Um terminal/console
  • em um navegador da 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

Clone o repositório do GitHub do codelab na linha de comando:

git clone https://github.com/firebase/codelab-friendlychat-web

Se você não tiver o git instalado, faça o download do repositório como um arquivo ZIP (link em inglês).

Importar o app inicial

Usando seu ambiente de desenvolvimento integrado, abra ou importe o diretório 📁 angularfire-start do repositório clonado. Esse diretório 📁 angularfire-start contém o código inicial do codelab, que será um app da Web de chat totalmente funcional.

3. Criar e configurar um projeto do Firebase

Criar um projeto do Firebase

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

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

  • Firebase Authentication: usado para permitir que os usuários façam login no seu 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 Hosting: é usado para hospedar e exibir seus recursos.
  • 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 desempenho do usuário para seu app.

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

Adicionar um app da Web do Firebase ao projeto

  1. Clique no ícone da Web 58d6543a156e56f9.png para criar um novo app da Web do Firebase.
  2. Registre o app com o apelido Friendly Chat e 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ê verá um objeto de configuração. Copie apenas o objeto JS (não o HTML circundante) para o arquivo firebase-config.js

Captura de tela do registro do app da Web

Ative o Login do Google para o Firebase Authentication.

Para permitir que os usuários façam login no app da Web com as próprias Contas do Google, use o método de login do Google.

Será necessário ativar o login do Google:

  1. No Console do Firebase, localize a seção Build no painel esquerdo.
  2. Clique em Autenticação e na guia Método de login (ou clique aqui para acessá-la).
  3. Ative o provedor de login do Google e clique em Salvar.
  4. Defina o nome público do app como Friendly Chat e escolha um E-mail de suporte do projeto no menu suspenso.
  5. Configure a tela de permissão OAuth no Console do Google Cloud e adicione um logotipo:

d89fb3873b5d36ae.png

Ativar o Cloud Firestore

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

Será necessário ativar o Cloud Firestore:

  1. Na seção Build do Console do Firebase, clique em Firestore Database.
  2. Clique em Criar banco de dados no painel do Cloud Firestore.

729991a081e7cd5.png

  1. Selecione a opção Iniciar no modo de teste e clique em Próxima depois de ler a exoneração de responsabilidade sobre as regras de segurança.

O modo de teste garante que você possa gravar livremente no banco de dados durante o desenvolvimento. Você vai deixar nosso banco de dados mais seguro mais adiante neste codelab.

77e4986cbeaf9dee.png

  1. Defina o local em que os dados do Cloud Firestore são armazenados. Mantenha essa configuração como padrão ou escolha uma região próxima a você. Clique em Concluído para provisionar o Firestore.

9f2bb0d4e7ca49c7.png

Ativar o Cloud Storage

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

Será necessário ativar o Cloud Storage:

  1. Na seção Build do Console do Firebase, clique em Armazenamento.
  2. Se o botão Começar não estiver disponível, isso significa que o Cloud Storage já está ativado e você não precisa seguir as etapas abaixo.
  3. Clique em Começar.
  4. Leia a exoneração de responsabilidade sobre as regras de segurança do seu projeto do Firebase e clique em Próxima.

Com as regras de segurança padrão, qualquer usuário autenticado pode gravar o que quiser no Cloud Storage. Você vai tornar nosso armazenamento mais seguro mais adiante neste codelab.

62f1afdcd1260127.png

  1. O local do Cloud Storage é pré-selecionado com a mesma região que você escolheu para seu banco de dados do Cloud Firestore. Clique em Concluído para finalizar a configuração.

1d7f49ebaddb32fc.png

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 implantá-lo no projeto do Firebase.

  1. Instale a CLI executando o seguinte comando npm:
npm -g install firebase-tools
  1. Verifique se a CLI foi instalada corretamente executando o seguinte comando:
firebase --version

Verifique se a versão da CLI do Firebase é a v4.1.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 extrair a configuração do app para o Firebase Hosting do diretório local dele (o repositório clonado anteriormente no codelab). No entanto, para extrair a configuração, é necessário associar o app ao projeto do Firebase.

  1. Confira 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 a ele.

Um alias é útil quando você tem vários ambientes (produção, preparo etc). No entanto, para este 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ê tem a CLI do Angular e o AngularFire configurados.

  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 instalará todas as dependências necessárias para o projeto.

  1. Quando solicitado, selecione os recursos que foram configurados no Console do Firebase (ng deploy -- hosting, Authentication, Firestore, Cloud Functions (callable), Cloud Messaging, Cloud Storage) e siga as instruções.

6. Executar o app inicial localmente

Agora que você importou e configurou seu projeto, está pronto para executar o app da Web pela primeira vez.

  1. Em um console do diretório angularfire-start, execute o seguinte comando da CLI do Firebase:
firebase emulators:start
  1. A linha de comando vai exibir a seguinte resposta:
✔  hosting: Local server: http://localhost:5000

Você está usando o emulador do Firebase Hosting para disponibilizar nosso app localmente. Agora o app da Web estará disponível em http://localhost:5000. Todos os arquivos localizados no subdiretório src serão exibidos.

  1. Usando o navegador, abra o aplicativo em http://localhost:5000.

Você verá a interface do seu app FriendlyChat, que (ainda) não está funcionando:

angularfire-2.png

O app não pode fazer nada no momento, mas com sua ajuda, ele fará isso em breve. Você só disponibilizou a interface até o momento.

Agora, vamos criar um chat em tempo real.

7. Importar e configurar o Firebase

Configurar o Firebase

Você precisará configurar o SDK do Firebase para informar o projeto que está sendo usado.

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

Você verá que o 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",
    databaseURL: "https://PROJECT_ID.firebaseio.com",
    projectId: "PROJECT_ID",
    storageBucket: "PROJECT_ID.appspot.com",
    messagingSenderId: "SENDER_ID",
    appId: "APP_ID",
    measurementId: "G-MEASUREMENT_ID",
  },
};

Importar o AngularFire

Os recursos selecionados no console foram roteados automaticamente no arquivo /angularfire-start/src/app/app.module.ts. Isso permite que o app use os recursos e as funcionalidades do Firebase. No entanto, para desenvolver em um ambiente local, você precisa conectá-los para usar o Pacote de emuladores.

  1. Em /angularfire-start/src/app/app.module.ts, encontre a seção imports e modifique as funções fornecidas para se conectar ao Pacote de emuladores em ambientes que não sejam de produção.
// ...

import { provideAuth,getAuth, connectAuthEmulator } from '@angular/fire/auth';
import { provideFirestore,getFirestore, connectFirestoreEmulator } from '@angular/fire/firestore';
import { provideFunctions,getFunctions, connectFunctionsEmulator } from '@angular/fire/functions';
import { provideMessaging,getMessaging } from '@angular/fire/messaging';
import { provideStorage,getStorage, connectStorageEmulator } from '@angular/fire/storage';

// ...

provideFirebaseApp(() => initializeApp(environment.firebase)),
provideAuth(() => {
    const auth = getAuth();
    if (location.hostname === 'localhost') {
        connectAuthEmulator(auth, 'http://127.0.0.1:9099', { disableWarnings: true });
    }
    return auth;
}),
provideFirestore(() => {
    const firestore = getFirestore();
    if (location.hostname === 'localhost') {
        connectFirestoreEmulator(firestore, '127.0.0.1', 8080);
    }
    return firestore;
}),
provideFunctions(() => {
    const functions = getFunctions();
    if (location.hostname === 'localhost') {
        connectFunctionsEmulator(functions, '127.0.0.1', 5001);
    }
    return functions;
}),
provideStorage(() => {
    const storage = getStorage();
    if (location.hostname === 'localhost') {
        connectStorageEmulator(storage, '127.0.0.1', 5001);
    }
    return storage;
}),
provideMessaging(() => {
    return getMessaging();
}),

// ...

app.module.ts

Durante este codelab, você usará o Firebase Authentication, Cloud Firestore, Cloud Storage, Cloud Messaging e Monitoramento de desempenho. Por isso, você está importando todas as bibliotecas deles. Nos próximos apps, verifique se está importando apenas as partes do Firebase de que precisa para reduzir o tempo de carregamento do app.

8. Configurar o login do usuário

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

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. Isso já foi configurado. Neste codelab, você quer autorizar o Firebase a usar o Google como provedor de identidade. Você usará um pop-up, mas há vários outros métodos disponíveis no Firebase.

  1. No diretório angularfire-start, 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 Logout.

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

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

Rastrear o estado da autenticação

Para atualizar nossa IU de forma adequada, você precisa de uma maneira de verificar se o usuário está conectado ou desconectado. Com o Firebase Authentication, você pode recuperar o estado do usuário que será acionado sempre que o estado da autenticação mudar.

  1. Volte para o arquivo src/app/services/chat.service.ts.
  2. Encontre a atribuição de variável user$.
  3. Substitua toda a atribuição pelo código a seguir.

chat.service.ts

// Observable user
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). Nesse ponto, você vai atualizar a interface para redirecionar, mostrar o usuário na navegação do cabeçalho e assim por diante. Todas essas partes da interface já foram implementadas.

Testar a geração de login no app

  1. Se o aplicativo ainda estiver sendo veiculado, atualize-o no navegador. Caso contrário, execute firebase emulators:start na linha de comando para começar a exibir o app em http://localhost:5000 e abra-o no navegador.
  2. Faça login no app usando o botão de login e sua Conta do Google. Se você receber a mensagem de erro auth/operation-not-allowed, verifique se ativou o Login do Google como um provedor de autenticação no Console do Firebase.
  3. 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 interface do app. Isso pode ser feito manualmente com o Console do Firebase, mas você fará 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 de 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>> => {
    let data: any;
    try {
      this.user$.subscribe(async (user) => 
      { 
        if(textMessage && textMessage.length > 0) {
          data =  await addDoc(collection(this.firestore, 'messages'), {
            name: user?.displayName,
            text: textMessage,
            profilePicUrl: user?.photoURL,
            timestamp: serverTimestamp(),
            uid: user?.uid
          })}
          else if (imageUrl && imageUrl.length > 0) {
            data =  await addDoc(collection(this.firestore, 'messages'), {
              name: user?.displayName,
              imageUrl: imageUrl,
              profilePicUrl: user?.photoURL,
              timestamp: serverTimestamp(),
              uid: user?.uid
            });
          }
          return data;
        }
      );
    }
    catch(error) {
      console.error('Error writing new message to Firebase Database', error);
      return;
    }
}

Testar o envio de mensagens

  1. Se o aplicativo ainda estiver sendo veiculado, atualize-o no navegador. Caso contrário, execute firebase emulators:start na linha de comando para começar a exibir o app em http://localhost:5000 e abra-o no navegador.
  2. Depois de fazer login, digite uma mensagem como "Olá!" e clique em ENVIAR. Isso gravará a mensagem no Cloud Firestore. No entanto, você ainda não verá os dados no seu app da Web real porque ainda precisa implementar a recuperação dos dados (a próxima seção do codelab).
  3. 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 aqui para ver a coleção messages com a mensagem recém-adicionada:

6812efe7da395692.png

10. Leia mensagens

Sincronizar mensagens

Para ler mensagens no app, adicione um elemento 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 ouve mensagens recém-adicionadas do app. Nesse código, você vai recuperar o snapshot da coleção messages. Só serão mostradas as últimas 12 mensagens do chat para evitar que o histórico seja muito longo durante o carregamento.

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

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 mensagens no banco de dados, crie uma consulta em uma coleção usando 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, que é onde as mensagens de chat são armazenadas. Você também vai aplicar um limite detectando apenas as últimas 12 mensagens usando limit(12) e ordenando as mensagens por data usando orderBy('timestamp', 'desc') para extrair as 12 mensagens mais recentes.

A função collectionData usa snapshots em segundo plano. A função de retorno de chamada será acionada quando houver alterações nos documentos que correspondam à consulta. Isso pode acontecer quando uma mensagem é excluída, modificada ou adicionada. Leia a documentação do Cloud Firestore para mais informações.

Testar a sincronização de mensagens

  1. Se o aplicativo ainda estiver sendo veiculado, atualize-o no navegador. Caso contrário, execute firebase emulators:start na linha de comando para começar a exibir o app em http://localhost:5000 e abra-o no navegador.
  2. As mensagens que você criou anteriormente no banco de dados devem ser exibidas na interface do FriendlyChat (confira abaixo). Fique à vontade para escrever novas mensagens, elas serão exibidas instantaneamente.
  3. (Opcional) Você pode tentar excluir, modificar ou adicionar manualmente novas mensagens diretamente na seção Firestore do Pacote de emuladores. Todas as alterações devem ser refletidas na interface.

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

angularfire-2.png

11. Enviar imagens

Agora você vai adicionar um recurso que compartilha imagens.

Embora o Cloud Firestore seja bom para armazenar dados estruturados, o Cloud Storage é mais adequado para armazenar arquivos. O Cloud Storage para Firebase é um serviço de armazenamento de arquivos/blobs. Ele é usado para armazenar imagens compartilhadas por um usuário com nosso app.

Salve imagens no Cloud Storage

Neste codelab, você já adicionou um botão que aciona uma caixa de diálogo do seletor de arquivos. Depois de selecionar um arquivo, a função saveImageMessage é chamada, e você pode acessar uma referência ao arquivo selecionado. A função saveImageMessage realiza as seguintes tarefas:

  1. cria uma mensagem de chat com um "marcador de posição" 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 neste 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 em vez da imagem de carregamento temporária.

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 pelo código a seguir.

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

// Saves a new message containing an image in Firebase.
// This first saves the image in Firebase storage.
saveImageMessage = async(file: any) => {
  try {
    // 1 - You 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);
  }
}

Testar o envio de imagens

  1. Se o aplicativo ainda estiver sendo veiculado, atualize-o no navegador. Caso contrário, execute firebase emulators:start na linha de comando para começar a exibir o app em http://localhost:5000 e abra-o no navegador.
  2. Depois de fazer login, clique no botão de upload de imagem no canto inferior esquerdo angularfire-4.png e escolha um arquivo de imagem usando o seletor de arquivos. Se você está procurando uma imagem, sinta-se à vontade para usar esta linda foto de uma xícara de café.
  3. Uma nova mensagem vai aparecer na interface do app com a imagem selecionada: angularfire-2.png.

Se você tentar adicionar uma imagem sem ter feito login, vai receber uma mensagem de erro informando que é preciso fazer login.

12. Mostrar notificações

Agora você vai adicionar suporte a notificações do navegador. O app 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 exiba notificações da Web.

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

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

app/app.module.ts

O service worker só precisa carregar e inicializar o SDK do Firebase Cloud Messaging, que vai se encarregar de mostrar as notificações.

Receber tokens de dispositivos do FCM

Quando as notificações forem ativadas em um dispositivo ou navegador, você receberá um token de dispositivo. Esse token de dispositivo é o que você usa para enviar uma notificação a um dispositivo ou navegador específico.

Quando o usuário fizer login, você chamará a função saveMessagingDeviceToken. É nesse local que você vai receber o token do dispositivo do FCM do navegador e salvá-lo no Cloud Firestore.

chat.service.ts

  1. Encontre a função saveMessagingDeviceToken.
  2. Substitua a função inteira pelo código a seguir.

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 funcionará inicialmente. Para que o app possa recuperar o token do dispositivo, o usuário precisa conceder permissão para que ele mostre notificações (a próxima etapa do codelab).

Solicitar permissões para mostrar notificações

Quando o usuário ainda não deu permissão ao app 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 pelo código a seguir.

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

Receber o token do dispositivo

  1. Se o aplicativo ainda estiver sendo veiculado, atualize-o no navegador. Caso contrário, execute firebase emulators:start na linha de comando para começar a exibir o app em http://localhost:5000 e abra-o no navegador.
  2. Depois de fazer login, a caixa de diálogo de permissão de notificações vai aparecer: bd3454e6dbfb6723.png
  3. Clique em Permitir.
  4. Abra o Console JavaScript do navegador. Você verá a seguinte mensagem: Got FCM device token: cWL6w:APA91bHP...4jDPL_A-wPP06GJp1OuekTaTZI5K2Tu
  5. Copie o token do dispositivo. Você vai precisar dele para a próxima etapa do codelab.

Enviar uma notificação para seu dispositivo

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

  1. Abra a guia Cloud Messaging do Console do Firebase.
  2. Clique em "Nova notificação"
  3. Digite o título e o texto da notificação.
  4. No lado direito da tela, clique em "Enviar mensagem de teste".
  5. Digite o token do dispositivo que você copiou 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 será exibida no navegador, como neste exemplo:

de79e8638a45864c.png

13. Regras de segurança do Cloud Firestore

Confira 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ê escolheu 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 conferir e modificar essas regras.

Agora, você deve ver as regras padrão, que não restringem o acesso ao armazenamento de dados. Isso significa que qualquer usuário pode ler e gravar em qualquer coleção do 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 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 para o 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ê escolheu usar a regra de segurança padrão do Cloud Storage, que permite o uso do Cloud Storage apenas por usuários autenticados. No Console do Firebase, na guia Regras da seção Armazenamento, é possível conferir e modificar regras. Você verá a regra padrão que permite que qualquer usuário conectado leia e grave arquivos 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 somente nas próprias pastas específicas
  • Permitir que qualquer pessoa leia no Cloud Storage
  • Verifique se os arquivos enviados são imagens
  • Restrinja o tamanho das imagens que podem ser enviadas a um máximo de 5 MB

Isso pode ser implementado usando as seguintes regras:

storage.rules (em inglês)

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

14. Implante seu app usando o Firebase Hosting

O Firebase oferece um serviço de hospedagem para disponibilizar seus recursos e apps da Web. É possível implantar arquivos no Firebase Hosting usando a CLI do Firebase. Antes da implantação, você precisa especificar no arquivo firebase.json quais arquivos locais devem ser implantados. Você já fez isso neste codelab, porque ela era necessária para disponibilizar nossos arquivos durante o codelab. As configurações de hospedagem são especificadas no atributo hosting:

firebase.json (link em inglês)

{
  // If you went through the "Cloud Firestore Security Rules" step.
  "firestore": {
    "rules": "firestore.rules"
  },
  // If you went through the "Storage Security Rules" step.
  "storage": {
    "rules": "storage.rules"
  },
  "hosting": {
    "public": "./public"
  }
}

Essas configurações informam à CLI que você quer implantar todos os arquivos no diretório ./public ( "public": "./public").

  1. Confira se a linha de comando está acessando o diretório local angularfire-start do app.
  2. Implante os arquivos no projeto do Firebase executando o seguinte comando:
ng deploy

Em seguida, selecione a opção Firebase e siga as instruções na linha de comando.

  1. O console vai exibir o seguinte:
=== Deploying to 'friendlychat-1234'...

i  deploying firestore, storage, hosting
i  storage: checking storage.rules for compilation errors...
✔  storage: rules file storage.rules compiled successfully
i  firestore: checking firestore.rules for compilation errors...
✔  firestore: rules file firestore.rules compiled successfully
i  storage: uploading rules storage.rules...
i  firestore: uploading rules firestore.rules...
i  hosting[friendlychat-1234]: beginning deploy...
i  hosting[friendlychat-1234]: found 8 files in ./public
✔  hosting[friendlychat-1234]: file upload complete
✔  storage: released rules storage.rules to firebase.storage/friendlychat-1234.appspot.com
✔  firestore: released rules firestore.rules to cloud.firestore
i  hosting[friendlychat-1234]: finalizing version...
✔  hosting[friendlychat-1234]: version finalized
i  hosting[friendlychat-1234]: releasing new version...
✔  hosting[friendlychat-1234]: release complete

✔  Deploy complete!

Project Console: https://console.firebase.google.com/project/friendlychat-1234/overview
Hosting URL: https://friendlychat-1234.firebaseapp.com
  1. Acesse seu app da Web que agora está totalmente hospedado em uma CDN global usando o Firebase Hosting em dois dos seus subdomínios do Firebase:
  • https://<firebase-projectId>.firebaseapp.com
  • https://<firebase-projectId>.web.app

Como alternativa, execute firebase open hosting:site na linha de comando.

Acesse a documentação para saber mais sobre como funciona o Firebase Hosting.

Acesse a seção Hosting do seu projeto no Console do Firebase para ver informações e ferramentas úteis de hospedagem, incluindo o histórico de implantações, a funcionalidade de reverter para versões anteriores do app e o fluxo de trabalho para configurar um domínio personalizado.

15. Parabéns!

Você usou o Firebase para criar um aplicativo da Web para chat em tempo real.

O que você aprendeu

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

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 ajuda a proteger seu back-end contra abusos. 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 conforme 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 adiante nesta etapa.

Como ativar o App Check

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

O App Check foi aplicado. Atualize o app e tente acessar 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.appspot.com',
    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 token do reCAPTCHA Enterprise.

Em seguida, navegue até o arquivo app.module.ts e adicione estas importações:

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

No mesmo arquivo app.module.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 em localhost, um token de depuração será registrado no console, semelhante a:

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 flutuante e selecione Gerenciar tokens de depuração.

Em seguida, clique em Adicionar token de depuração e cole o token de depuração do seu console, conforme 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 outros serviços do Firebase.

export class ChatService {
appCheck: AppCheck = inject(AppCheck);
...

Parabéns! O App Check agora deve estar funcionando no seu app.