Crie um aplicativo Android com Firebase e Jetpack Compose

1. Introdução

Última atualização: 2022-11-16

Construindo um aplicativo Android com Firebase e Jetpack Compose

Neste codelab, você criará um app para Android chamado Make It So . A interface do usuário deste aplicativo é totalmente construída com o Jetpack Compose , que é o kit de ferramentas moderno do Android para criar interface do usuário nativa - é intuitivo e requer menos código do que escrever arquivos .xml e vinculá-los a Activities, Fragments ou Views.

A primeira etapa para entender como o Firebase e o Jetpack Compose funcionam juntos é entender a arquitetura moderna do Android. Uma boa arquitetura torna o sistema fácil de entender, fácil de desenvolver e fácil de manter, pois deixa bem claro como os componentes se organizam e se comunicam entre si. No mundo Android, a arquitetura recomendada é chamada Model-View-ViewModel . O Modelo representa a camada que acessa os Dados na aplicação. A View é a camada de interface do usuário e não deve saber nada sobre a lógica de negócios. E o ViewModel é onde a lógica de negócios é aplicada, o que às vezes requer que o ViewModel chame a camada Model .

Recomendamos a leitura deste artigo para entender como o Model - View - ViewModel é aplicado a um aplicativo Android criado com o Jetpack Compose, pois isso facilitará o entendimento da base de código e a conclusão das próximas etapas.

O que você vai construir

Make It So é um aplicativo simples de lista de tarefas que permite ao usuário adicionar e editar tarefas, adicionar sinalizadores, prioridades e datas de vencimento e marcar as tarefas como concluídas. As imagens abaixo mostram as duas páginas principais deste aplicativo: a página de criação de tarefas e a página principal com a lista de tarefas criadas.

Make it So Adicionar tela de tarefaTela inicial do Make it So

Você adicionará alguns recursos que estão faltando neste aplicativo:

  • Autenticar usuários com e-mail e senha
  • Adicione um ouvinte a uma coleção do Firestore e faça a interface do usuário reagir às alterações
  • Adicione rastreamentos personalizados para monitorar o desempenho de um código específico no aplicativo
  • Crie uma alternância de recursos usando o Remote Config e use o lançamento gradual para iniciá-lo

O que você aprenderá

  • Como usar Firebase Authentication, Performance Monitoring, Remote Config e Cloud Firestore em um aplicativo Android moderno
  • Como fazer com que as APIs do Firebase se encaixem em uma arquitetura MVVM
  • Como refletir as alterações feitas com as APIs do Firebase em uma IU do Compose

O que você precisará

2. Obtenha o aplicativo de amostra e configure o Firebase

Obtenha o código do aplicativo de exemplo

Clone o repositório GitHub na linha de comando:

git clone https://github.com/FirebaseExtended/make-it-so-android.git

Configurar o Firebase

A primeira coisa que você precisa fazer é acessar o console do Firebase e criar um projeto Firebase clicando no botão "+ Adicionar projeto", conforme você pode ver abaixo:

Console do Firebase

Siga as etapas na tela para concluir a criação do projeto.

Dentro de cada projeto Firebase, você pode criar diferentes aplicativos: para Android, iOS, Web, Flutter e Unity. Escolha a opção Android, como você vê aqui:

Visão geral do projeto Firebase

Em seguida, siga estas etapas:

  1. Insira com.example.makeitso como o nome do pacote e, opcionalmente, insira um apelido. Para este codelab, você não precisa adicionar o certificado de assinatura de depuração.
  2. Clique em Next para registrar seu aplicativo e acessar o arquivo de configuração do Firebase.
  3. Clique em Baixar google-services.json para baixar seu arquivo de configuração e salve-o no diretório make-it-so-android/app .
  4. Clique em Avançar . Como os Firebase SDKs já estão incluídos no arquivo build.gradle no projeto de amostra, clique em Next para pular para as próximas etapas .
  5. Clique em Continuar para console para concluir.

Para que o aplicativo Make it So funcione corretamente, há duas coisas que você precisa fazer no console antes de pular para o código: habilitar os provedores de autenticação e criar o banco de dados do Firestore. Primeiro, vamos ativar a Autenticação para que os usuários possam fazer login no aplicativo:

  1. No menu Build , selecione Authentication e clique em Get Started .
  2. No cartão Método de login , selecione E-mail/Senha e habilite-o.
  3. Em seguida, clique em Adicionar novo provedor e selecione e habilite Anonymous .

