Semana da Programação

16% de desconto!
Oferta acaba em:

0

dias

00

hrs

00

min

00

seg

Autenticação com FirebaseUI no Android

O que é FirebaseUI?

Antes de configurar ou implementar código, é muito importante entender o que é o FirebaseUI e a sua proposta. Basicamente, é uma biblioteca do Firebase com a proposta de facilitar a implementação do Firebase Authentication.

Em outras palavras, o FirebaseUI implementa todo o fluxo de tela e lógica de autenticação, isso significa que não há a necessidade de criar um layout próprio e implementar todo o fluxo assim como fazemos no SDK do Firebase Authentication.

Isso também significa que temos restrições na personalização das telas e fluxo utilizando o FirebaseUI e, caso você tenha interesse em ter uma experiência diferente para o seu usuário, você não deve considerar o uso do FirebaseUI.

Tendo consciência das vantagens e desvantagens, agora podemos começar a configuração do FirebaseUI.

Você pode conferir mais detalhes sobre a capacidade do FirebaseUI na página de introdução oficial do Firebase.

Pré-requisitos

Neste artigo usaremos o projeto desenvolvido no curso de Firebase Authentication com Android. Se você já tem o projeto, fique à vontade em reutilizá-lo, caso contrário, você pode baixá-lo ou acessar o código fonte via GitHub.

O projeto fornecido não acompanha o arquivo de integração com o Firebase, o google-services.json. Isso significa que ao rodar o App, o Android Studio vai indicar a ausência do arquivo e não vai executar.

Para resolver o problema, você precisa ter ou registrar um App para Android no console do Firebase com o pacote br.com.alura.aluraesporte. Então, basta apenas baixar o arquivo e adicionar dentro do módulo app do projeto.

Caso esteja com dúvida de como fazer a configuração, confira a primeira aula do curso ou consulte a página da documentação do Firebase que explica o passo-a-passo.

Ao rodar o App deve apresentar a seguinte tela:

É importante ressaltar que iremos explorar a autenticação por meio de e-mail e senha, portanto, é necessário configurar o console do projeto do Firebase. Para isso você pode acessar o menu Authentication > Sign-in method para que permita esse tipo de autenticação:

Após preparar todo ambiente, já somos capazes de iniciar a implementação do FirebaseUI no projeto Android.

Adicionando o FirebaseUI no projeto

Como primeiro passo, precisamos ter acesso ao FirebaseUI no projeto. Para isso adicionamos as seguintes dependências:

dependencies {
    implementation 'com.firebaseui:firebase-ui-auth:6.2.0'
}

Como a própria documentação indica, caso queira fazer a autenticação com o Twitter ou Facebook, é necessário adicionar libs separadas também:

dependencies {
    implementation 'com.firebaseui:firebase-ui-auth:6.2.0'

    // Necessário somente para o login com Facebook
    // A versão mais atual do Facebook SDK pode ser encontrada aqui: https://goo.gl/Ce5L94
    implementation 'com.facebook.android:facebook-android-sdk:4.x'

    // Necessário somente para o login com Twitter
    // A versão mais atual do Twitter SDK pode ser encontrada aqui: https://goo.gl/E5wZvQ
    implementation 'com.twitter.sdk.android:twitter-core:3.x'
}

Após a adição, basta apenas sincronizar o App para ter o acesso aos componentes do FirebaseUI.

Adicionando os botões de autenticação

Agora que temos o FirebaseUI, precisamos de uma instância de AuthUI que será responsável em controlar todo o fluxo. Para isso, no onViewCreated() do LoginFragment, podemos pegar a instância via método estático da classe AuthUI:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    //restante do código
    val authUi = AuthUI.getInstance()
}

Em seguida precisamos montar a Intent que vai ficar responsável em abrir as telas do fluxo do FirebaseUI, fazemos isso com o método createSignInIntentBuilder() e adicionamos os provedores disponíveis durante o processo de construção:

val authUi = AuthUI.getInstance()
val intent = authUi.createSignInIntentBuilder()
    .setAvailableProviders(listOf(AuthUI.IdpConfig.EmailBuilder().build()))
    .build()

Note que ele recebe uma lista, ou seja, é possível enviar mais de um provedor de uma vez.

Então precisamos inicializar a Intent, porém, a inicialização da Intent é a partir do método startActivityForResult(), pois ao finalizar a Activity inicializada, precisamos lidar com o retorno:

val authUi = AuthUI.getInstance()
val intent = authUi.createSignInIntentBuilder()
    .setAvailableProviders(listOf(AuthUI.IdpConfig.EmailBuilder().build()))
    .build()
startActivityForResult(intent, RC_SIGN_IN)

RC_SIGN_IN é uma constante que identifica a requisição feita pela Intent, você pode colocar o valor Int que preferir, como por exemplo, o 1

Então podemos rodar o App e conferir o que acontece:

Note que não temos mais acesso à nossa tela de Login que fizemos anteriormente!

