Accesso ad Android con FirebaseUI

Questo codelab fa parte del corso Advanced Android in Kotlin. Otterrai il massimo valore da questo corso se lavori in sequenza nei codelab, ma non è obbligatorio. Tutti i codelab del corso sono elencati nella pagina di destinazione avanzata per i codelab di Android in Kotlin.

Introduzione

Lo sviluppo dell'app per Android può comportare diversi vantaggi. Se consenti agli utenti di creare un'identità all'interno della tua app, puoi offrire loro altri modi per interagire con l'app.

Con gli account personalizzati gli utenti possono personalizzare la propria esperienza in-app, interagire con altri utenti e mantenere i propri dati e trasferirli se utilizzano l'app su un altro dispositivo (ad esempio su Web o su un nuovo telefono).

In questo codelab, imparerai le nozioni di base su come supportare l'accesso alla tua app utilizzando la libreria Firebase. Tra le altre cose, la libreria FirebaseUI rende facile agli sviluppatori che vogliono creare un flusso di accesso e gestisce il lavoro della gestione degli account utente al posto tuo.

Informazioni importanti

  • Nozioni di base sulla creazione di un'app Android
  • LiveData e ViewModel

Obiettivi didattici

  • Come aggiungere Firebase al tuo progetto
  • Come supportare l'accesso alla tua app Android
  • Come controllare lo stato di autenticazione attuale dell'app
  • Come disconnettere gli utenti

In questo lab proverai a:

  • Utilizzare la Console Firebase per integrare Firebase nella tua app.
  • Implementare la funzionalità di accesso.
  • Aggiungi personalizzazioni nell'app per gli utenti che hanno eseguito l'accesso.
  • Implementare la disconnessione degli utenti.

Scopri di più su LiveData e ViewModel

Per l'app in questo codelab, è necessaria una conoscenza di base di LiveData e Viewmodel. Leggi le panoramiche LiveData e Viewmodel se vuoi una breve panoramica di questi concetti.

Puoi anche seguire il corso Sviluppo di app Android con Kotlin per scoprire gli argomenti fondamentali di Android che incontrerai nell'ambito di questo codelab. Il corso è disponibile sia come corso su Udacity sia come corso su codelab.

In questo codelab, creerai un'app che mostra curiosità su Android. Aspetto ancora più importante: l'app ha un pulsante Accedi/Esci. Quando l'utente ha eseguito l'accesso all'app, qualsiasi informazione mostrata su Android mostrerà un saluto all'utente per aggiungere un tocco di personalizzazione.

Per scaricare l'app di esempio, puoi:

Scarica Zip

... oppure clona il repository GitHub dalla riga di comando utilizzando il comando seguente e passa al ramo start del repository:

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

Importante: dato che integrerai l'app per utilizzare Firebase, l'app iniziale dovrà essere configurata in modo da poter essere creata ed eseguita. Dovrai farlo nel passaggio successivo del codelab.

Passaggio 1: crea un progetto Firebase

Prima di poter aggiungere Firebase alla tua app Android, devi creare un progetto Firebase per connetterti all'app.

  1. Nella Console Firebase, fai clic su Aggiungi progetto.
  2. Seleziona o inserisci un Nome progetto. Puoi assegnare un nome al progetto qualsiasi, ma cerca di scegliere un nome pertinente all'app che stai creando.
  3. Fai clic su Continua.
  4. Puoi saltare la configurazione di Google Analytics e scegliere l'opzione Non ora.
  5. Fai clic su Crea progetto per completare la configurazione del progetto Firebase.

Passaggio 2: registra la tua app con Firebase

Ora che hai creato un progetto Firebase, puoi aggiungervi l'app per Android.

  1. Al centro della pagina Panoramica del progetto della Console Firebase, fai clic sull'icona Android per avviare il flusso di lavoro di configurazione.
  2. Inserisci l'ID applicazione della tua app nel campo Nome del pacchetto Android. Assicurati di inserire l'ID utilizzato dalla tua app, poiché non potrai aggiungere o modificare questo valore dopo aver registrato l'app con il tuo progetto Firebase.
  1. Un ID applicazione è a volte indicato come nome del pacchetto.
  2. Trova questo ID applicazione nel file Gradle del tuo modulo (a livello di app), in genere app/build.gradle (ID esempio: com.yourcompany.yourproject).
  3. Inserisci il certificato SHA-1 per la firma di debug. Puoi generare questa chiave inserendo il seguente comando nel terminale della riga di comando.
