Creare un'app per Android con Firebase e Jetpack Compose

1. Introduzione

Ultimo aggiornamento: 16/11/2022

Creare un'app per Android con Firebase e Jetpack Compose

In questo codelab, creerai un'app per Android chiamata Make It So. L'interfaccia utente di questa app è interamente realizzata con Jetpack Compose, il toolkit moderno di Android per la creazione di interfacce utente native. È intuitivo e richiede meno codice rispetto alla scrittura di file .xml e alla loro associazione ad attività, frammenti o visualizzazioni.

Il primo passo per capire quanto bene Firebase e Jetpack Compose funzionano insieme è comprendere l'architettura Android moderna. Una buona architettura rende il sistema facile da comprendere, da sviluppare e da mantenere, poiché chiarisce molto bene come i componenti sono organizzati e comunicano tra loro. Nel mondo Android, l'architettura consigliata è chiamata Modello - Visualizzazione - ViewModel. Modello rappresenta il livello che accede ai dati nell'applicazione. La visualizzazione è il livello dell'interfaccia utente e non deve conoscere nulla della logica di business. Inoltre, il ViewModel è il luogo in cui viene applicata la logica di business, che a volte richiede al ViewModel di chiamare il livello Model.

Ti consigliamo vivamente di leggere questo articolo per capire come Model - View - ViewModel viene applicato a un'app per Android creata con Jetpack Compose, in quanto renderà la base di codice più facile da comprendere e i passaggi successivi più facili da completare.

Cosa creerai

Make It So è una semplice applicazione per elenchi di cose da fare che consente all'utente di aggiungere e modificare attività, aggiungere indicatori, priorità e date di scadenza e contrassegnare le attività come completate. Le immagini seguenti mostrano le due pagine principali di questa applicazione: la pagina di creazione delle attività e la pagina principale con l'elenco delle attività create.

Schermata Aggiungi attività di Fai così Schermata Home di Crealo

Aggiungerai alcune funzionalità mancanti in questa app:

  • Autentica gli utenti con email e password
  • Aggiungere un listener a una raccolta Firestore e fare in modo che l'interfaccia utente reagisca alle modifiche
  • Aggiungere tracce personalizzate per monitorare il rendimento di un codice specifico nell'app
  • Crea un pulsante di attivazione/disattivazione della funzionalità utilizzando Remote Config e utilizza l'implementazione graduale per lanciarla

Cosa imparerai a fare

  • Come utilizzare Firebase Authentication, Performance Monitoring, Remote Config e Cloud Firestore in un'applicazione Android moderna
  • Come adattare le API Firebase a un'architettura MVVM
  • Come riflettere le modifiche apportate con le API Firebase in un'interfaccia utente di Compose

Che cosa ti serve

2. Ottieni l'app di esempio e configura Firebase

Ottieni il codice dell'app di esempio

Clona il repository GitHub dalla riga di comando:

git clone https://github.com/FirebaseExtended/make-it-so-android.git

Creare un progetto Firebase

La prima cosa da fare è accedere alla Console Firebase e creare un progetto Firebase facendo clic sul pulsante "+ Aggiungi progetto", come mostrato di seguito:

Console Firebase

Segui i passaggi sullo schermo per completare la creazione del progetto.

Aggiungi un'app per Android al tuo progetto Firebase

Nel tuo progetto Firebase puoi registrare app diverse: per Android, iOS, web, Flutter e Unity.

Scegli l'opzione Android, come mostrato di seguito:

Panoramica del progetto Firebase

Poi segui questi passaggi:

  1. Inserisci com.example.makeitso come nome del pacchetto e, facoltativamente, un nickname. Per questo codelab, non è necessario aggiungere il certificato di firma di debug.
  2. Fai clic su Avanti per registrare la tua app e accedere al file di configurazione di Firebase.
  3. Fai clic su Scarica google-services.json per scaricare il file di configurazione e salvarlo nella directory make-it-so-android/app.
  4. Fai clic su Avanti. Poiché gli SDK Firebase sono già inclusi nel file build.gradle del progetto di esempio, fai clic su Avanti per passare alla sezione Passaggi successivi.
  5. Fai clic su Continua alla console per completare l'operazione.

