1. Introdução
Última atualização:16/11/2022
Como criar um app Android com o Firebase e o Jetpack Compose
Neste codelab, você vai criar um app Android chamado Make It So. A interface dele é totalmente criada com o Jetpack Compose, que é o kit de ferramentas moderno do Android para criar interfaces nativas. Ele é intuitivo e exige 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 juntos é conhecer a arquitetura moderna do Android. Uma boa arquitetura facilita a compreensão, o desenvolvimento e a manutenção do sistema, já que deixa muito claro como os componentes são organizados e se comunicam entre si. No mundo Android, a arquitetura recomendada é chamada de Model - View - ViewModel. O modelo representa a camada que acessa os dados no aplicativo. A View é a camada de interface 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 ler este artigo para entender como o Model-View-ViewModel é aplicado a um app Android criado com o Jetpack Compose. Isso vai facilitar a compreensão da base de código e a conclusão das próximas etapas.
O que você vai criar
O Make It So é um aplicativo simples de lista de tarefas que permite ao usuário adicionar e editar tarefas, adicionar flags, prioridades e datas de conclusão 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.
Você vai adicionar alguns recursos que estão faltando neste app:
- Autenticar usuários com e-mail e senha
- Adicionar um listener a uma coleção do Firestore e fazer a interface reagir a mudanças
- Adicionar traces personalizados para monitorar o desempenho de um código específico no app
- Criar uma flag de recurso usando o Remote Config e usar o lançamento gradual para lançar
O que você aprenderá
- Como usar o Firebase Authentication, o Monitoramento de desempenho, a Configuração remota e o Cloud Firestore em um aplicativo Android moderno
- Como fazer as APIs do Firebase se encaixarem em uma arquitetura MVVM
- Como refletir mudanças feitas com as APIs do Firebase em uma interface do Compose
O que é necessário
- Android Studio Flamingo+
- Android Emulator com API 21 ou mais recente
- Familiaridade com a linguagem de programação Kotlin
2. Receber o app de exemplo e configurar o Firebase
Acessar o código do app de exemplo
Clone o repositório do GitHub na linha de comando:
git clone https://github.com/FirebaseExtended/make-it-so-android.git
Criar um projeto do Firebase
Primeiro, acesse o Console do Firebase e crie um projeto clicando no botão "+ Adicionar projeto", como mostrado abaixo:
Siga as etapas na tela para concluir a criação do projeto.
Adicionar um app Android ao projeto do Firebase
No seu projeto do Firebase, você pode registrar diferentes apps: para Android, iOS, Web, Flutter e Unity.
Escolha a opção Android, como mostrado aqui:
Em seguida:
- Insira
com.example.makeitso
como o nome do pacote e, se quiser, um apelido. Para este codelab, não é necessário adicionar o certificado de assinatura de depuração. - Clique em Próxima para registrar o app e acessar o arquivo de configuração do Firebase.
- Clique em Fazer o download do google-services.json para baixar o arquivo de configuração e salve-o no diretório
make-it-so-android/app
. - Clique em Próxima. Como os SDKs do Firebase já estão incluídos no arquivo
build.gradle
do projeto de exemplo, clique em Próxima para pular para Próximas etapas. - Clique em Continuar para o console para concluir.
Para que o app Make it So funcione corretamente, é necessário fazer duas coisas no console antes de passar para o código: ativar os provedores de autenticação e criar o banco de dados do Firestore.
Configurar a autenticação
Primeiro, vamos ativar a autenticação para que os usuários possam fazer login no app:
- No menu Build, selecione Authentication e clique em Get Started.
- No card Método de login, selecione E-mail/senha e ative essa opção.
- Em seguida, clique em Adicionar novo provedor e selecione e ative Anônimo.
Configurar o Cloud Firestore
Em seguida, configure o Firestore. Você vai usar o Firestore para armazenar as tarefas de um usuário conectado. Cada usuário recebe um documento em uma coleção do banco de dados.
- No painel à esquerda do console do Firebase, expanda Build e selecione Banco de dados do Firestore.
- Clique em Criar banco de dados.
- Deixe o ID do banco de dados definido como
(default)
. - 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. - Clique em Iniciar no modo de teste. Leia o aviso sobre as regras de segurança.
Nas próximas etapas desta seção, 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. - Clique em Criar.
Vamos criar regras de segurança robustas para o banco de dados do Firestore.
- Abra o painel do Firestore e acesse a guia Regras.
- Atualize as regras de segurança para que fiquem assim:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /tasks/{document} {
allow create: if request.auth != null;
allow read, update, delete: if request.auth != null
&& resource.data.userId == request.auth.uid
&& request.data.userId == resource.data.userId;
}
}
}
Essas regras basicamente dizem que qualquer usuário conectado do app pode criar um documento para si mesmo em qualquer coleção. Depois de criado, somente o usuário que criou o documento poderá acessar, atualizar ou excluir o arquivo.
Executar o aplicativo
Agora você já pode executar o aplicativo. Abra a pasta make-it-so-android/start
no Android Studio e execute o app (isso pode ser feito usando um emulador Android ou um dispositivo Android real).
3. Firebase Authentication
Qual recurso você vai adicionar?
No estado atual do app de exemplo Make It So, um usuário pode começar a usar o app sem precisar fazer login primeiro. Ele usa a autenticação anônima para isso. No entanto, as contas anônimas não permitem que um usuário acesse os dados em outros dispositivos ou até mesmo em sessões futuras. Embora a autenticação anônima seja útil para uma integração lenta, sempre ofereça aos usuários a opção de mudar para outra forma de login. Com isso em mente, neste codelab, você vai adicionar a autenticação por e-mail e senha ao app Make It So.
Hora de programar!
Assim que o usuário criar uma conta digitando um e-mail e uma senha, peça uma credencial de e-mail à API Firebase Authentication e vincule a nova credencial à conta anônima. Abra o arquivo AccountServiceImpl.kt
no Android Studio e atualize a função linkAccount
para que ela 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 linkAccount
do serviço no 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, passa para a próxima tela (o 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 processada, e a segunda linha não será alcançada.
Assim que o SettingsScreen
for aberto novamente, verifique se as opções Fazer login e Criar conta não aparecem mais, porque o usuário já está autenticado. Para 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 que fique assim:
screens/settings/SettingsViewModel.kt
val uiState = accountService.currentUser.map {
SettingsUiState(it.isAnonymous)
}
Por fim, atualize 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, sempre que o usuário mudar, o SettingsScreen
vai 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 acesse as configurações clicando no ícone de engrenagem no canto superior direito da tela. Em seguida, clique na opção de criar conta:
Digite um e-mail válido e uma senha forte para criar sua conta. Isso deve funcionar, e você vai ser redirecionado para a página de configurações, onde verá duas novas opções: sair e excluir sua conta. Para verificar a nova conta criada no painel "Autenticação" do console do Firebase, clique na guia "Usuários".
4. Cloud Firestore
Qual recurso você vai adicionar?
No Cloud Firestore, você vai adicionar um listener à coleção do Firestore que armazena os documentos que representam as tarefas exibidas em Make it So. Depois de adicionar esse listener, você vai receber todas as atualizações feitas nessa coleção.
Hora de programar!
Atualize o Flow
disponível em StorageServiceImpl.kt
para que fique assim:
model/service/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()
}
Esse código adiciona um listener à coleção de tarefas com base no user.id
. Cada tarefa é representada por um documento em uma coleção chamada tasks
, e cada uma delas tem um campo chamado userId
. Um novo Flow
será emitido se o status do currentUser
mudar (ao sair da conta, por exemplo).
Agora, é preciso fazer com que o Flow
em TasksViewModel.kt
reflita o mesmo que no serviço:
screens/tasks/TasksViewModel.kt
val tasks = storageService.tasks
Por fim, vamos fazer com que o composable function
em TasksScreens.kt
, que representa a interface, conheça esse fluxo e o colete como um estado. Sempre que o estado muda, a função combinável se recompõe automaticamente e mostra o estado mais recente para o usuário. Adicione isso ao TasksScreen composable function
:
screens/tasks/TasksScreen.kt
val tasks = viewModel
.tasks
.collectAsStateWithLifecycle(emptyList())
Depois que a função combinável tiver acesso a esses estados, você poderá atualizar o LazyColumn
(que é a estrutura usada para mostrar 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 app. Clique no botão de adição no canto inferior direito da tela. Depois de criar a tarefa, ela vai aparecer na coleção do Firestore no console do Firestore. Se você fizer login no Faça isso em outros dispositivos com a mesma conta, poderá editar seus itens da lista de tarefas e acompanhar as atualizações em tempo real em todos os dispositivos.
5. Monitoramento de desempenho
Qual recurso você vai adicionar?
O desempenho é muito importante porque os usuários provavelmente vão desistir de usar seu app se ele não for bom e demorar muito para concluir uma tarefa simples. Por isso, às vezes é útil coletar algumas métricas sobre uma jornada específica que um usuário faz no seu app. Para ajudar 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 partes do código no Make it So.
Hora de programar!
Se você abrir o arquivo Performance.kt
, vai encontrar uma função inline chamada "trace". Essa função chama a API Performance Monitoring para criar um trace personalizado, transmitindo o nome do trace como um parâmetro. O outro parâmetro que aparece é o bloco de código que você quer monitorar. A métrica padrão coletada para cada rastreamento é o tempo necessário para a execução completa:
model/service/Performance.kt
inline fun <T> trace(name: String, block: Trace.() -> T): T = Trace.create(name).trace(block)
Você pode escolher quais partes do codebase considera importante medir e adicionar rastros personalizados a elas. Confira um exemplo de como adicionar um rastreamento personalizado à função linkAccount
que você viu antes (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 rastros personalizados ao app Make it So e siga para a próxima seção para testar se ele funcionou conforme o esperado.
Hora de testar!
Depois de adicionar os traces personalizados, execute o app e use os recursos que você quer medir algumas vezes. Em seguida, acesse o console do Firebase e o painel de Desempenho. Na parte de baixo da tela, você encontra três guias: Solicitações de rede, Traces personalizados e Renderização da tela.
Acesse a guia Traces personalizados e verifique se os traces adicionados na base de código estão sendo exibidos e se é possível ver quanto tempo geralmente leva para executar esses trechos de código.
6. Configuração remota
Qual recurso você vai adicionar?
Há vários casos de uso para a Configuração remota, desde mudar a aparência do app remotamente até configurar comportamentos diferentes para segmentos de usuários diferentes. Neste codelab, você vai usar a Configuração remota para criar uma flag de recurso que vai mostrar ou ocultar o novo recurso Editar tarefa no app Make it So.
Hora de programar!
Primeiro, crie a configuração no console do Firebase. Para fazer isso, acesse o painel da Configuração remota e clique no botão Adicionar parâmetro. Preencha os campos de acordo com a imagem abaixo:
Depois de preencher todos os campos, clique no botão Salvar e em Publicar. Agora que o parâmetro foi criado e está disponível para sua base de código, adicione o código que vai buscar os novos valores ao app. 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 app é iniciado, em SplashViewModel.kt
. Essa é a melhor maneira de garantir que os valores mais atualizados estejam disponíveis em todas as telas desde o início. Não é uma boa experiência do usuário mudar a interface ou o comportamento do app depois, quando o usuário está no meio de algo.
A segunda função retorna o valor booleano publicado para o parâmetro que você acabou de criar no console. 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 dos itens de tarefa na segunda linha. Se o valor for false
, o menu não vai ter a opção de edição. Agora que você tem a lista de opções, é necessário fazer com que a interface a mostre corretamente. Ao criar um app com o Jetpack Compose, você precisa procurar o composable function
que declara como a interface do TasksScreen
deve ser. 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
é outro composable function
que declara como a interface de uma única tarefa deve ser. Cada tarefa tem um menu com opções que aparece quando o usuário clica no ícone de três pontos no final dela.
Hora de testar!
Agora você já pode executar o app. Verifique se o valor publicado usando o console do Firebase corresponde ao comportamento do app:
- Se for
false
, você só vai ver duas opções ao clicar no ícone de três pontos: - Se for
true
, você vai encontrar três opções ao clicar no ícone de três pontos:
Mude o valor algumas vezes no console e reinicie o app. É assim que fica fácil lançar novos recursos no app usando a Configuração remota.
7. Parabéns
Parabéns! Você criou um app Android com o Firebase e o Jetpack Compose.
Você adicionou o Firebase Authentication, o Monitoramento de desempenho, a Configuração remota e o Cloud Firestore a um app Android totalmente criado com o Jetpack Compose para a interface, e o adaptou à arquitetura MVVM recomendada.
Leia mais
- Como criar um app Android com o Firebase e o Compose
- Adicionar o Firebase Authentication a um app do Jetpack Compose
- Como adicionar o Cloud Firestore a um app do Jetpack Compose
- Como adicionar corrotinas e fluxo a um app Android criado com o Firebase e o Compose
- Como adicionar o Monitoramento de desempenho do Firebase a um app do Jetpack Compose
- Adicionar a Configuração remota do Firebase a um app do Jetpack Compose