Login do Android com o FirebaseUI

Este codelab faz parte do curso Android avançado no Kotlin. Você vai aproveitar mais este curso se fizer os codelabs em sequência, mas isso não é obrigatório. Todos os codelabs do curso estão listados na página de destino dos codelabs do Android avançado em Kotlin.

Introdução

Ao criar um app Android, há muitos benefícios em oferecer suporte ao login para os usuários. Ao permitir que os usuários criem uma identidade no seu app, você oferece mais maneiras de interagir com ele.

Com as contas personalizadas, os usuários podem personalizar a experiência no app, interagir com outras pessoas e ter os dados mantidos e transferidos se usarem o app em outro dispositivo (como a Web ou um novo smartphone).

Neste codelab, você vai aprender os conceitos básicos de como oferecer suporte ao login no seu app usando a biblioteca FirebaseUI. Entre muitas outras coisas, a biblioteca FirebaseUI facilita o trabalho dos desenvolvedores que querem criar um fluxo de login e gerencia as contas de usuário para você.

O que você já precisa saber

  • Conceitos básicos de como criar um app Android
  • LiveData e ViewModel

O que você vai aprender

  • Como adicionar o Firebase ao seu projeto
  • Como oferecer suporte ao login no seu app Android
  • Como observar o status de autenticação atual do seu app
  • Como desconectar usuários

Atividades deste laboratório

  • Use o console do Firebase para integrar o Firebase ao seu app.
  • Implemente o recurso de login.
  • Adicione personalizações no app para usuários conectados.
  • Implemente a saída dos usuários.

Saiba mais sobre LiveData e ViewModel

Para o app neste codelab, você precisa ter uma compreensão básica de LiveData e ViewModel. Leia as visões gerais do LiveData e do ViewModel se quiser uma breve visão geral desses conceitos.

Você também pode fazer o curso Desenvolvimento de apps Android com Kotlin para aprender sobre temas fundamentais do Android que vai encontrar neste codelab. Esse curso está disponível como um curso da Udacity e um curso de codelabs.

Neste codelab, você vai criar um app que mostra fatos divertidos sobre o Android. E o mais importante: o app terá um botão Fazer login/Sair. Quando o usuário faz login no app, qualquer fato do Android exibido inclui uma saudação para adicionar um toque de personalização.

Para fazer o download do app de exemplo, você pode:

Fazer o download do ZIP

... ou clone o repositório do GitHub pela linha de comando usando o comando abaixo e mude para a ramificação start do repositório:

$  git clone https://github.com/googlecodelabs/android-kotlin-login

Importante:como você vai integrar o app para usar o Firebase, o app inicial requer alguma configuração para ser criado e executado. Você vai fazer isso na próxima etapa do codelab.

Etapa 1: criar um projeto do Firebase

Antes de adicionar o Firebase ao seu app Android, é preciso criar um projeto do Firebase para conectar ao app.

  1. No console do Firebase, clique em Adicionar projeto.
  2. Selecione ou insira um Nome do projeto. Você pode nomear seu projeto como quiser, mas tente escolher um nome relevante para o app que está criando.
  3. Clique em Continuar.
  4. Você pode pular a configuração do Google Analytics e escolher a opção Agora não.
  5. Clique em Criar projeto para concluir a configuração do projeto do Firebase.

Etapa 2: registrar seu app com o Firebase

Agora que você tem um projeto do Firebase, é possível adicionar seu app Android a ele.

  1. No centro da página de visão geral do projeto do Console do Firebase, clique no ícone do Android para iniciar o fluxo de trabalho de configuração.
  2. Insira o ID do aplicativo no campo Nome do pacote do Android. Insira o ID que o app está usando, já que não é possível adicionar ou modificar esse valor depois de registrar o app no projeto do Firebase.
  1. Às vezes, um ID do aplicativo é chamado de nome do pacote.
  2. Encontre esse ID no módulo (nível do app) do arquivo do Gradle, geralmente app/build.gradle (ID de exemplo: com.yourcompany.yourproject).
  3. Insira o certificado de assinatura SHA-1 de depuração. Para gerar essa chave, insira o seguinte comando no terminal da linha de comando.