keytool -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v -storepass android
  1. Fai clic su Registra app.

Passaggio 3: aggiungi il file di configurazione Firebase al progetto

Aggiungi il file di configurazione di Firebase Android alla tua app:

  1. Fai clic su Scarica google-services.json per ottenere il file di configurazione di Firebase Android (google-services.json).
  • Puoi scaricare di nuovo il file di configurazione Android di Firebase in qualsiasi momento.
  • Assicurati che al file di configurazione non siano aggiunti caratteri aggiuntivi e che abbia il nome google-services.json
  1. Sposta il file di configurazione nella directory del modulo (a livello di app) dell'app.

Passaggio 4: configura il progetto Android per attivare i prodotti Firebase

  1. Per attivare i prodotti Firebase nella tua app, aggiungi il plug-in google-services ai tuoi file Gradle.
  1. Nel file Gradle a livello di progetto (build.gradle) a livello di progetto, aggiungi le regole per includere il plug-in Servizi Google. Verifica di avere anche il repository Maven di 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. Nel file Gradle del tuo modulo (a livello di app, in genere app/build.gradle), aggiungi una riga alla fine del file.

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

Passaggio 4: aggiungi la dipendenza Firebase

In questo codelab, il motivo principale per l'integrazione di Firebase è la creazione e la gestione di utenti. Per farlo, devi aggiungere una libreria Firebase che ti consenta di implementare l'accesso.

  1. Aggiungi la seguente dipendenza al file build.gradle (Module:app) in modo da poter utilizzare l'SDK nella tua app. L'SDK firebase-auth consente la gestione degli utenti autenticati della tua applicazione.

app/build.gradle

implementation 'com.firebaseui:firebase-ui-auth:5.0.0'
  1. Sincronizza il tuo progetto con file gradle per assicurarti che tutte le dipendenze siano disponibili per la tua app. Se non richiesto, scegli File > Sync Project with Gradle Files in Android Studio o dalla barra degli strumenti.

Passaggio 5: esegui l'app e analizza il codice

  1. Esegui l'app su un emulatore o un dispositivo fisico per assicurarti che il tuo ambiente sia configurato correttamente per iniziare lo sviluppo.

In caso di esito positivo, dovresti visualizzare la schermata Home con una curiosità su Android e un pulsante di accesso nell'angolo in alto a sinistra. Non devi fare nulla se tocchi il pulsante di accesso.

In linea generale, si tratta di un'unica app per attività con più frammenti. L'elemento MainFragment contiene tutta l'UI che vedi nella schermata di seguito. Lavorerai con LoginFragment e SettingsFragment in un codelab di follow-up.

  1. Familiarizza con il codice. In particolare, tieni presente quanto segue:
  • FirebaseUserLiveData è la classe che implementerai per osservare l'utente Firebase attuale associato all'app. Utilizzerai l'istanza FirebaseAuth come punto di contatto per recuperare queste informazioni dell'utente in un passaggio successivo.
  • MainFragment è legato a LoginViewModel. LoginViewModel è la classe che implementerai per utilizzare FirebaseUserLiveData per creare una variabile authenticationState. Utilizzando questa variabile authenticationState, MainFragment può quindi osservare il valore per aggiornare l'interfaccia utente di conseguenza.

In questo passaggio utilizzerai la Console Firebase per configurare i metodi di autenticazione che vuoi vengano supportati dalla tua app. Per questo codelab, ti concentrerai sulla possibilità di consentire agli utenti di accedere con un indirizzo email fornito o con il proprio Account Google.

  1. Vai alla Console Firebase. (Nota: se sei ancora nel flusso di lavoro di Aggiungi Firebase, fai clic sulla X nell'angolo in alto a sinistra per tornare alla console.
  2. Seleziona il progetto, se non è già presente.
  3. Apri il menu di navigazione a sinistra e seleziona Sviluppo > Autenticazione.

  1. Seleziona la scheda Metodo di accesso nella barra di navigazione in alto.

  1. Fai clic sulla riga Email/password.
  2. Nella finestra popup, attiva l'opzione Attiva e fai clic su Salva.
  3. Allo stesso modo, fai clic sulla riga Google.
  4. Attiva l'opzione Abilitata, inserisci un indirizzo email dell'assistenza e fai clic su Salva.

In questa attività implementerai la funzionalità di accesso per gli utenti.

  1. Apri MainFragment.kt.
  2. Nel layout di MainFragment, nota il auth_button. Attualmente non è configurato per gestire gli input degli utenti.
  3. In onViewCreated(), aggiungi un onClickListener a auth_button per chiamare launchSignInFlow().

Fragment.kt principale

binding.authButton.setOnClickListener { launchSignInFlow() }
  1. Cerca il metodo launchSignInFlow() in MainFragment.kt. Al momento contiene un elemento TODO.
  2. Completa la funzione launchSignInFlow() come mostrato di seguito.

Fragment.kt principale

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
   )
}

