Crie um aplicativo Android com Firebase e Jetpack Compose

1. Introdução

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

Construindo um aplicativo Android com Firebase e Jetpack Compose

Neste codelab, você criará um app Android chamado Make It So . A UI deste aplicativo é inteiramente construída com Jetpack Compose , que é o kit de ferramentas moderno do Android para construir UI nativa - é intuitivo e requer menos código do que escrever arquivos .xml e vinculá-los a atividades, fragmentos ou visualizações.

A primeira etapa para entender como o Firebase e o Jetpack Compose funcionam bem juntos é compreender 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 estão organizados 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 da UI 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 exige que o ViewModel chame a camada Model .

Recomendamos fortemente a leitura deste artigo para entender como Model - View - ViewModel é aplicado a um aplicativo Android criado com Jetpack Compose, pois isso tornará a base de código mais fácil de entender e as próximas etapas mais fáceis de serem concluídas.

O que você 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.

Faça assim tela Adicionar tarefaFaça isso na tela inicial

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

  • Autenticar usuários com e-mail e senha
  • Adicione um listener a uma coleção do Firestore e faça a IU reagir às alterações
  • Adicione traces personalizados para monitorar o desempenho de código específico no aplicativo
  • Crie uma alternância de recursos usando a Configuração remota 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 APIs do Firebase em uma IU do Compose

O que você precisará

2. Obtenha o aplicativo de exemplo 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 é ir ao console do Firebase e criar um projeto Firebase clicando no botão “+ Adicionar projeto”, como você pode ver abaixo:

Console do Firebase

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

Dentro de cada projeto do 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. Neste codelab, não é necessário adicionar o certificado de assinatura de depuração.
  2. Clique em Avançar 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 salvá-lo no diretório make-it-so-android/app .
  4. Clique em Avançar . Como os SDKs do Firebase já estão incluídos no arquivo build.gradle do projeto de exemplo, clique em Avançar para pular para as próximas etapas .
  5. Clique em Continuar para console para finalizar.

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

  1. No menu Construir , selecione Autenticação e clique em Começar .
  2. No cartão Método de login , selecione Email/Senha e ative-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 seus usuários e em comum com outros serviços do Firebase, como o Functions. Neste codelab, você pode manter a região padrão ou selecionar a região mais próxima de você.
  4. Clique em Habilitar para provisionar seu banco de dados do Firestore.

Vamos reservar um momento para 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 ficar 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 ao aplicativo pode criar um documento para si mesmo em qualquer coleção. Então, uma vez criado, apenas o usuário que criou o 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 Android Emulator ou um dispositivo Android real).

3. Autenticação 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 fazer login 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 calorosa, você deve sempre fornecer a opção para os usuários converterem para uma forma diferente de login. Com isso em mente, neste codelab você adicionará autenticação de e-mail e senha ao app Make It So.

É hora de codificar!

Assim que o usuário criar uma conta, digitando um e-mail e uma senha, você precisará solicitar uma credencial de e-mail à API Firebase Authentication e, em seguida, 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:

modelo/serviço/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 :

telas/sign_up/SignUpViewModel.kt

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

Primeiro ele tenta se 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 desapareceram, pois agora o usuário já está autenticado. Para fazer isso, vamos fazer o SettingsViewModel ouvir 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 ter a seguinte aparência:

telas/configurações/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 :

telas/configurações/SettingsScreen.kt

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

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

Hora de testar!

Execute 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 do Make it SoFaça isso, então tela de inscrição

Digite um e-mail válido e uma senha forte para criar sua conta. Deve funcionar e você 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 listener à coleção do Firestore que armazena os documentos que representam as tarefas exibidas em 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 com que o Flow em TasksViewModel.kt reflita o mesmo que no serviço:

telas/tarefas/TasksViewModel.kt

val tasks = storageService.tasks

E a última coisa será fazer com que a composable function em TasksScreens.kt , que representa a UI, 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 isto à TasksScreen composable function :

telas/tarefas/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 LazyColumn (que é a estrutura usada para exibir uma lista na tela) para ficar assim:

telas/tarefas/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 deverá aparecer na coleção do Firestore no Firestore Console. Se você fizer login no Make it So em outros dispositivos com a mesma conta, poderá editar suas tarefas e vê-las sendo atualizadas 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 os usuários provavelmente desistirão de usar seu aplicativo se o desempenho não for bom e levarem muito tempo 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 no seu aplicativo. E para te ajudar com isso, o Firebase Performance Monitoring oferece traces personalizados . Siga as próximas etapas para adicionar rastreamentos personalizados e medir o desempenho em diferentes partes do código em Make it So .

É hora de codificar!

Se você abrir o arquivo Performance.kt , verá uma função embutida chamada trace. Esta função chama a API Performance Monitoring para criar um rastreamento personalizado, passando o nome do rastreamento como parâmetro. O outro parâmetro que você vê é o bloco de código que você deseja monitorar. A métrica padrão coletada para cada rastreamento é o tempo necessário 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 adição de um trace personalizado à função linkAccount que você viu anteriormente (em AccountServiceImpl.kt ) neste codelab:

modelo/serviço/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 rastreamentos 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 rastreamentos personalizados, execute o aplicativo e use 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 , Rastreamentos personalizados e Renderização de tela .

Vá para a guia Rastreamentos personalizados e verifique se os rastreios adicionados à base de código estão sendo exibidos lá e se você pode ver quanto tempo normalmente 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 a Configuração remota, desde a alteração remota da aparência do seu aplicativo até a configuração de diferentes comportamentos para diferentes segmentos de usuários. Neste codelab, você usará a Configuração remota para criar uma alternância de recursos 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 do Configuração remota e clicar no botão Adicionar parâmetro . Preencha os campos conforme imagem abaixo:

Caixa de diálogo Criar um parâmetro do Configuração remota

Depois que todos os campos estiverem preenchidos, você pode clicar no botão Salvar e depois em Publicar . Agora que o parâmetro foi criado e está 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:

modelo/serviço/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 retorna 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 :

telas/tarefas/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, é necessário fazer com que a IU 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 . Portanto, abra o arquivo TasksScreen.kt e atualize o LazyColum para apontar para as opções disponíveis em TasksViewModel.kt :

telas/tarefas/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 pontos ao final dela.

Hora de testar!

Agora você está pronto para executar o aplicativo! Verifique se o valor publicado usando o console do Firebase 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. É tão fácil lançar novos recursos no seu aplicativo usando a Configuração remota!

7. Parabéns

Parabéns, você criou um aplicativo Android com sucesso 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 IU e ajustou-o à arquitetura MVVM recomendada.

Leitura adicional

Documentos de referência