Testando o fluxo de autenticação e cadastro via e-mail e senha

Apenas com essa implementação temos acesso ao fluxo completo de autenticação via e-mail e senha utilizando o Firebase Authentication como, por exemplo, o cadastro de um usuário inexistente:

Ou a autenticação quando o usuário já existe:

Em ambos os casos, ao abrir o App novamente, que faz a verificação da existência de um usuário logado, entramos diretamente na tela inicial, a lista de produtos.

Para fazer as simulações, você pode deslogar do App :)

Entretanto, esse fluxo natural não acontece após cadastrar ou autenticar com o FirebaseUI... O motivo disso é o fato de que não estamos lidando com a resposta da inicialização da Activity, ou seja, precisamos sobrescrever o onActivityResult() e implementar a devida verificação:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == RC_SIGN_IN) {
        if (resultCode == RESULT_OK) {
            vaiParaListaProdutos()
        }
    }
}

Nessa implementação basicamente identificamos a requisição que foi feita e se obtivermos um código de sucesso, então redirecionamos para a tela da lista de produtos que já faz a verificação da existência de usuário:

Observe que agora o App mantém o comportamento natural durante a autenticação ou no cadastro:

E agora temos uma implementação do fluxo de cadastro e autenticação com e-mail e senha utilizando o FirebaseUI, simples né?

Lidando com os possíveis problemas

Na nossa primeira implementação, simulamos apenas os 'caminhos felizes', quando tudo ocorre como o esperado, e não notamos nenhum comportamento estranho. Porém, em situações que temos uma falha o App volta novamente para a tela de login e sem nenhum feedback para o usuário ou usuária, um comportamento bastante estranho.

Para lidarmos com isso, podemos verificar quando o resultado não é RESULT_OK e identificar o possível problema com a resposta recebida:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == RC_SIGN_IN) {
        if (resultCode == RESULT_OK) {
            vaiParaListaProdutos()
        } else {
            val response = IdpResponse.fromResultIntent(data)
            Log.e(TAG, "onActivityResult: falha ao autenticar", response?.error)
            view?.snackBar("Falha ao autenticar")
        }
    }
}

TAG é uma constante do tipo String, você pode colocar o valor que preferir para identificar o log, geralmente eu costumo colocar no nome da classe.

Ao testar novamente a autenticação temos a identificação do problema visualmente:

E uma informação mais precisa via logcat:

2020-08-19 12:30:55.419 19460-19460/br.com.alura.aluraesporte E/LoginFragment: onActivityResult: falha ao autenticar

Nesse caso temos um erro nulo, o que indica que este usuário voltou da tela de autenticação segundo a amostra de código da documentação, inclusive, também é indicado que em casos que não é nulo, é possível verificar o código para identificar o erro:

val response = IdpResponse.fromResultIntent(data)

Adaptando a tela inicial com o FirebaseUI

Um outro ponto importante em relação ao uso do FirebaseUI, é que delegamos toda a responsabilidade de autenticação para ele, ou seja, não faz sentido manter a mesma tela de login que temos quando consideramos o seu uso.

Em outras palavras, é mais conveniente utilizar uma tela que apresente um botão para entrar no App e assim abrir o FirebaseUI:

Essa implementação pode ser feita de várias maneiras, considerando este projeto que utiliza o Navigation, são necessários os seguintes passos:

  • Criar um novo destino (Fragment) para a tela de início;
  • Implementar a tela (XML de layout);
  • Configurar o listener do botão Entrar para abrir o componente do FirebaseUI;
  • Migrar a sobrescrita do onActivityResult() da tela de login para a tela de início;
  • Configurar o controlador do navigation para acessar a lista de produtos quando a autenticação for sucedida;
  • Configurar o Fragment base para redirecionar para a tela de início ao invés da tela de login quando o usuário não estiver autenticado ou quando for deslogado;

Considere esses passos como desafio e tente implementá-los ;)

Caso queira conferir como foi feita toda a implementação do artigo, confira este commit ou o código fonte no repositório do GitHub.

Para saber mais: Possibilidades com o FirebaseUI

A implementação do FirebaseUI desenvolvida durante o artigo é apenas uma parte das possibilidades que essa biblioteca oferece, ou seja, há muitas outras possibilidades e funcionalidades que podem ser exploradas. Caso tenha interesse em saber mais além do conteúdo introdutório visto na documentação, confira o README do projeto via GitHub.

Alex Felipe
Alex Felipe

Alex é instrutor e desenvolvedor com foco em Java, Kotlin, Android e Spring. É expert em Programação Orientada a Objetos, visando sempre compartilhar as melhores práticas e tendências do mercado para desenvolvimento de software com quem está estudando o assunto. Atuou 2 anos como editor de conteúdo no blog da Alura e hoje ainda escreve artigos técnicos sobre o desenvolvimento.

Veja outros artigos sobre Mobile