Questa operazione consente agli utenti di registrarsi e accedere con il proprio indirizzo email o Account Google. Se l'utente sceglie di registrarsi con il proprio indirizzo email, la combinazione di indirizzo email e password creata è univoca per la tua app. Ciò significa che potrà accedere alla tua app con la combinazione di indirizzo email e password, ma non potrà accedere a qualsiasi altra app supportata da Firebase con le stesse credenziali.

  1. In MainFragment.kt puoi ascoltare il risultato della procedura di accesso implementando il metodo onActivityResult(), come mostrato di seguito. Da quando hai iniziato la procedura di accesso con SIGN_IN_REQUEST_CODE, puoi anche ascoltare il risultato della procedura di accesso filtrando per quando SIGN_IN_REQUEST_CODE viene restituito a onActivityResult(). Inizia con alcune istruzioni di log per capire se l'utente ha eseguito l'accesso.

Fragment.kt principale

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}")
       }
   }
}

Ora la tua app dovrebbe essere in grado di gestire la registrazione e l'accesso degli utenti.

  1. Esegui l'app e verifica che il tocco sul pulsante Accedi mostri la schermata di accesso.
  2. Ora puoi accedere con il tuo indirizzo email e una password o con il tuo Account Google.
  3. Una volta eseguito l'accesso, l'interfaccia utente non verrà modificata dopo aver eseguito l'aggiornamento (nel passaggio successivo), ma se tutto funziona correttamente, dopo il completamento del flusso di registrazione dovrebbe essere visualizzato il messaggio di log Successfully signed in user ${your name}!.
  4. Puoi anche accedere alla Console Firebase e selezionare Sviluppo > Autenticazione > Utenti per verificare che l'app ora abbia un utente registrato.
  5. Tieni presente che quando gli utenti creano un account per la tua app, questo account è collegato esclusivamente all'app e non a qualsiasi app che utilizza Firebase per la funzionalità di accesso.

In questa attività, implementerai l'aggiornamento dell'interfaccia utente in base allo stato di autenticazione. Se l'utente ha eseguito l'accesso, puoi personalizzare la schermata Home visualizzandone il nome. Inoltre, il pulsante Login (Accesso) diventerà Logout (Accesso) quando l'utente avrà eseguito l'accesso.

  1. Apri il corso FirebaseUserLiveData.kt, che è già stato creato per te. La prima cosa da fare è fornire agli altri corsi nell'app un modo per sapere quando un utente ha eseguito l'accesso o è uscito. Tuttavia, il corso non fa ancora nulla perché il valore di LiveData non viene aggiornato.
  2. Poiché utilizzi la libreria FirebaseAuth, puoi ascoltare le modifiche apportate all'utente che ha eseguito l'accesso con il callback FirebaseUser.AuthStateListener implementato automaticamente per te all'interno della libreria FirebaseUI. Questo callback viene attivato ogni volta che un utente accede o esce dalla tua app.
  3. Tieni presente che FirebaseUserLiveData.kt definisce la variabile authStateListener. Utilizzerai questa variabile per memorizzare il valore di LiveData. La variabile authStateListener è stata creata, in modo da poter avviare e interrompere correttamente l'ascolto delle modifiche in stato di autenticazione in base allo stato dell'applicazione. Ad esempio, se l'utente inserisce l'app in background, l'app non deve più ascoltare le modifiche dello stato di autenticazione per evitare potenziali perdite di memoria.
  4. Aggiorna authStateListener in modo che il valore della variabile FirebaseUserLiveData corrisponda all'attuale utente Firebase.

FirebaseUserLiveData.kt