keytool -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v -storepass android
  1. Clique em Registrar app.

Etapa 3: adicionar o arquivo de configuração do Firebase ao seu projeto

Adicione o arquivo de configuração do Firebase para Android ao app:

  1. Clique em Fazer o download do google-services.json para receber o arquivo de configuração do Firebase para Android (google-services.json).
  1. Mova o arquivo de configuração para o diretório do módulo (nível do app) do seu app.

Etapa 4: configurar seu projeto Android para ativar os produtos do Firebase

  1. Para ativar os produtos do Firebase no seu app, adicione o plug-in google-services aos seus arquivos do Gradle.
  1. No nível raiz (do projeto) do arquivo Gradle (build.gradle), adicione as regras para incluir o plug-in do Google Services. Verifique se você também tem o repositório Maven do Google.

build.gradle

buildscript {

  repositories {
    // Check that you have the following line (if not, add it):
    google()  // Google's Maven repository
  }

  dependencies {
    // ...

    // Add the following line:
    classpath 'com.google.gms:google-services:4.3.0'  // Google Services plugin
  }
}

allprojects {
  // ...

  repositories {
    // Check that you have the following line (if not, add it):
    google()  // Google's Maven repository
    // ...
  }
}
  1. No arquivo do Gradle (geralmente app/build.gradle) do seu módulo (nível do app), adicione uma linha na parte de baixo do arquivo.

app/build.gradle

apply plugin: 'com.android.application'

android {
  // ...
}

// Add the following line to the bottom of the file:
apply plugin: 'com.google.gms.google-services'  // Google Play services Gradle plugin

Etapa 4: adicionar a dependência do Firebase

Neste codelab, o principal motivo para integrar o Firebase é ter uma maneira de criar e gerenciar usuários. Para isso, adicione uma biblioteca do Firebase que permita implementar o login.

  1. Adicione a seguinte dependência ao arquivo build.gradle (Module:app) para usar o SDK no app. O SDK firebase-auth permite o gerenciamento de usuários autenticados do aplicativo.

app/build.gradle:

implementation 'com.firebaseui:firebase-ui-auth:5.0.0'
  1. Sincronize seu projeto com os arquivos Gradle para garantir que todas as dependências estejam disponíveis para o app. Se não for solicitado, selecione File > Sync Project with Gradle Files no Android Studio ou na barra de ferramentas.

Etapa 5: executar o app e inspecionar o código

  1. Execute o app em um emulador ou dispositivo físico para garantir que o ambiente esteja configurado corretamente para iniciar o desenvolvimento.

Se tudo der certo, a tela inicial vai mostrar uma curiosidade divertida sobre o Android e um botão de login no canto superior esquerdo. Tocar no botão de login ainda não faz nada.

Em um nível alto, esse é um app de atividade única com vários fragmentos. O MainFragment contém toda a interface que você vê na tela abaixo. Você vai trabalhar com o LoginFragment e o SettingsFragment em um codelab de acompanhamento.

  1. Conheça o código. Em particular, observe:
  • FirebaseUserLiveData é a classe que você vai implementar para observar o usuário atual do Firebase associado ao app. Você vai usar a instância FirebaseAuth como um ponto de entrada para receber essas informações do usuário em uma etapa posterior.
  • O MainFragment está vinculado ao LoginViewModel. LoginViewModel é a classe que você vai implementar para usar FirebaseUserLiveData e criar uma variável authenticationState. Usando essa variável authenticationState, MainFragment pode observar o valor para atualizar a interface de acordo.

Nesta etapa, você vai usar o console do Firebase para configurar os métodos de autenticação que quer que seu app ofereça suporte. Neste codelab, você vai se concentrar em permitir que os usuários façam login com um endereço de e-mail fornecido ou com a Conta do Google.

  1. Navegue até o Console do Firebase. Observação: se você ainda estiver no fluxo de trabalho "Adicionar Firebase", clique no X no canto superior esquerdo para voltar ao console.
  2. Selecione seu projeto, caso ainda não esteja nele.
  3. Abra a navegação à esquerda e selecione Desenvolver > Autenticação .

  1. Selecione a guia Método de login na barra de navegação superior.

  1. Clique na linha E-mail/Senha.
  2. No pop-up, ative a chave Ativado e clique em Salvar.
  3. Da mesma forma, clique na linha Google.
  4. Ative a chave Ativado, insira um E-mail de suporte do projeto e clique em Salvar.

