Login do Android com a FirebaseUI

Este codelab faz parte do curso Android avançado no Kotlin. Você aproveitará mais o 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 avançados do Android em Kotlin (link em inglês).

Introdução

Ao criar um app Android, há muitos benefícios que podem vir do suporte ao login para seus usuários. Ao permitir que os usuários criem uma identidade no app, você pode oferecer mais formas de engajamento.

Com as contas personalizadas, os usuários podem personalizar a experiência no app, interagir com outros usuários e manter e transferir os dados se usarem o app em outro dispositivo, como a Web ou um novo smartphone.

Neste codelab, você aprenderá as noções básicas de compatibilidade com o login do seu app usando a biblioteca FirebaseUI. A biblioteca FirebaseUI simplifica muito o trabalho de desenvolvedores que querem criar um fluxo de login e faz o gerenciamento das contas de usuário.

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 compatibilidade com o login do seu app Android
  • Como observar o status de autenticação atual do app.
  • Como desconectar os usuários

Atividades do laboratório

  • Use o Console do Firebase para integrar o Firebase ao seu aplicativo.
  • Implemente o recurso de login.
  • Adicione personalizações no app para usuários conectados.
  • Implemente o logout de usuários.

Saiba mais sobre LiveData e ViewModel

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

Você também pode fazer o curso Developing Android Apps with Kotlin para saber mais sobre os tópicos fundamentais do Android que aprenderá neste codelab. Esse curso está disponível no curso Udacity e no codelabs.

Neste codelab, você criará um app que exibe fatos divertidos sobre o Android. Mais importante, o app terá um botão Login/Logout. Quando o usuário estiver conectado ao aplicativo, qualquer informação exibida no Android incluirá uma saudação, como forma de adicionar um toque de personalização.

Faça o download do app de exemplo:

Fazer o download do ZIP

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

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

Importante:como você integrará o app para usar o Firebase, será necessário fazer algumas configurações no app inicial para que ele seja criado e executado. Você fará isso na próxima etapa do codelab.

Etapa 1: criar um projeto do Firebase

Antes de adicionar o Firebase ao app Android, é preciso criar um projeto do Firebase e conectá-lo ao app.

  1. No Console do Firebase, clique em Adicionar projeto.
  2. Selecione ou insira um nome de projeto. Você pode nomear o projeto, mas escolha um nome relevante para o app que você 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 para 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. Digite o ID do aplicativo no campo Nome do pacote do Android. Insira o ID que seu app está usando, já que não será possível adicionar nem modificar esse valor depois de registrá-lo no projeto do Firebase.
  1. Um ID do aplicativo é chamado às vezes de nome do pacote.
  2. Esse ID do aplicativo é encontrado no arquivo Gradle do seu módulo (nível do app), geralmente app/build.gradle (ID de exemplo: com.yourcompany.yourproject).
  3. Digite o certificado de assinatura de depuração SHA-1. Para gerar essa chave, digite o seguinte no terminal de linha de comando:
keytool -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v -storepass android
  1. Clique em Register app.

Etapa 3: adicionar o arquivo de configuração do Firebase ao 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 seu arquivo de configuração para o diretório de módulos do seu app.

Etapa 4: configurar seu projeto Android para ativar 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 arquivo do Gradle (build.gradle) no nível raiz, adicione 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 módulo (nível do app), adicione uma linha na parte inferior 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 dependência do Firebase

Neste codelab, o principal motivo para integrar o Firebase é ter uma maneira de criar e gerenciar usuários. Para isso, você precisa adicionar 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 do firebase-auth permite gerenciar os usuários autenticados do aplicativo.

app/build.gradle:

implementation 'com.firebaseui:firebase-ui-auth:5.0.0'
  1. Sincronize seu projeto com arquivos do Gradle para garantir que todas as dependências estejam disponíveis para seu app. Se não for solicitado, escolha 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, você verá a tela inicial exibindo um fato curioso sobre o Android e um botão de login no canto superior esquerdo. Tocar no botão de login ainda não faz nada.

De modo geral, esse é um app de atividade única com vários fragmentos. A MainFragment contém toda a IU que você vê na tela abaixo. Você trabalhará com o LoginFragment e o SettingsFragment em um codelab de acompanhamento.

  1. Familiarize-se com o código. Mais especificamente, observe o seguinte:
  • FirebaseUserLiveData é a classe que você implementará para observar o usuário atual do Firebase associado ao app. Você usará a instância do FirebaseAuth como ponto de entrada para acessar essas informações do usuário em uma etapa posterior.
  • O MainFragment está vinculado ao LoginViewModel. LoginViewModel é a classe que você implementará para usar FirebaseUserLiveData para criar uma variável authenticationState. Ao usar essa variável authenticationState, o MainFragment pode observar o valor para atualizar a IU de acordo.

Nesta etapa, você usará o Console do Firebase para configurar os métodos de autenticação a que o app precisa ser compatível. Neste codelab, você vai permitir que os usuários façam login com um endereço de e-mail ou a Conta do Google deles.

  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 retornar ao console.
  2. Selecione o 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, alterne a chave Ativada e clique em Salvar.
  3. Da mesma forma, clique na linha Google.
  4. Alterne a chave Enabled, digite um E-mail de suporte do projeto e clique em Save.

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

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