private val authStateListener = FirebaseAuth.AuthStateListener { firebaseAuth ->
   value = firebaseAuth.currentUser
}
  1. Apri LoginViewModel.kt.
  2. In LoginViewModel.kt, crea una variabile authenticationState basata sull'oggetto FirebaseUserLiveData appena implementato. Creando questa variabile authenticationState, altre classi possono ora verificare se l'utente ha effettuato l'accesso o meno tramite LoginViewModel.

LoginViewModel.kt

val authenticationState = FirebaseUserLiveData().map { user ->
   if (user != null) {
       AuthenticationState.AUTHENTICATED
   } else {
       AuthenticationState.UNAUTHENTICATED
   }
}
  1. Apri MainFragment.kt.
  2. In observeAuthenticationState() di MainFragment.kt puoi utilizzare la variabile authenticationState appena aggiunta in LoginViewModel e modificare l'interfaccia utente di conseguenza. Se è presente un utente che ha eseguito l'accesso, authButton dovrebbe visualizzare Logout.

Fragment.kt principale

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 l'utente ha eseguito l'accesso, puoi anche personalizzare il messaggio di benvenuto utilizzando la funzione getFactWithPersonalization() fornita in MainFragment.

Fragment.kt principale

binding.welcomeText.text = getFactWithPersonalization(factToDisplay)
  1. Infine, se non è presente alcun utente che ha eseguito l'accesso (quando authenticationState è diverso da LoginViewModel.AuthenticationState.AUTHENTICATED), auth_button dovrebbe visualizzare Accesso e avviare la schermata di accesso quando viene fatto clic. Inoltre, il messaggio non deve essere personalizzato.

Fragment.kt principale

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

Dopo aver completato tutti i passaggi, il metodo observeAuthenticationState() finale dovrebbe essere simile al codice riportato di seguito.

Fragment.kt principale

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. Esegui la tua app. L'interfaccia utente dovrebbe aggiornarsi in base al fatto che un utente abbia eseguito o meno l'accesso. Se tutto funziona correttamente e hai effettuato l'accesso, nella schermata Home dovresti vedere il tuo nome, oltre a visualizzare un fatto Android. Anche il pulsante Login (Accedi) dovrebbe essere visualizzato, Logout.

In questa attività implementerai la funzionalità di disconnessione.

L'app consente agli utenti di eseguire l'accesso e dovrebbe fornire loro anche un modo per uscire. Ecco un esempio di come disconnettere un utente con una sola riga di codice:

AuthUI.getInstance().signOut(requireContext())
  1. Apri MainFragment.kt.
  2. Nella observeAuthenticationState() di MainFragment.kt, aggiungi la logica di disconnessione in modo che auth_button funzioni correttamente quando è presente un utente che ha eseguito l'accesso. Il risultato finale del metodo sembra simile al seguente codice.

Fragment.kt principale

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. Esegui l'app.
  2. Tocca il pulsante Esci e verifica che l'utente sia disconnesso; lo stato del pulsante cambierà in Accedi.

La versione finale dell'app completata è disponibile qui https://github.com/googlecodelabs/android-kotlin-login.

In questo codelab, hai imparato:

  • Come aggiungere Firebase al progetto aggiungendo le dipendenze necessarie nel file Gradle e configurando il progetto nella Console Firebase.
  • Come implementare l'accesso alla tua app utilizzando la libreria FirebaseUI e specificando come consentire agli utenti di accedere. Tieni presente che gli account creati dagli utenti nella tua app sono specifici per la tua app e non condivisi con tutte le app che utilizzano Firebase per la funzionalità di accesso.
  • Come controllare lo stato di autenticazione attuale della tua app con LiveData.
  • Come disconnettere gli utenti.

Questo codelab ha trattato le nozioni di base su come supportare l'accesso per un'app Android.

In questo codelab hai consentito agli utenti di registrarsi e accedere con il loro indirizzo email. Tuttavia, con la libreria FirebaseUI puoi anche supportare altri metodi di autenticazione, ad esempio l'accesso con un numero di telefono. Per saperne di più sulle funzionalità della libreria FirebaseUI e su come utilizzare altre funzionalità che offre, consulta le seguenti risorse:

Per ulteriori informazioni sulle best practice per l'accesso, consulta queste altre risorse:

Codelab:

Documentazione per gli sviluppatori Android:

Video:

Per i link ad altri codelab in questo corso, consulta la pagina di destinazione Advanced Android in Kotlin.