Nesta tarefa, você vai implementar o recurso de login para seus usuários.

  1. Abra MainFragment.kt.
  2. No layout do MainFragment, observe o auth_button. No momento, ele não está configurado para processar entradas do usuário.
  3. Em onViewCreated(),, adicione um onClickListener a auth_button para chamar launchSignInFlow().

MainFragment.kt

binding.authButton.setOnClickListener { launchSignInFlow() }
  1. Procure o método launchSignInFlow() em MainFragment.kt. No momento, ele contém um TODO.
  2. Conclua a função launchSignInFlow() conforme mostrado abaixo.

MainFragment.kt

private fun launchSignInFlow() {
   // Give users the option to sign in / register with their email or Google account.
   // If users choose to register with their email,
   // they will need to create a password as well.
   val providers = arrayListOf(
       AuthUI.IdpConfig.EmailBuilder().build(), AuthUI.IdpConfig.GoogleBuilder().build()

       // This is where you can provide more ways for users to register and 
       // sign in.
   )

   // Create and launch sign-in intent.
   // We listen to the response of this activity with the
   // SIGN_IN_REQUEST_CODE 
   startActivityForResult(
       AuthUI.getInstance()
           .createSignInIntentBuilder()
           .setAvailableProviders(providers)
           .build(),
       MainFragment.SIGN_IN_REQUEST_CODE
   )
}

Isso permite que os usuários se registrem e façam login com o endereço de e-mail ou a Conta do Google. Se o usuário escolher se registrar com o endereço de e-mail, a combinação de e-mail e senha criada será exclusiva para seu app. Isso significa que ele poderá fazer login no app com a combinação de e-mail e senha, mas não poderá fazer login em nenhum outro app compatível com o Firebase usando as mesmas credenciais.

  1. Em MainFragment.kt, é possível detectar o resultado do processo de login implementando o método onActivityResult(), conforme mostrado abaixo. Como você iniciou o processo de login com SIGN_IN_REQUEST_CODE, também é possível ouvir o resultado filtrando quando SIGN_IN_REQUEST_CODE é transmitido de volta para onActivityResult(). Comece com algumas instruções de registro para saber se o usuário fez login com sucesso.

MainFragment.kt

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
   super.onActivityResult(requestCode, resultCode, data)
   if (requestCode == SIGN_IN_REQUEST_CODE) {
       val response = IdpResponse.fromResultIntent(data)
       if (resultCode == Activity.RESULT_OK) {
           // User successfully signed in
           Log.i(TAG, "Successfully signed in user ${FirebaseAuth.getInstance().currentUser?.displayName}!")
       } else {
           // Sign in failed. If response is null the user canceled the
           // sign-in flow using the back button. Otherwise check
           // response.getError().getErrorCode() and handle the error.
           Log.i(TAG, "Sign in unsuccessful ${response?.error?.errorCode}")
       }
   }
}

Agora seu app pode registrar e fazer login de usuários.

  1. Execute o app e verifique se tocar no botão Login abre a tela de login.
  2. Agora você pode fazer login com seu endereço de e-mail e uma senha ou com sua Conta do Google.
  3. Não haverá mudanças na interface depois que você fizer login (a atualização da interface será implementada na próxima etapa), mas, se tudo estiver funcionando corretamente, a mensagem de registro Successfully signed in user ${your name}! vai aparecer depois que você passar pelo fluxo de inscrição.
  4. Você também pode acessar o console do Firebase e navegar até Desenvolver > Autenticação > Usuários para verificar se o app tem um usuário registrado.
  5. Quando os usuários criam uma conta para seu app, ela fica vinculada especificamente a ele, e não a qualquer outro app que use o Firebase para a funcionalidade de login.