Per far funzionare correttamente l'app Make it So, devi eseguire due operazioni nella Console prima di passare al codice: attivare i provider di autenticazione e creare il database Firestore.

Configurare l'autenticazione

Innanzitutto, abilitiamo l'autenticazione in modo che gli utenti possano accedere all'app:

  1. Nel menu Build (Compilazione), seleziona Autenticazione e poi fai clic su Inizia.
  2. Nella scheda Metodo di accesso, seleziona Email/password e attivalo.
  3. Poi, fai clic su Aggiungi nuovo fornitore e seleziona e attiva Anonimo.

Configurare Cloud Firestore

Poi, configura Firestore. Utilizzerai Firestore per archiviare le attività di un utente che ha eseguito l'accesso. Ogni utente avrà il proprio documento all'interno di una raccolta del database.

  1. Nel riquadro a sinistra della console Firebase, espandi Build e seleziona Database Firestore.
  2. Fai clic su Crea database.
  3. Lascia l'ID database impostato su (default).
  4. Seleziona una posizione per il database, poi fai clic su Avanti.
    Per un'app reale, scegli una posizione vicina ai tuoi utenti.
  5. Fai clic su Avvia in modalità di test. Leggi il disclaimer relativo alle regole di sicurezza.
    Nei passaggi successivi di questa sezione, aggiungerai le regole di sicurezza per proteggere i tuoi dati. Non distribuire o esporre pubblicamente un'app senza aggiungere regole di sicurezza per il tuo database.
  6. Fai clic su Crea.

Prenditi un momento per creare regole di sicurezza efficaci nel database Firestore.

  1. Apri la dashboard di Firestore e vai alla scheda Regole.
  2. Aggiorna le regole di sicurezza in questo modo:
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow create: if request.auth != null;
      allow read, update, delete: if request.auth != null && resource.data.userId == request.auth.uid;
    }
  }
}

Queste regole indicano in sostanza che qualsiasi utente che ha eseguito l'accesso all'app può creare un documento per sé all'interno di qualsiasi raccolta. Una volta creato, solo l'utente che ha creato il documento potrà visualizzarlo, aggiornarlo o eliminarlo.

Esegui l'applicazione

Ora puoi eseguire l'applicazione. Apri la cartella make-it-so-android/start in Android Studio ed esegui l'app (puoi farlo utilizzando un emulatore Android o un vero dispositivo Android).

3. Firebase Authentication

Quale funzionalità aggiungerai?

Nell'attuale stato dell'app di esempio Make It So, un utente può iniziare a utilizzare l'app senza dover prima accedere. Per farlo, utilizza l'autenticazione anonima. Tuttavia, gli account anonimi non consentono a un utente di accedere ai propri dati su altri dispositivi o anche in sessioni future. Sebbene l'autenticazione anonima sia utile per un onboarding caldo, devi sempre offrire agli utenti la possibilità di passare a una forma di accesso diversa. Tenendo presente questo, in questo codelab aggiungerai l'autenticazione tramite email e password all'app Make It So.

È ora di programmare.

Non appena l'utente crea un account digitando un indirizzo email e una password, devi chiedere all'API Firebase Authentication una credenziale email, quindi collegare la nuova credenziale all'account anonimo. Apri il file AccountServiceImpl.kt in Android Studio e aggiorna la funzione linkAccount in modo che abbia il seguente aspetto:

model/service/impl/AccountServiceImpl.kt

override suspend fun linkAccount(email: String, password: String) {
    val credential = EmailAuthProvider.getCredential(email, password)
    auth.currentUser!!.linkWithCredential(credential).await()
}