MainFragment.kt (em inglês)

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 (em inglês)

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 inscrevam e façam login com o endereço de e-mail ou a Conta do Google deles. 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 seu app com essa combinação de endereços de e-mail e senha, mas isso não significa que ele também poderá fazer login em qualquer outro app com suporte do Firebase usando as mesmas credenciais.

  1. Em MainFragment.kt, você pode 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 detectar o resultado do processo de login ao filtrar quando SIGN_IN_REQUEST_CODE é transmitido de volta para onActivityResult(). Comece com alguns log statements para saber se o usuário fez login com sucesso.

MainFragment.kt (em inglês)

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 deve ser capaz de processar registros e usuários.

  1. Execute o app e verifique se ao tocar no botão Login você abre a tela de login.
  2. Agora, é possível fazer login com seu endereço de e-mail e sua senha ou com sua Conta do Google.
  3. Não haverá mudanças na IU após o login. Você implementará a atualização na próxima etapa, mas se tudo estiver funcionando corretamente, verá a mensagem de registro Successfully signed in user ${your name}! após passar pelo fluxo de registro.
  4. Você também pode acessar o Console do Firebase e navegar para Desenvolver > Authentication > Users para verificar se o app agora tem um usuário registrado.
  5. Quando os usuários criam uma conta para seu app, ela é vinculada especificamente ao app e não a qualquer app que use o Firebase para a funcionalidade de login.

Nesta tarefa, você implementará a atualização da IU com base no estado da autenticação. Quando o usuário estiver conectado, você pode personalizar a tela inicial exibindo o nome. O botão Login também será atualizado para Logout quando o usuário estiver conectado.

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

FirebaseUserLiveData.kt (em inglês)

private val authStateListener = FirebaseAuth.AuthStateListener { firebaseAuth ->
   value = firebaseAuth.currentUser
}
  1. Abra o 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 agora podem consultar se o usuário está conectado ou não pelo LoginViewModel.

LoginViewModel.kt (link em inglês)

val authenticationState = FirebaseUserLiveData().map { user ->
   if (user != null) {
       AuthenticationState.AUTHENTICATED
   } else {
       AuthenticationState.UNAUTHENTICATED
   }
}
  1. Abrir MainFragment.kt.
  2. Na observeAuthenticationState() do MainFragment.kt, é possível usar a variável authenticationState que você acabou de adicionar na LoginViewModel e mudar a IU de acordo. Se houver um usuário conectado, o authButton exibirá Sair.

MainFragment.kt (em inglês)

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 tiver feito login, também será possível personalizar a mensagem de boas-vindas exibida usando a função getFactWithPersonalization() fornecida no MainFragment.

MainFragment.kt (em inglês)

binding.welcomeText.text = getFactWithPersonalization(factToDisplay)
  1. Por fim, se não houver um usuário conectado (quando authenticationState não for LoginViewModel.AuthenticationState.AUTHENTICATED), auth_button exibirá Login e abrirá a tela de login quando clicado. Também não deve haver personalização da mensagem exibida.

MainFragment.kt (em inglês)

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

Com todas as etapas concluídas, seu método final observeAuthenticationState() ficará semelhante ao código abaixo.

MainFragment.kt (em inglês)

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 IU será atualizada se o usuário estiver conectado ou não. Se tudo estiver funcionando corretamente e você tiver feito login, a tela inicial será exibida pelo seu nome e exibirá um fato Android. Agora, o botão Login também exibirá Logout.

Nesta tarefa, você implementará o recurso de saída.

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

AuthUI.getInstance().signOut(requireContext())
  1. Abra o MainFragment.kt
  2. No observeAuthenticationState() do MainFragment.kt, adicione a lógica de saída para que o auth_button funcione corretamente quando houver um usuário conectado. O resultado final do método é semelhante ao código abaixo.

MainFragment.kt (em inglês)

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 confirme que o usuário saiu, e o estado do botão mudou para Login.

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

Neste codelab, você aprendeu:

  • Como adicionar o Firebase ao seu projeto adicionando as dependências necessárias no arquivo do Gradle e configurando o projeto no Console do Firebase.
  • Como implementar o login para seu app usando a biblioteca FirebaseUI e especificando como você quer permitir que os usuários façam login. Todas as contas criadas por um usuário no seu aplicativo são específicas e não são compartilhadas com todos os aplicativos que utilizam o Firebase para a funcionalidade de login.
  • Como observar o status atual de autenticação do seu app usando o LiveData.
  • Como desconectar os usuários.

Este codelab aborda as noções básicas de como oferecer compatibilidade com o login de um app Android.

Neste codelab, os usuários puderam se registrar e fazer login com o endereço de e-mail deles. No entanto, com a biblioteca FirebaseUI, você também pode 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 utilizar 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 ver links de outros codelabs neste curso, consulte a página de destino dos codelabs avançados no Android.