Em seguida, configure o Firestore. Você usará o Firestore para armazenar as tarefas de um usuário conectado. Cada usuário obterá seu próprio documento dentro de uma coleção do banco de dados.

  1. No menu Build , selecione Firestore e clique em Create database .
  2. Mantenha Iniciar no modo de produção ativado e clique em Avançar .
  3. Quando solicitado, selecione o local onde os dados do Cloud Firestore serão armazenados. Ao desenvolver um aplicativo de produção, você deseja que ele esteja em uma região próxima à maioria dos usuários e em comum com outros serviços do Firebase, como o Functions. Para este codelab, você pode manter a região padrão ou selecionar a região mais próxima de você.
  4. Clique em Ativar para provisionar seu banco de dados do Firestore.

Vamos criar regras de segurança robustas para o banco de dados do Firestore. Abra o painel do Firestore e vá para a guia Regras . Em seguida, atualize as regras de segurança para que fiquem assim:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow create: if request.auth != null;
      allow read, update, delete: if request.auth != null && resource.data.userId == request.auth.uid;
    }
  }
}

Essas regras basicamente dizem que qualquer usuário conectado do aplicativo pode criar um documento para si mesmo em qualquer coleção. Então, uma vez criado, apenas o usuário que criou esse documento poderá visualizar, atualizar ou excluir esse documento.

Execute o aplicativo

Agora você está pronto para executar o aplicativo! Abra a pasta make-it-so-android/start no Android Studio e execute o aplicativo (isso pode ser feito usando um emulador Android ou um dispositivo Android real).

3. Autenticação do Firebase

Qual recurso você vai adicionar?

No estado atual do aplicativo de exemplo Make It So , um usuário pode começar a usar o aplicativo sem precisar entrar primeiro. Ele usa autenticação anônima para conseguir isso. No entanto, as contas anônimas não permitem que um usuário acesse seus dados em outros dispositivos ou mesmo em sessões futuras. Embora a autenticação anônima seja útil para uma integração morna, você sempre deve fornecer a opção para os usuários converterem para uma forma diferente de entrada. Com isso em mente, neste codelab, você adicionará autenticação de e-mail e senha ao aplicativo Make It So.

Hora de codificar!

Assim que o usuário criar uma conta, digitando um e-mail e uma senha, é necessário solicitar à Firebase Authentication API uma credencial de e-mail e vincular a nova credencial à conta anônima. Abra o arquivo AccountServiceImpl.kt no Android Studio e atualize a função linkAccount para que fique assim:

model/service/impl/AccountServiceImpl.kt

override suspend fun linkAccount(email: String, password: String) {
    val credential = EmailAuthProvider.getCredential(email, password)
    auth.currentUser!!.linkWithCredential(credential).await()
}

Agora abra SignUpViewModel.kt e chame a função de serviço linkAccount dentro do bloco launchCatching da função onSignUpClick :

screens/sign_up/SignUpViewModel.kt

launchCatching {
    accountService.linkAccount(email, password)
    openAndPopUp(SETTINGS_SCREEN, SIGN_UP_SCREEN)
}

Primeiro ele tenta autenticar e, se a chamada for bem-sucedida, ele segue para a próxima tela (a SettingsScreen ). Como você está executando essas chamadas dentro de um bloco launchCatching , se ocorrer um erro na primeira linha, a exceção será capturada e tratada, e a segunda linha não será alcançada.

Assim que a SettingsScreen for aberta novamente, você precisa se certificar de que as opções de Entrar e Criar conta sumiram, pois agora o usuário já está autenticado. Para fazer isso, vamos fazer o SettingsViewModel escutar o status do usuário atual (disponível em AccountService.kt ), para verificar se a conta é anônima ou não. Para fazer isso, atualize o uiState em SettingsViewModel.kt para se parecer com o seguinte:

screens/settings/SettingsViewModel.kt

val uiState = accountService.currentUser.map {
    SettingsUiState(it.isAnonymous)
}

A última coisa que você precisa fazer é atualizar o uiState em SettingsScreen.kt para coletar os estados emitidos pelo SettingsViewModel :

screens/settings/SettingsScreen.kt

val uiState by viewModel.uiState.collectAsState(
    initial = SettingsUiState(false)
)

Agora toda vez que o usuário mudar, a SettingsScreen irá se recompor para mostrar as opções de acordo com o novo estado de autenticação do usuário.

Hora de testar!

Execute o Make it So e navegue até as configurações clicando no ícone de engrenagem no canto superior direito da tela. A partir daí, clique na opção criar conta:

Tela de configurações Make it SoTela de inscrição do Make it So

