Firebase Auth no Android

Um jeito mais fácil de gerenciar logins e usuários no seu app.

Daivid Vasconcelos Leal
Accenture Digital Product Dev

--

Em algum momento, as aplicações que criamos vão precisar de um serviço de autenticação, principalmente se necessitarmos de um controle de usuários. Além disso, para que um usuário não “fuja” do nosso aplicativo à primeira vista, queremos sempre dar a possibilidade de várias opções de login. Certo?

O Firebase nos dá uma lista de possibilidades de auth para que possamos criar nossa estrutura de usuário em um único local, além de facilitar bastante a criação de novos métodos de Login. Imagine poder gerenciar usuários que utilizam Google, Facebook, Twitter e outros em um único local, sem se preocupar com o tratamento do servidor, novos contratos com a API, tokens diferentes ou outros problemas que encontramos com a preparação de um ambiente que possibilite vários logins? Pois esse é o propósito deste post.

Bora lá?

Firebase

O Firebase se tornou uma ferramenta de Backend as a Service (BaaS) muito robusta, e agora trata não somente de autenticação como também de vários outros serviços, concentrando, atualmente, um conjunto de ferramenta úteis para diversas áreas:

Como podemos ver, além dos serviços de autenticação existem vários outros que podemos usufruir e utilizar na nossa aplicação. E o melhor de tudo é que sempre tem aquele limite básico para testarmos se vale a pena ou não. Mas vamos ao que interessa!

O Firebase nos dá a seguinte lista de provedores de Login:

firebase.google.com

Nesse post, vamos criar um exemplo de auth do Firebase com e-mail e senha. Vai ser bem simples, para que prolongarmos muito, mas vai te dar uma base para que possas evoluir com outros serviços de autenticação que necessites.

Criando o projeto no Firebase

Em primeiro lugar, precisamos criar um projeto no Firebase que ficará ligado ao nosso projeto Android. Para fazer isso, é só seguir as instruções abaixo:

  • Clique em criar novo projeto;
firebase.google.com
  • Defina o nome do seu projeto e aceite os termos do Firebase;
firebase.google.com
  • Se quiser, você pode habilitar o Google Analytics, mas não é obrigatório e você pode fazer isso depois;
firebase.google.com
  • Se você escolher configurar o Google Analytics, terá mais um passo;
firebase.google.com

Configurando o projeto no firebase

Lembra da lista de provedores de login que deixamos ali em cima? Para chegar lá, utilizamos o menu lateral e, ao clicar no item Desenvolvedor > Authentication, você terá acesso às opções de Usuários, Método de Login, Modelos e Uso.

  • Vá até “Método de Login” e ative o primeiro método que é de “E-mail/Senha”.
  • Volte para a tela inicial do seu projeto e, no menu superior, você vai encontrar um botão para adicionar o seu aplicativo. Mas calma lá, antes disso crie seu App no Android Studio, defina o nome do pacote e abra o projeto, pois você precisará dele.
  • Com o nome do pacote do seu projeto em mãos podemos continuar. Após clicar no botão “adicionar app”, vamos ter quatro opções. Escolha o tipo do seu projeto (Android, no nosso caso).
  • Use o comando abaixo para verificar sua SHA-1:

keytool -list -v \-alias androiddebugkey -keystore ~/.android/debug.keystore

Windows:

keytool -list -v \-alias androiddebugkey -keystore %USERPROFILE%\.android\debug.keystore

firebase.google.com

Aí é só seguir os passos indicados pelo Firebase. Você vai precisar fazer o download de um arquivo .json chamado google-services.json e adicionar na pasta app do seu projeto, adicionar o SDK do firebase e executar o app para validar se a conexão foi realizada. Neste momento, tem um “trick” que se não for realizado o projeto não vai se conectar. Dá uma olhada na próxima sessão.

Projeto Android

Com o Firebase configurado, damos início ao desenvolvimento do projeto. Vamos tomar como base um projeto que esteja utilizando Koin para injetar as dependências necessárias e MVVM como arquitetura.

  • No build.gradle do módulo app, adicione ao final do arquivo a seguinte linha de código:

apply plugin: ‘com.google.gms.google-services’

Isso vai possibilitar a leitura do arquivo que você adicionou no módulo app, além de aplicar algumas dependências que são necessárias para rodar os serviços solicitados ao Firebase.

  • Agora sim, você pode rodar o projeto e ele deverá se comunicar o Firebase e concluir a última etapa do processo de criação da aplicação.

Adicione as seguintes dependências de bibliotecas no seu projeto:

implementation “com.google.firebase:firebase-auth:19.1.0”
implementation “com.google.firebase:firebase-core:17.2.1”

Assim, você pode iniciar uma instância do Firebase e utilizar as dependências do login!

Utilizando o Firebase no Android

Bem, o primeiro passo depois da configuração inicial é inicializar uma instância do Firebase na aplicação. No meu caso, criei uma classe MyAppApplication que estende de Application do Android e setei para ser minha aplication do projeto.

import android.app.Application
import com.google.firebase.FirebaseApp
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin

class MyApplication : Application(){

override fun onCreate() {
super.onCreate()
FirebaseApp.initializeApp(this)
startKoin {
androidContext(this@MyApplication)
modules(listOf(
networkModule,
repositoryModule,
viewModelModule
))
properties(
mapOf(PROPERTY_BASE_URL to BuildConfig.BASE_URL))
}
}
}