Ora apri SignUpViewModel.kt e chiama la funzione linkAccount del servizio all'interno del blocco launchCatching della funzione onSignUpClick:

screens/sign_up/SignUpViewModel.kt

launchCatching {
    accountService.linkAccount(email, password)
    openAndPopUp(SETTINGS_SCREEN, SIGN_UP_SCREEN)
}

Innanzitutto, tenta di autenticarsi e, se la chiamata va a buon fine, passa alla schermata successiva (SettingsScreen). Quando esegui queste chiamate all'interno di un blocco launchCatching, se si verifica un errore nella prima riga, l'eccezione verrà rilevata e gestita e la seconda riga non verrà raggiunta.

Non appena SettingsScreen viene aperto di nuovo, devi assicurarti che le opzioni Accedi e Crea account non siano più disponibili, perché l'utente è già autenticato. A tale scopo, facciamo in modo che SettingsViewModel ascolti lo stato dell'utente corrente (disponibile in AccountService.kt) per verificare se l'account è anonimo o meno. A questo scopo, aggiorna uiState in SettingsViewModel.kt in modo che sia simile al seguente:

screens/settings/SettingsViewModel.kt

val uiState = accountService.currentUser.map {
    SettingsUiState(it.isAnonymous)
}

L'ultima cosa da fare è aggiornare uiState in SettingsScreen.kt per raccogliere gli stati emessi da SettingsViewModel:

screens/settings/SettingsScreen.kt

val uiState by viewModel.uiState.collectAsState(
    initial = SettingsUiState(false)
)

Ora, ogni volta che l'utente cambia, il SettingsScreen si ricompone per mostrare le opzioni in base al nuovo stato di autenticazione dell'utente.

È ora di fare un test.

Esegui Realizza e vai alle impostazioni facendo clic sull'icona a forma di ingranaggio nell'angolo in alto a destra dello schermo. Da qui, fai clic sull'opzione per creare un account:

Schermata delle impostazioni di Crealo Schermata di registrazione di Make It So

Digita un indirizzo email valido e una password efficace per creare il tuo account. Dovrebbe funzionare e dovresti essere reindirizzato alla pagina delle impostazioni, dove vedrai due nuove opzioni: uscire ed eliminare il tuo account. Puoi controllare il nuovo account creato nella dashboard di autenticazione della console Firebase facendo clic sulla scheda Utenti.

4. Cloud Firestore

Quale funzionalità aggiungerai?

Per Cloud Firestore, aggiungi un ascoltatore alla raccolta Firestore che memorizza i documenti che rappresentano le attività visualizzate in Realizza. Dopo aver aggiunto questo ascoltatore, riceverai tutti gli aggiornamenti apportati a questa raccolta.

È ora di programmare.

Aggiorna il Flow disponibile in StorageServiceImpl.kt in questo modo:

model/service/impl/StorageServiceImpl.kt

override val tasks: Flow<List<Task>>
    get() =
      auth.currentUser.flatMapLatest { user ->
        firestore.collection(TASK_COLLECTION).whereEqualTo(USER_ID_FIELD, user.id).dataObjects()
      }

Questo codice aggiunge un ascoltatore alla raccolta di attività in base a user.id. Ogni attività è rappresentata da un documento in una raccolta denominata tasks e ognuna ha un campo denominato userId. Tieni presente che verrà emesso un nuovo Flow se lo stato del currentUser cambia (ad esempio se esci).

Ora devi fare in modo che Flow in TasksViewModel.kt corrisponda a quello nel servizio:

screens/tasks/TasksViewModel.kt

val tasks = storageService.tasks

Infine, dovrai fare in modo che composable function in TasksScreens.kt, che rappresenta l'interfaccia utente, sia consapevole di questo flusso e lo raccolga come stato. Ogni volta che lo stato cambia, la funzione composable si ricomporrà automaticamente e mostrerà all'utente lo stato più recente. Aggiungi il seguente codice a TasksScreen composable function:

screens/tasks/TasksScreen.kt

val tasks = viewModel
    .tasks
    .collectAsStateWithLifecycle(emptyList())

Una volta che la funzione composable ha accesso a questi stati, puoi aggiornare LazyColumn (la struttura utilizzata per visualizzare un elenco sullo schermo) in questo modo:

screens/tasks/TasksScreen.kt

LazyColumn {
    items(tasks.value, key = { it.id }) { taskItem ->
        TaskItem( [...] )
    }
}

È ora di fare un test.

Per verificare che funzioni, aggiungi una nuova attività utilizzando l'app (facendo clic sul pulsante Aggiungi nell'angolo in basso a destra dello schermo). Al termine della creazione, l'attività dovrebbe essere visualizzata nella raccolta Firestore nella console Firestore. Se accedi a Fai così su altri dispositivi con lo stesso account, potrai modificare le tue attività da svolgere e osservarne l'aggiornamento in tempo reale su tutti i dispositivi.

5. Performance Monitoring

Quale funzionalità aggiungerai?

Le prestazioni sono un aspetto molto importante a cui prestare attenzione, perché gli utenti sono molto propensi ad abbandonare l'utilizzo della tua app se le prestazioni non sono buone e impiegano troppo tempo per completare una semplice attività. Ecco perché a volte è utile raccogliere alcune metriche su un percorso specifico intrapreso da un utente nella tua app. Per aiutarti, Firebase Performance Monitoring offre tracce personalizzate. Segui i passaggi successivi per aggiungere tracce personalizzate e misurare il rendimento in diversi frammenti di codice in Make it So.

È ora di programmare.

Se apri il file Performance.kt, vedrai una funzione in linea chiamata trace. Questa funzione chiama l'API Performance Monitoring per creare una traccia personalizzata, passando il nome della traccia come parametro. L'altro parametro che vedi è il blocco di codice che vuoi monitorare. La metrica predefinita raccolta per ogni traccia è il tempo necessario per l'esecuzione completa:

model/service/Performance.kt

inline fun <T> trace(name: String, block: Trace.() -> T): T = Trace.create(name).trace(block)

Puoi scegliere le parti del codice di cui ritieni importante misurare le prestazioni e aggiungere tracce personalizzate. Ecco un esempio di aggiunta di una traccia personalizzata alla funzione linkAccount che hai visto in precedenza (in AccountServiceImpl.kt) in questo codelab:

model/service/impl/AccountServiceImpl.kt

override suspend fun linkAccount(email: String, password: String): Unit =
  trace(LINK_ACCOUNT_TRACE) {
      val credential = EmailAuthProvider.getCredential(email, password)
      auth.currentUser!!.linkWithCredential(credential).await()
  }

Ora tocca a voi! Aggiungi alcune tracce personalizzate all'app Make it So e vai alla sezione successiva per verificare se funziona come previsto.

È ora di fare un test.

Dopo aver aggiunto le tracce personalizzate, esegui l'app e assicurati di utilizzare le funzionalità che vuoi misurare alcune volte. Poi vai alla Console Firebase e alla dashboard sul rendimento. Nella parte inferiore dello schermo sono presenti tre schede: Richieste di rete, Tracce personalizzate e Rendering dello schermo.

Vai alla scheda Tracce personalizzate e controlla che le tracce aggiunte nella base di codice vengano visualizzate e che tu possa vedere il tempo necessario per l'esecuzione di questi frammenti di codice.

6. Remote Config

Quale funzionalità aggiungerai?

Esistono molti casi d'uso per Remote Config, dalla modifica dell'aspetto dell'app da remoto alla configurazione di comportamenti diversi per segmenti di utenti diversi. In questo codelab utilizzerai Remote Config per creare un pulsante di attivazione/disattivazione della funzionalità che mostrerà o nasconderà la nuova funzionalità di modifica dell'attività nell'app Make it So.