Nesta tarefa, você vai implementar a atualização da interface com base no estado de autenticação. Quando o usuário faz login, é possível personalizar a tela inicial mostrando o nome dele. Você também vai atualizar o botão Login para Logout quando o usuário fizer login.

  1. Abra a classe FirebaseUserLiveData.kt, que já foi criada para você. A primeira coisa que você precisa fazer é fornecer uma maneira para que outras classes no app saibam quando um usuário fez login ou logout. No entanto, a classe ainda não faz nada, porque o valor de LiveData não está sendo atualizado.
  2. Como você está usando a biblioteca FirebaseAuth, é possível detectar mudanças no usuário conectado com o callback FirebaseUser.AuthStateListener, que é implementado para você como parte da biblioteca FirebaseUI. Esse callback é acionado sempre que um usuário faz login ou logout no seu app.
  3. Observe que FirebaseUserLiveData.kt define a variável authStateListener. Você vai usar essa variável para armazenar o valor de LiveData. A variável authStateListener foi criada para que você possa iniciar e interromper corretamente a escuta de mudanças no estado de autenticação com base no estado do seu aplicativo. Por exemplo, se o usuário colocar o app em segundo plano, ele vai parar de detectar mudanças no estado de autenticação para evitar possíveis vazamentos de memória.
  4. Atualize authStateListener para que o valor de FirebaseUserLiveData corresponda ao usuário atual do Firebase.

FirebaseUserLiveData.kt

private val authStateListener = FirebaseAuth.AuthStateListener { firebaseAuth ->
   value = firebaseAuth.currentUser
}
  1. Abra LoginViewModel.kt.
  2. Em LoginViewModel.kt, crie uma variável authenticationState com base no objeto FirebaseUserLiveData que você acabou de implementar. Ao criar essa variável authenticationState, outras classes podem consultar se o usuário fez login ou não usando o LoginViewModel.

LoginViewModel.kt

val authenticationState = FirebaseUserLiveData().map { user ->
   if (user != null) {
       AuthenticationState.AUTHENTICATED
   } else {
       AuthenticationState.UNAUTHENTICATED
   }
}
  1. Abrir MainFragment.kt.
  2. No observeAuthenticationState() do MainFragment.kt, use a variável authenticationState que você acabou de adicionar em LoginViewModel e mude a interface de acordo. Se houver um usuário conectado, authButton vai mostrar Sair.

MainFragment.kt

private fun observeAuthenticationState() {
   val factToDisplay = viewModel.getFactToDisplay(requireContext())

   viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
       when (authenticationState) {
           LoginViewModel.AuthenticationState.AUTHENTICATED -> {
               binding.authButton.text = getString(R.string.logout_button_text)
               binding.authButton.setOnClickListener {
                   // TODO implement logging out user in next step
               }

                // TODO 2. If the user is logged in, 
                 // you can customize the welcome message they see by
                 // utilizing the getFactWithPersonalization() function provided

           }
           else -> {
               // TODO 3. Lastly, if there is no logged-in user, 
                // auth_button should display Login and
                //  launch the sign in screen when clicked.
           }
       }
   })
}
  1. Se o usuário estiver conectado, você também poderá personalizar a mensagem de boas-vindas que ele vê usando a função getFactWithPersonalization() fornecida em MainFragment.
    .

MainFragment.kt

binding.welcomeText.text = getFactWithPersonalization(factToDisplay)
  1. Por fim, se não houver um usuário conectado (quando authenticationState for diferente de LoginViewModel.AuthenticationState.AUTHENTICATED), auth_button vai mostrar Fazer login e abrir a tela de login quando clicado. A mensagem exibida também não pode ser personalizada.

MainFragment.kt

binding.authButton.text = getString(R.string.login_button_text)
binding.authButton.setOnClickListener { launchSignInFlow() }
binding.welcomeText.text = factToDisplay

Com todas as etapas concluídas, o método observeAuthenticationState() final vai ficar parecido com o código abaixo.

MainFragment.kt