Digite um e-mail válido e uma senha forte para criar sua conta. Deve funcionar e você deve ser redirecionado para a página de configurações, onde verá duas novas opções: sair e excluir sua conta. Você pode verificar a nova conta criada no painel de autenticação no console do Firebase clicando na guia Usuários.

4. Nuvem Firestore

Qual recurso você vai adicionar?

Para o Cloud Firestore, você adicionará um ouvinte à coleção do Firestore que armazena os documentos que representam as tarefas exibidas no Make it So . Depois de adicionar este ouvinte, você receberá todas as atualizações feitas nesta coleção.

Hora de codificar!

Atualize o Flow disponível em StorageServiceImpl.kt para ficar assim:

modelo/serviço/impl/StorageServiceImpl.kt

override val tasks: Flow<List<Task>>
    get() =
      auth.currentUser.flatMapLatest { user ->
        firestore.collection(TASK_COLLECTION).whereEqualTo(USER_ID_FIELD, user.id).dataObjects()
      }

Este código está adicionando um ouvinte à coleção de tarefas com base em user.id . Cada tarefa é representada por um documento em uma coleção chamada tasks , e cada uma delas possui um campo chamado userId . Observe que um novo Flow será emitido se o status do currentUser for alterado (ao sair, por exemplo).

Agora você precisa fazer o Flow em TasksViewModel.kt refletir o mesmo que no serviço:

screens/tasks/TasksViewModel.kt

val tasks = storageService.tasks

E a última coisa será fazer com que a composable function em TasksScreens.kt , que representa a interface do usuário, esteja ciente desse fluxo e colete-o como um estado. Sempre que o estado muda, a função que pode ser composta se recompõe automaticamente e exibe o estado mais recente para o usuário. Adicione isso à TasksScreen composable function :

screens/tasks/TasksScreen.kt

val tasks = viewModel
    .tasks
    .collectAsStateWithLifecycle(emptyList())

Depois que a função que pode ser composta tiver acesso a esses estados, você poderá atualizar a LazyColumn (que é a estrutura usada para exibir uma lista na tela) para ficar assim:

screens/tasks/TasksScreen.kt

LazyColumn {
    items(tasks.value, key = { it.id }) { taskItem ->
        TaskItem( [...] )
    }
}

Hora de testar!

Para testar se funcionou, adicione uma nova tarefa usando o aplicativo (clicando no botão adicionar no canto inferior direito da tela). Depois de terminar de criar a tarefa, ela deve aparecer na coleção do Firestore no Console do Firestore. Se você fizer login no Make it So em outros dispositivos com a mesma conta, poderá editar seus itens de tarefas e vê-los sendo atualizados em todos os dispositivos em tempo real.

5. Monitoramento de Desempenho

Qual recurso você vai adicionar?

O desempenho é uma coisa muito importante a se prestar atenção, porque é muito provável que os usuários desistam de usar seu aplicativo se o desempenho não for bom e eles demorarem muito para concluir uma tarefa simples usando-o. É por isso que às vezes é útil coletar algumas métricas sobre uma jornada específica que um usuário faz em seu aplicativo. E para ajudá-lo com isso, o Monitoramento de desempenho do Firebase oferece rastreamentos personalizados . Siga as próximas etapas para adicionar rastreamentos personalizados e medir o desempenho em diferentes trechos de código no Make it So .

Hora de codificar!

Se você abrir o arquivo Performance.kt , verá uma função embutida chamada trace. Essa função chama a API de monitoramento de desempenho para criar um rastreamento personalizado, transmitindo o nome do rastreamento como um parâmetro. O outro parâmetro que você vê é o bloco de código que deseja monitorar. A métrica padrão coletada para cada rastreamento é o tempo que leva para ser executado completamente:

modelo/serviço/Performance.kt

inline fun <T> trace(name: String, block: Trace.() -> T): T = Trace.create(name).trace(block)

Você pode escolher quais partes da base de código você acha importante medir e adicionar rastreamentos personalizados a ela. Veja um exemplo de como adicionar um rastreamento personalizado à função linkAccount que você viu anteriormente (em AccountServiceImpl.kt ) neste codelab:

model/service/impl/AccountServiceImpl.kt

override suspend fun linkAccount(email: String, password: String): Unit =
  trace(LINK_ACCOUNT_TRACE) {
      val credential = EmailAuthProvider.getCredential(email, password)
      auth.currentUser!!.linkWithCredential(credential).await()
  }

Agora é sua vez! Adicione alguns traços personalizados ao aplicativo Make it So e prossiga para a próxima seção para testar se funcionou conforme o esperado.