È ora di programmare.

La prima cosa da fare è creare la configurazione nella console Firebase. Per farlo, devi andare alla dashboard di Remote Config e fare clic sul pulsante Aggiungi parametro. Compila i campi come indicato nell'immagine di seguito:

Finestra di dialogo Crea un parametro di Remote Config

Una volta compilati tutti i campi, puoi fare clic sul pulsante Salva e poi su Pubblica. Ora che il parametro è stato creato e reso disponibile per il tuo codice di base, devi aggiungere il codice che recupererà i nuovi valori nella tua app. Apri il file ConfigurationServiceImpl.kt e aggiorna l'implementazione di queste due funzioni:

model/service/impl/ConfigurationServiceImpl.kt

override suspend fun fetchConfiguration(): Boolean {
  return remoteConfig.fetchAndActivate().await()
}

override val isShowTaskEditButtonConfig: Boolean
  get() = remoteConfig[SHOW_TASK_EDIT_BUTTON_KEY].asBoolean()

La prima funzione recupera i valori dal server e viene chiamata non appena l'app viene avviata, in SplashViewModel.kt. È il modo migliore per assicurarti che i valori più aggiornati siano disponibili in tutte le schermate fin dall'inizio. Non è un'esperienza utente positiva se modifichi l'interfaccia utente o il comportamento dell'app in un secondo momento, quando l'utente sta facendo qualcosa.

La seconda funzione restituisce il valore booleano pubblicato per il parametro che hai appena creato nella console. Inoltre, dovrai recuperare queste informazioni in TasksViewModel.kt aggiungendo quanto segue alla funzione loadTaskOptions:

screens/tasks/TasksViewModel.kt

fun loadTaskOptions() {
  val hasEditOption = configurationService.isShowTaskEditButtonConfig
  options.value = TaskActionOption.getOptions(hasEditOption)
}

Recuperi il valore nella prima riga e lo utilizzi per caricare le opzioni di menu per gli elementi della task nella seconda riga. Se il valore è false, significa che il menu non conterrà l'opzione di modifica. Ora che hai l'elenco di opzioni, devi fare in modo che l'interfaccia utente lo mostri correttamente. Quando crei un'app con Jetpack Compose, devi cercare il composable function che dichiara l'aspetto dell'interfaccia utente del TasksScreen. Apri quindi il file TasksScreen.kt e aggiorna LazyColum in modo che indichi le opzioni disponibili in TasksViewModel.kt:

screens/tasks/TasksScreen.kt

val options by viewModel.options

LazyColumn {
  items(tasks.value, key = { it.id }) { taskItem ->
    TaskItem(
      options = options,
      [...]
    )
  }
}

TaskItem è un altro composable function che dichiara l'aspetto dell'interfaccia utente di una singola attività. Ogni attività ha un menu con opzioni che viene visualizzato quando l'utente fa clic sull'icona con tre puntini alla fine.

È ora di fare un test.

Ora puoi eseguire l'app. Verifica che il valore pubblicato utilizzando la Console Firebase corrisponda al comportamento dell'app:

  • Se è false, dovresti vedere solo due opzioni quando fai clic sull'icona con i tre puntini.
  • Se è true, dovresti vedere tre opzioni quando fai clic sull'icona con i tre puntini.

Prova a modificare il valore un paio di volte nella console e a riavviare l'app. È così facile lanciare nuove funzionalità nella tua app utilizzando Remote Config.

7. Complimenti

Complimenti, hai creato un'app per Android con Firebase e Jetpack Compose.

Hai aggiunto Firebase Authentication, Performance Monitoring, Remote Config e Cloud Firestore a un'app per Android interamente creata con Jetpack Compose per l'interfaccia utente e l'hai adattata all'architettura MVVM consigliata.

Letture aggiuntive

Documentazione di riferimento