Para frisar a parte que realmente interessa no post, temos que prestar atenção na seguinte linha de código:

FirebaseApp.initializeApp(this)

Com isso, estamos inicializando o Firebase no nosso projeto e passando para ele a aplicação na qual desejamos utilizá-lo.

Como estamos utilizando o MVVM como padrão de arquitetura e o Koin para injetar as dependências nas respectivas necessidades, criei os seguintes módulos que foram inicializados na imagem anterior:

val networkModule = module {
single{
FirebaseAuth.getInstance()
}
}
val repositoryModule = module {
single{ ServiceAuth(get()) as ServiceAuthContract }
}
val viewModelModule = module {
viewModel { AuthViewModel(get()) }
viewModel { SplashViewModel(get()) }
}

Logo, é possível perceber que temos duas classes no projeto, uma para fazer as requests ServiceAuth e outra para ser o controle dos dados AuthViewModel.

Para não acoplar o Service no ViewModel, criamos uma interface chamada ServiceAuthContract para definir os métodos que serão implementados e estarão disponíveis para o ViewModel, e ao invés de passarmos uma instância do Service, passamos uma instância do contrato. Perceba que realizamos um cast no módulo de repository que a idle nos indica que não está sendo utilizado. Porém, se o cast não for forçado, o Koin entende como uma instância da classe e não dá interface, e o código quebra em tempo de execução quando o koin tenta inicializar o ViewModel.

A interface descrita abaixo provê para o viewModel os métodos descritos por meio da inicialização a partir de uma classe que implementa esta interface.

interface ServiceAuthContract {

fun signIn(
email: String,
password: String,
success: (FirebaseUser?) -> Unit,
error: (Exception?) -> Unit
)

fun register(
email: String,
password: String,
success: (FirebaseUser?) -> Unit,
error: (Exception?) -> Unit
)

fun signOut()

}

Definimos que a classe ServiceAuth implementa a interface acima, e logo temos que sobrescrever os métodos solicitados. Aqui começamos a utilizar os métodos de autenticação da biblioteca do Firebase:

class ServiceAuth(
private val auth: FirebaseAuth
) : ServiceAuthContract {

override fun register(
email: String,
password: String,
success: (FirebaseUser?) -> Unit,
error: (Exception?) -> Unit
) { }

override fun signIn(
email: String,
password: String,
success: (FirebaseUser?) -> Unit,
error: (Exception?) -> Unit
) { }

override fun signOut(){ }

}

Note que auth é um objeto do tipo FirebaseAuth, injetado pelo koin. Neste objeto temos vários tipos de login, como mencionados anteriormente, tais como: Facebook, Google, Twitter e etc. Inclusive o que vamos utilizar, que é com E-mail/Password.

Neste momento você está se perguntando: “cadê o código que faz a autenticação?” Então, vamos ao que interessa!

override fun register(
email: String,
password: String,
success: (FirebaseUser?) -> Unit,
error: (Exception?) -> Unit
) {
auth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
Log.d("FIREBASE:", "Usuário criado com sucesso!")
success(auth.currentUser)
} else {
Log.w(
"FIREBASE:",
"Erro ao criar o usuário!",
task.exception)
error(task.exception)
}
}
}

Antes de realizar qualquer autenticação temos que ter um usuário criado. É claro que poderíamos criar diretamente no Firebase, mas com o código é mais legal, né? Então vamos lá!

Ao realizar a chamada do método createUserWithEmailAndPassword devemos passar como parâmetro o e-mail e a senha do usuário e deixar por conta do Firebase que ele vai fazer a conexão e nos retornar um usuário logado caso o usuário não exista ou então um erro informando que o e-mail já está sendo usado por outro usuário.

Daqui pra frente cabe ao desenvolvedor escolher o que fazer com o usuário logado, ou o erro! Vejamos então outro exemplo, mas agora com a função SignIn:

override fun signIn(
email: String,
password: String,
success: (FirebaseUser?) -> Unit,
error: (Exception?) -> Unit
) {
auth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
Log.d("FIREBASE:", "Usuário logado com sucesso!")
success(auth.currentUser)
} else {
Log.w(
"FIREBASE:",
"Erro de login!",
task.exception)
error(task.exception)
}
}
}

Neste caso, ao chamar a função signInWithEmailAndPassword, se o e-mail não estiver cadastrado a mensagem de erro do Firebase é que não existe nenhum usuário para este e-mail. Se a senha estiver incorreta retornará que usuário e/ou senha estão incorretos. E caso seja um login válido, temos como retorno um usuário logado do Firebase.

Ainda vale lembrar que podemos checar se já existe um usuário logado ao solicitar a instância do FirebaseAuth. Sem efetuar chamada de nenhuma função podemos verificar diretamente se algum usuário já está logado da seguinte forma:

FirebaseAuth.getInstance().currentUser

E, por fim, se for necessário realizar um logoff, podemos simplesmente chamar a função signOut.

Concluindo

Podemos perceber que o Firebase facilita muito a criação e controle de usuários. Para aplicações simples, não precisamos necessariamente criar do zero uma estrutura de back-end, visto que o Firebase já nos oferece poder suficiente para trabalhar com o controle de usuários de forma prática e objetiva. Quer saber mais? Dá uma olhada lá na documentação do próprio Firebase. Até a próxima!

--

--

Daivid Vasconcelos Leal
Accenture Digital Product Dev

Currently Master Student at UFRPE in Applied Computer Science with the field Quantum Computer, and Android Developer at Concrete Solutions.