Hora de testar!

Depois de terminar de adicionar os traços personalizados, execute o aplicativo e certifique-se de usar os recursos que deseja medir algumas vezes. Em seguida, vá para o console do Firebase e vá para o painel de desempenho . Na parte inferior da tela, você encontrará três guias: Solicitações de rede , Traços personalizados e Renderização de tela .

Vá para a guia Custom traces e verifique se os traces que você adicionou na base de código estão sendo exibidos lá e se você pode ver quanto tempo geralmente leva para executar esses trechos de código.

6. Configuração Remota

Qual recurso você vai adicionar?

Há uma infinidade de casos de uso para Configuração remota, desde alterar a aparência do seu aplicativo remotamente até configurar diferentes comportamentos para diferentes segmentos de usuários. Neste codelab, você usará o Remote Config para criar um recurso de alternância que mostrará ou ocultará o novo recurso de tarefa de edição no aplicativo Make it So.

Hora de codificar!

A primeira coisa que você precisa fazer é criar a configuração no console do Firebase. Para fazer isso, você precisa navegar até o painel Configuração remota e clicar no botão Adicionar parâmetro . Preencha os campos conforme imagem abaixo:

Configuração remota Criar uma caixa de diálogo de parâmetro

Depois que todos os campos estiverem preenchidos, você pode clicar no botão Salvar e depois em Publicar . Agora que o parâmetro está criado e disponível para sua base de código, você precisa adicionar o código que buscará os novos valores para seu aplicativo. Abra o arquivo ConfigurationServiceImpl.kt e atualize a implementação destas duas funções:

model/service/impl/ConfigurationServiceImpl.kt

override suspend fun fetchConfiguration(): Boolean {
  return remoteConfig.fetchAndActivate().await()
}

override val isShowTaskEditButtonConfig: Boolean
  get() = remoteConfig[SHOW_TASK_EDIT_BUTTON_KEY].asBoolean()

A primeira função busca os valores do servidor e é chamada assim que o aplicativo é iniciado, em SplashViewModel.kt . É a melhor forma de garantir que os valores mais atualizados estarão disponíveis em todas as telas desde o início. Não é uma boa experiência do usuário se você alterar a interface do usuário ou o comportamento do aplicativo posteriormente, quando o usuário estiver fazendo algo!

A segunda função está retornando o valor booleano que foi publicado para o parâmetro que você acabou de criar no Console. E você precisará recuperar essas informações em TasksViewModel.kt , adicionando o seguinte à função loadTaskOptions :

screens/tasks/TasksViewModel.kt

fun loadTaskOptions() {
  val hasEditOption = configurationService.isShowTaskEditButtonConfig
  options.value = TaskActionOption.getOptions(hasEditOption)
}

Você está recuperando o valor na primeira linha e usando-o para carregar as opções de menu para os itens de tarefa na segunda linha. Se o valor for false , significa que o menu não conterá a opção de edição. Agora que você tem a lista de opções, precisa fazer com que a interface do usuário a exiba corretamente. Ao criar um aplicativo com o Jetpack Compose, você precisa procurar a composable function que declara a aparência da IU do TasksScreen . Então abra o arquivo TasksScreen.kt e atualize o LazyColum para apontar para as opções disponíveis em TasksViewModel.kt :

screens/tasks/TasksScreen.kt

val options by viewModel.options

LazyColumn {
  items(tasks.value, key = { it.id }) { taskItem ->
    TaskItem(
      options = options,
      [...]
    )
  }
}

O TaskItem é outra composable function que declara como deve ser a interface do usuário de uma única tarefa. E cada tarefa possui um menu com opções que é exibido quando o usuário clica no ícone de três pontinhos ao final dele.

Hora de testar!

Agora você está pronto para executar o aplicativo! Verifique se o valor que você publicou usando o Firebase console corresponde ao comportamento do aplicativo:

  • Se for false , você verá apenas duas opções ao clicar no ícone de três pontos;
  • Se for true , você deverá ver três opções ao clicar no ícone de três pontos;

Tente alterar o valor algumas vezes no Console e reiniciar o aplicativo. Assim é fácil lançar novos recursos em seu aplicativo usando o Remote Config!

7. Parabéns

Parabéns, você criou com sucesso um aplicativo Android com Firebase e Jetpack Compose!

Você adicionou Firebase Authentication, Performance Monitoring, Remote Config e Cloud Firestore a um aplicativo Android totalmente desenvolvido com Jetpack Compose para a interface do usuário e o encaixou na arquitetura MVVM recomendada!

Leitura adicional

Documentos de referência