private fun observeAuthenticationState() {
   val factToDisplay = viewModel.getFactToDisplay(requireContext())

   viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
        // TODO 1. Use the authenticationState variable you just added 
         // in LoginViewModel and change the UI accordingly.
       when (authenticationState) {
            // TODO 2.  If the user is logged in, 
             // you can customize the welcome message they see by
             // utilizing the getFactWithPersonalization() function provided
           LoginViewModel.AuthenticationState.AUTHENTICATED -> {
               binding.welcomeText.text = getFactWithPersonalization(factToDisplay)
               binding.authButton.text = getString(R.string.logout_button_text)
               binding.authButton.setOnClickListener {
                   // TODO implement logging out user in next step
               }
           }
           else -> {
                // TODO 3. Lastly, if there is no logged-in user, 
                 // auth_button should display Login and
                 // launch the sign in screen when clicked.
               binding.welcomeText.text = factToDisplay

               binding.authButton.text = getString(R.string.login_button_text)
               binding.authButton.setOnClickListener {
                   launchSignInFlow()
               }
           }
       }
   })
}
  1. Execute o app. A interface vai ser atualizada de acordo com o status de login do usuário. Se tudo estiver funcionando corretamente e você estiver conectado, a tela inicial vai mostrar seu nome e um fato sobre o Android. O botão Login também vai mostrar Logout.

Nesta tarefa, você vai implementar o recurso de logout.

Como o app permite que os usuários façam login, ele também precisa oferecer uma maneira de fazer logout. Confira um exemplo de como fazer logout de um usuário com apenas uma linha de código:

AuthUI.getInstance().signOut(requireContext())
  1. Abra MainFragment.kt.
  2. No observeAuthenticationState() de MainFragment.kt, adicione a lógica de logout para que as funções auth_button funcionem corretamente quando houver um usuário conectado. O resultado final do método é parecido com o código abaixo.

MainFragment.kt

private fun observeAuthenticationState() {
   val factToDisplay = viewModel.getFactToDisplay(requireContext())

   viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
       when (authenticationState) {
           LoginViewModel.AuthenticationState.AUTHENTICATED -> {
               binding.welcomeText.text = getFactWithPersonalization(factToDisplay)

               binding.authButton.text = getString(R.string.logout_button_text)
               binding.authButton.setOnClickListener {
                   AuthUI.getInstance().signOut(requireContext())
               }
           }
           else -> {
               binding.welcomeText.text = factToDisplay

               binding.authButton.text = getString(R.string.login_button_text)
               binding.authButton.setOnClickListener {
                   launchSignInFlow()
               }
           }
       }
   })
}
  1. Execute o app.
  2. Toque no botão Sair e verifique se o usuário fez logout e se o estado do botão mudou para Fazer login.

Confira a versão final do app concluído aqui: https://github.com/googlecodelabs/android-kotlin-login.

Neste codelab, você aprendeu como:

  • Como adicionar o Firebase ao seu projeto adicionando as dependências necessárias ao arquivo gradle e configurando o projeto no console do Firebase.
  • Como implementar o login no seu app usando a biblioteca FirebaseUI e especificando como você quer permitir que os usuários façam login. Qualquer conta criada por um usuário no seu app é específica apenas para ele e não é compartilhada com todos os apps que usam o Firebase para a funcionalidade de login.
  • Como observar o status de autenticação atual do seu app usando LiveData.
  • Como desconectar usuários.

Este codelab abordou os conceitos básicos de como oferecer suporte ao login em um app Android.

Neste codelab, você permitiu que os usuários se registrassem e fizessem login com o endereço de e-mail. No entanto, com a biblioteca FirebaseUI, também é possível oferecer suporte a outros métodos de autenticação, como fazer login com um número de telefone. Para saber mais sobre os recursos da biblioteca FirebaseUI e como usar outras funcionalidades que ela oferece, confira os seguintes recursos:

Para saber mais sobre as práticas recomendadas de login, confira estes outros recursos:

Codelabs:

Documentação do desenvolvedor Android:

Vídeos:

Para acessar links de outros codelabs deste curso, consulte a página inicial dos codelabs do curso Android avançado no Kotlin.