Codelab per Android su Cloud Firestore

Codelab per Android su Cloud Firestore

Informazioni su questo codelab

subjectUltimo aggiornamento: set 15, 2025
account_circleScritto da un Googler

1. Panoramica

Obiettivi

In questo codelab creerai un'app di consigli di ristoranti su Android supportata da Cloud Firestore. Imparerai come:

  • Leggere e scrivere dati in Firestore da un'app per Android
  • Ascolta le modifiche ai dati di Firestore in tempo reale
  • Utilizzare Firebase Authentication e le regole di sicurezza per proteggere i dati di Firestore
  • Scrivere query Firestore complesse

Prerequisiti

Prima di iniziare questo codelab, assicurati di avere:

  • Android Studio Flamingo o versioni successive
  • Un emulatore Android con API 19 o versioni successive
  • Node.js versione 16 o successive
  • Versione di Java 17 o successive

2. Crea un progetto Firebase

  1. Accedi alla console Firebase utilizzando il tuo Account Google.
  2. Fai clic sul pulsante per creare un nuovo progetto, quindi inserisci un nome per il progetto (ad esempio FriendlyEats).
  3. Fai clic su Continua.
  4. Se richiesto, leggi e accetta i termini di Firebase, quindi fai clic su Continua.
  5. (Facoltativo) Attiva l'assistenza AI nella console Firebase (denominata "Gemini in Firebase").
  6. Per questo codelab non hai bisogno di Google Analytics, quindi disattiva l'opzione Google Analytics.
  7. Fai clic su Crea progetto, attendi il provisioning del progetto, poi fai clic su Continua.

3. Configurare il progetto di esempio

Scarica il codice

Esegui questo comando per clonare il codice di esempio per questo codelab. Verrà creata una cartella denominata friendlyeats-android sul tuo computer:

$ git clone https://github.com/firebase/friendlyeats-android

Se non hai git sul tuo computer, puoi anche scaricare il codice direttamente da GitHub.

Aggiungi la configurazione di Firebase

  1. Nella console Firebase, seleziona Panoramica del progetto nel menu di navigazione a sinistra. Fai clic sul pulsante Android per selezionare la piattaforma. Quando ti viene chiesto un nome del pacchetto, utilizza com.google.firebase.example.fireeats

73d151ed16016421.png

  1. Fai clic su Registra app e segui le istruzioni per scaricare il file google-services.json e spostarlo nella cartella app/ del codice che hai appena scaricato. Quindi, fai clic su Avanti.

Importare il progetto

Apri Android Studio. Fai clic su File > Nuovo > Importa progetto e seleziona la cartella friendlyeats-android.

4. Configura gli emulatori Firebase

In questo codelab utilizzerai Firebase Emulator Suite per emulare localmente Cloud Firestore e altri servizi Firebase. In questo modo, avrai a disposizione un ambiente di sviluppo locale sicuro, rapido e senza costi per creare la tua app.

Installa l'interfaccia a riga di comando di Firebase

Innanzitutto, devi installare l'interfaccia a riga di comando di Firebase. Se utilizzi macOS o Linux, puoi eseguire il seguente comando cURL:

curl -sL https://firebase.tools | bash

Se utilizzi Windows, leggi le istruzioni di installazione per ottenere un binario autonomo o per eseguire l'installazione tramite npm.

Dopo aver installato la CLI, l'esecuzione di firebase --version dovrebbe restituire una versione di 9.0.0 o successive:

$ firebase --version
9.0.0

Accedi

Esegui firebase login per collegare la CLI al tuo Account Google. Si aprirà una nuova finestra del browser per completare la procedura di accesso. Assicurati di scegliere lo stesso account che hai utilizzato in precedenza per creare il progetto Firebase.

Dalla cartella friendlyeats-android esegui firebase use --add per connettere il progetto locale al progetto Firebase. Segui le istruzioni per selezionare il progetto che hai creato in precedenza e, se ti viene chiesto di scegliere un alias, inserisci default.

5. Esegui l'app

Ora è il momento di eseguire Firebase Emulator Suite e l'app per Android FriendlyEats per la prima volta.

Esegui gli emulatori

Nel terminale, dalla directory friendlyeats-android, esegui firebase emulators:start per avviare gli emulatori Firebase. Dovresti visualizzare log simili a questi:

$ firebase emulators:start
i  emulators: Starting emulators: auth, firestore
i  firestore: Firestore Emulator logging to firestore-debug.log
i  ui: Emulator UI logging to ui-debug.log

┌─────────────────────────────────────────────────────────────┐
│ ✔  All emulators ready! It is now safe to connect your app. │
│ i  View Emulator UI at http://localhost:4000                │
└─────────────────────────────────────────────────────────────┘

┌────────────────┬────────────────┬─────────────────────────────────┐
│ Emulator       │ Host:Port      │ View in Emulator UI             │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Authentication │ localhost:9099 │ http://localhost:4000/auth      │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Firestore      │ localhost:8080 │ http://localhost:4000/firestore │
└────────────────┴────────────────┴─────────────────────────────────┘
  Emulator Hub running at localhost:4400
  Other reserved ports: 4500

Issues? Report them at https://github.com/firebase/firebase-tools/issues and attach the *-debug.log files.

Ora hai un ambiente di sviluppo locale completo in esecuzione sulla tua macchina. Assicurati di lasciare in esecuzione questo comando per il resto del codelab, la tua app per Android dovrà connettersi agli emulatori.

Connettere l'app agli emulatori

Apri i file util/FirestoreInitializer.kt e util/AuthInitializer.kt in Android Studio. Questi file contengono la logica per connettere gli SDK Firebase agli emulatori locali in esecuzione sul tuo computer all'avvio dell'applicazione.

Nel metodo create() della classe FirestoreInitializer, esamina questo codice:

    // Use emulators only in debug builds
    if (BuildConfig.DEBUG) {
        firestore.useEmulator(FIRESTORE_EMULATOR_HOST, FIRESTORE_EMULATOR_PORT)
    }

Utilizziamo BuildConfig per assicurarci di connetterci agli emulatori solo quando la nostra app è in esecuzione in modalità debug. Quando compiliamo l'app in modalità release, questa condizione sarà false.

Possiamo vedere che utilizza il metodo useEmulator(host, port) per connettere l'SDK Firebase all'emulatore Firestore locale. In tutta l'app utilizzeremo FirebaseUtil.getFirestore() per accedere a questa istanza di FirebaseFirestore, in modo da assicurarci di connetterci sempre all'emulatore Firestore quando viene eseguito in modalità debug.

Esegui l'app

Se hai aggiunto correttamente il file google-services.json, ora il progetto dovrebbe essere compilato. In Android Studio fai clic su Build (Compila) > Rebuild Project (Ricompila progetto) e assicurati che non siano rimasti errori.

In Android Studio, esegui l'app sull'emulatore Android. All'inizio vedrai una schermata di "Accesso". Puoi utilizzare qualsiasi email e password per accedere all'app. Questo processo di accesso si connette all'emulatore Firebase Authentication, quindi non vengono trasmesse credenziali reali.

Ora apri la UI degli emulatori andando all'indirizzo http://localhost:4000 nel browser web. Quindi fai clic sulla scheda Autenticazione e dovresti visualizzare l'account appena creato:

Emulatore Firebase Auth

Una volta completato il processo di accesso, dovresti visualizzare la schermata iniziale dell'app:

de06424023ffb4b9.png

A breve aggiungeremo alcuni dati per compilare la schermata Home.

6. Scrivi dati in Firestore

In questa sezione scriveremo alcuni dati in Firestore in modo da poter popolare la schermata Home attualmente vuota.

L'oggetto modello principale nella nostra app è un ristorante (vedi model/Restaurant.kt). I dati di Firestore sono suddivisi in documenti, raccolte e sottoraccolte. Memorizzeremo ogni ristorante come documento in una raccolta di primo livello chiamata "restaurants". Per scoprire di più sul modello di dati di Firestore, leggi la documentazione relativa a documenti e raccolte.

A scopo dimostrativo, aggiungeremo una funzionalità nell'app per creare dieci ristoranti casuali quando facciamo clic sul pulsante "Aggiungi elementi casuali" nel menu overflow. Apri il file MainFragment.kt e sostituisci i contenuti nel metodo onAddItemsClicked() con:

    private fun onAddItemsClicked() {
        val restaurantsRef
= firestore.collection("restaurants")
       
for (i in 0..9) {
           
// Create random restaurant / ratings
            val randomRestaurant
= RestaurantUtil.getRandom(requireContext())

           
// Add restaurant
            restaurantsRef
.add(randomRestaurant)
       
}
   
}

Ecco alcuni aspetti importanti da notare sul codice riportato sopra:

  • Abbiamo iniziato ottenendo un riferimento alla raccolta "restaurants". Le raccolte vengono create implicitamente quando vengono aggiunti documenti, quindi non era necessario creare la raccolta prima di scrivere i dati.
  • I documenti possono essere creati utilizzando le classi di dati Kotlin, che utilizziamo per creare ogni documento del ristorante.
  • Il metodo add() aggiunge un documento a una raccolta con un ID generato automaticamente, quindi non è necessario specificare un ID univoco per ogni ristorante.

Ora esegui di nuovo l'app e fai clic sul pulsante "Aggiungi elementi casuali" nel menu extra (nell'angolo in alto a destra) per richiamare il codice che hai appena scritto:

95691e9b71ba55e3.png

Ora apri la UI degli emulatori andando all'indirizzo http://localhost:4000 nel browser web. Quindi, fai clic sulla scheda Firestore e dovresti vedere i dati appena aggiunti:

Emulatore Firebase Auth

Questi dati sono locali al 100% sulla tua macchina. Infatti, il tuo progetto reale non contiene ancora un database Firestore. Ciò significa che puoi modificare ed eliminare questi dati senza conseguenze.

Congratulazioni, hai appena scritto dati in Firestore. Nel passaggio successivo impareremo a visualizzare questi dati nell'app.

7. Visualizzare i dati di Firestore

In questo passaggio impareremo a recuperare i dati da Firestore e a visualizzarli nella nostra app. Il primo passaggio per leggere i dati da Firestore è creare un Query. Apri il file MainFragment.kt e aggiungi il seguente codice all'inizio del metodo onViewCreated():

        // Firestore
        firestore = Firebase.firestore

        // Get the 50 highest rated restaurants
        query = firestore.collection("restaurants")
            .orderBy("avgRating", Query.Direction.DESCENDING)
            .limit(LIMIT.toLong())

Ora vogliamo ascoltare la query, in modo da ricevere tutti i documenti corrispondenti e ricevere notifiche sugli aggiornamenti futuri in tempo reale. Poiché il nostro obiettivo finale è associare questi dati a un RecyclerView, dobbiamo creare una classe RecyclerView.Adapter per ascoltare i dati.

Apri la classe FirestoreAdapter, che è già stata implementata parzialmente. Innanzitutto, facciamo in modo che l'adattatore implementi EventListener e definiamo la funzione onEvent in modo che possa ricevere aggiornamenti a una query Firestore:

abstract class FirestoreAdapter<VH : RecyclerView.ViewHolder>(private var query: Query?) :
        RecyclerView.Adapter<VH>(),
        EventListener<QuerySnapshot> { // Add this implements
   
    // ...

    // Add this method
    override fun onEvent(documentSnapshots: QuerySnapshot?, e: FirebaseFirestoreException?) {
       
        // Handle errors
        if (e != null) {
            Log.w(TAG, "onEvent:error", e)
            return
        }

        // Dispatch the event
        if (documentSnapshots != null) {
            for (change in documentSnapshots.documentChanges) {
                // snapshot of the changed document
                when (change.type) {
                    DocumentChange.Type.ADDED -> {
                        // TODO: handle document added
                    }
                    DocumentChange.Type.MODIFIED -> {
                        // TODO: handle document changed
                    }
                    DocumentChange.Type.REMOVED -> {
                        // TODO: handle document removed
                    }
                }
            }
        }

        onDataChanged()
    }
   
    // ...
}

Al caricamento iniziale, il listener riceverà un evento ADDED per ogni nuovo documento. Man mano che il set di risultati della query cambia nel tempo, il listener riceverà più eventi contenenti le modifiche. Ora completiamo l'implementazione del listener. Innanzitutto, aggiungi tre nuovi metodi: onDocumentAdded, onDocumentModified e onDocumentRemoved:

    private fun onDocumentAdded(change: DocumentChange) {
        snapshots
.add(change.newIndex, change.document)
        notifyItemInserted
(change.newIndex)
   
}

   
private fun onDocumentModified(change: DocumentChange) {
       
if (change.oldIndex == change.newIndex) {
           
// Item changed but remained in same position
            snapshots
[change.oldIndex] = change.document
            notifyItemChanged
(change.oldIndex)
       
} else {
           
// Item changed and changed position
            snapshots
.removeAt(change.oldIndex)
            snapshots
.add(change.newIndex, change.document)
            notifyItemMoved
(change.oldIndex, change.newIndex)
       
}
   
}

   
private fun onDocumentRemoved(change: DocumentChange) {
        snapshots
.removeAt(change.oldIndex)
        notifyItemRemoved
(change.oldIndex)
   
}

Quindi chiama questi nuovi metodi da onEvent:

    override fun onEvent(documentSnapshots: QuerySnapshot?, e: FirebaseFirestoreException?) {

        // Handle errors
        if (e != null) {
            Log.w(TAG, "onEvent:error", e)
            return
        }

        // Dispatch the event
        if (documentSnapshots != null) {
            for (change in documentSnapshots.documentChanges) {
                // snapshot of the changed document
                when (change.type) {
                    DocumentChange.Type.ADDED -> {
                        onDocumentAdded(change) // Add this line
                    }
                    DocumentChange.Type.MODIFIED -> {
                        onDocumentModified(change) // Add this line
                    }
                    DocumentChange.Type.REMOVED -> {
                        onDocumentRemoved(change) // Add this line
                    }
                }
            }
        }

        onDataChanged()
    }

Infine, implementa il metodo startListening() per collegare il listener:

    fun startListening() {
        if (registration == null) {
            registration = query.addSnapshotListener(this)
        }
    }

Ora l'app è completamente configurata per leggere i dati da Firestore. Esegui di nuovo l'app e dovresti vedere i ristoranti che hai aggiunto nel passaggio precedente:

9e45f40faefce5d0.png

Ora torna all'interfaccia utente dell'emulatore nel browser e modifica uno dei nomi dei ristoranti. Dovresti vederla cambiare quasi immediatamente nell'app.

8. Ordinare e filtrare i dati

Attualmente l'app mostra i ristoranti con le valutazioni più alte dell'intera raccolta, ma in un'app di ristoranti reale l'utente vorrebbe ordinare e filtrare i dati. Ad esempio, l'app dovrebbe essere in grado di mostrare "I migliori ristoranti di pesce a Filadelfia" o "La pizza meno costosa".

Se fai clic sulla barra bianca nella parte superiore dell'app, viene visualizzata una finestra di dialogo dei filtri. In questa sezione utilizzeremo le query Firestore per far funzionare questa finestra di dialogo:

67898572a35672a5.png

Modifichiamo il metodo onFilter() di MainFragment.kt. Questo metodo accetta un oggetto Filters, che è un oggetto helper creato per acquisire l'output della finestra di dialogo dei filtri. Modificheremo questo metodo per creare una query dai filtri:

    override fun onFilter(filters: Filters) {
        // Construct query basic query
        var query: Query = firestore.collection("restaurants")

        // Category (equality filter)
        if (filters.hasCategory()) {
            query = query.whereEqualTo(Restaurant.FIELD_CATEGORY, filters.category)
        }

        // City (equality filter)
        if (filters.hasCity()) {
            query = query.whereEqualTo(Restaurant.FIELD_CITY, filters.city)
        }

        // Price (equality filter)
        if (filters.hasPrice()) {
            query = query.whereEqualTo(Restaurant.FIELD_PRICE, filters.price)
        }

        // Sort by (orderBy with direction)
        if (filters.hasSortBy()) {
            query = query.orderBy(filters.sortBy.toString(), filters.sortDirection)
        }

        // Limit items
        query = query.limit(LIMIT.toLong())

        // Update the query
        adapter.setQuery(query)

        // Set header
        binding.textCurrentSearch.text = HtmlCompat.fromHtml(
            filters.getSearchDescription(requireContext()),
            HtmlCompat.FROM_HTML_MODE_LEGACY
        )
        binding.textCurrentSortBy.text = filters.getOrderDescription(requireContext())

        // Save filters
        viewModel.filters = filters
    }

Nello snippet precedente creiamo un oggetto Query collegando le clausole where e orderBy in modo che corrispondano ai filtri specificati.

Esegui di nuovo l'app e seleziona il seguente filtro per visualizzare i ristoranti economici più popolari:

7a67a8a400c80c50.png

Ora dovresti visualizzare un elenco filtrato di ristoranti contenente solo opzioni a basso prezzo:

a670188398c3c59.png

Se sei arrivato fin qui, hai creato un'app di visualizzazione di consigli sui ristoranti completamente funzionante su Firestore. Ora puoi ordinare e filtrare i ristoranti in tempo reale. Nelle prossime sezioni aggiungeremo recensioni ai ristoranti e regole di sicurezza all'app.

9. Organizzare i dati in subcollezioni

In questa sezione aggiungeremo le valutazioni all'app in modo che gli utenti possano recensire i loro ristoranti preferiti (o meno).

Raccolte e raccolte secondarie

Finora abbiamo archiviato tutti i dati dei ristoranti in una raccolta di primo livello denominata "restaurants". Quando un utente valuta un ristorante, vogliamo aggiungere un nuovo oggetto Rating ai ristoranti. Per questa attività utilizzeremo una raccolta secondaria. Puoi pensare a una raccolta secondaria come a una raccolta collegata a un documento. Pertanto, ogni documento del ristorante avrà una sottoraccolta di valutazioni piena di documenti di valutazione. Le raccolte secondarie aiutano a organizzare i dati senza appesantire i documenti o richiedere query complesse.

Per accedere a una raccolta secondaria, chiama .collection() nel documento principale:

val subRef = firestore.collection("restaurants")
       
.document("abc123")
       
.collection("ratings")

Puoi accedere a una raccolta secondaria ed eseguire query su di essa proprio come faresti con una raccolta di primo livello. Non ci sono limiti di dimensioni o modifiche alle prestazioni. Puoi scoprire di più sul modello di dati di Firestore qui.

Scrittura dei dati in una transazione

L'aggiunta di un Rating alla sottoraccolta corretta richiede solo la chiamata di .add(), ma dobbiamo anche aggiornare la valutazione media e il numero di valutazioni dell'oggetto Restaurant per riflettere i nuovi dati. Se utilizziamo operazioni separate per apportare queste due modifiche, si verificano una serie di condizioni di competizione che potrebbero comportare dati obsoleti o errati.

Per assicurarci che le valutazioni vengano aggiunte correttamente, utilizzeremo una transazione per aggiungere le valutazioni a un ristorante. Questa transazione eseguirà alcune azioni:

  • Leggi la valutazione attuale del ristorante e calcola la nuova
  • Aggiungi la valutazione alla sottoraccolta
  • Aggiornare la valutazione media e il numero di valutazioni del ristorante

Apri RestaurantDetailFragment.kt e implementa la funzione addRating:

    private fun addRating(restaurantRef: DocumentReference, rating: Rating): Task<Void> {
        // Create reference for new rating, for use inside the transaction
        val ratingRef = restaurantRef.collection("ratings").document()

        // In a transaction, add the new rating and update the aggregate totals
        return firestore.runTransaction { transaction ->
            val restaurant = transaction.get(restaurantRef).toObject<Restaurant>()
                ?: throw Exception("Restaurant not found at ${restaurantRef.path}")

            // Compute new number of ratings
            val newNumRatings = restaurant.numRatings + 1

            // Compute new average rating
            val oldRatingTotal = restaurant.avgRating * restaurant.numRatings
            val newAvgRating = (oldRatingTotal + rating.rating) / newNumRatings

            // Set new restaurant info
            restaurant.numRatings = newNumRatings
            restaurant.avgRating = newAvgRating

            // Commit to Firestore
            transaction.set(restaurantRef, restaurant)
            transaction.set(ratingRef, rating)

            null
        }
    }

La funzione addRating() restituisce un Task che rappresenta l'intera transazione. Nella funzione onRating() vengono aggiunti listener all'attività per rispondere al risultato della transazione.

Ora esegui di nuovo l'app e fai clic su uno dei ristoranti, che dovrebbe visualizzare la schermata dei dettagli del ristorante. Fai clic sul pulsante + per iniziare ad aggiungere una recensione. Aggiungi una recensione scegliendo un numero di stelle e inserendo del testo.

78fa16cdf8ef435a.png

Se fai clic su Invia, la transazione verrà avviata. Al termine della transazione, vedrai la tua recensione visualizzata di seguito e un aggiornamento del conteggio delle recensioni del ristorante:

f9e670f40bd615b0.png

Congratulazioni! Ora hai un'app mobile per le recensioni di ristoranti social e locali basata su Cloud Firestore. Ho sentito dire che sono molto popolari al giorno d'oggi.

10. Proteggi i tuoi dati

Finora non abbiamo preso in considerazione la sicurezza di questa applicazione. Come facciamo a sapere che gli utenti possono leggere e scrivere solo i propri dati corretti? I database Firestore sono protetti da un file di configurazione chiamato Regole di sicurezza.

Apri il file firestore.rules e sostituisci i contenuti con i seguenti:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Determine if the value of the field "key" is the same
    // before and after the request.
    function isUnchanged(key) {
      return (key in resource.data)
        && (key in request.resource.data)
        && (resource.data[key] == request.resource.data[key]);
    }

    // Restaurants
    match /restaurants/{restaurantId} {
      // Any signed-in user can read
      allow read: if request.auth != null;

      // Any signed-in user can create
      // WARNING: this rule is for demo purposes only!
      allow create: if request.auth != null;

      // Updates are allowed if no fields are added and name is unchanged
      allow update: if request.auth != null
                    && (request.resource.data.keys() == resource.data.keys())
                    && isUnchanged("name");

      // Deletes are not allowed.
      // Note: this is the default, there is no need to explicitly state this.
      allow delete: if false;

      // Ratings
      match /ratings/{ratingId} {
        // Any signed-in user can read
        allow read: if request.auth != null;

        // Any signed-in user can create if their uid matches the document
        allow create: if request.auth != null
                      && request.resource.data.userId == request.auth.uid;

        // Deletes and updates are not allowed (default)
        allow update, delete: if false;
      }
    }
  }
}

Queste regole limitano l'accesso per garantire che i client apportino solo modifiche sicure. Ad esempio, gli aggiornamenti a un documento di un ristorante possono modificare solo le valutazioni, non il nome o altri dati immutabili. Le valutazioni possono essere create solo se l'ID utente corrisponde all'utente che ha eseguito l'accesso, il che impedisce lo spoofing.

Per saperne di più sulle regole di sicurezza, consulta la documentazione.

11. Conclusione

Ora hai creato un'app completa basata su Firestore. Hai scoperto le funzionalità più importanti di Firestore, tra cui:

  • Documenti e raccolte
  • Lettura e scrittura dei dati
  • Ordinamento e filtro con le query
  • Sottoraccolte
  • Transazioni

Scopri di più

Per continuare a scoprire Firestore, ecco alcune risorse utili per iniziare:

L'app del ristorante in questo codelab è basata sull'applicazione di esempio "Friendly Eats". Puoi sfogliare il codice sorgente di questa app qui.

(Facoltativo) Esegui il deployment in produzione

Finora questa app ha utilizzato solo Firebase Emulator Suite. Se vuoi scoprire come eseguire il deployment di questa app in un progetto Firebase reale, vai al passaggio successivo.

12. (Facoltativo) Esegui il deployment dell&#39;app

Finora questa app è stata completamente locale e tutti i dati sono contenuti in Firebase Emulator Suite. In questa sezione imparerai a configurare il progetto Firebase in modo che questa app funzioni in produzione.

Firebase Authentication

Nella console Firebase, vai alla sezione Autenticazione e fai clic su Inizia. Vai alla scheda Metodo di accesso e seleziona l'opzione Email/Password da Provider nativi.

Attiva il metodo di accesso Email/password e fai clic su Salva.

sign-in-providers.png

Firestore

Crea database

Vai alla sezione Database Firestore della console e fai clic su Crea database:

  1. Quando ti viene chiesto di scegliere la modalità di avvio delle regole di sicurezza, seleziona Modalità di produzione. Aggiorneremo queste regole a breve.
  2. Scegli la posizione del database che vuoi utilizzare per la tua app. Tieni presente che la selezione di una posizione del database è una decisione permanente e per modificarla dovrai creare un nuovo progetto. Per saperne di più sulla scelta di una località per il progetto, consulta la documentazione.

Regole di deployment

Per eseguire il deployment delle regole di sicurezza che hai scritto in precedenza, esegui questo comando nella directory del codelab:

$ firebase deploy --only firestore:rules

In questo modo, i contenuti di firestore.rules verranno implementati nel tuo progetto, come puoi verificare accedendo alla scheda Regole nella console.

Esegui il deployment degli indici

L'app FriendlyEats ha un ordinamento e un filtro complessi che richiedono una serie di indici composti personalizzati. Questi possono essere creati manualmente nella console Firebase, ma è più semplice scrivere le loro definizioni nel file firestore.indexes.json e implementarle utilizzando la CLI Firebase.

Se apri il file firestore.indexes.json, vedrai che gli indici richiesti sono già stati forniti:

{
 
"indexes": [
   
{
     
"collectionId": "restaurants",
     
"queryScope": "COLLECTION",
     
"fields": [
       
{ "fieldPath": "city", "mode": "ASCENDING" },
       
{ "fieldPath": "avgRating", "mode": "DESCENDING" }
     
]
   
},
   
{
     
"collectionId": "restaurants",
     
"queryScope": "COLLECTION",
     
"fields": [
       
{ "fieldPath": "category", "mode": "ASCENDING" },
       
{ "fieldPath": "avgRating", "mode": "DESCENDING" }
     
]
   
},
   
{
     
"collectionId": "restaurants",
     
"queryScope": "COLLECTION",
     
"fields": [
       
{ "fieldPath": "price", "mode": "ASCENDING" },
       
{ "fieldPath": "avgRating", "mode": "DESCENDING" }
     
]
   
},
   
{
     
"collectionId": "restaurants",
     
"queryScope": "COLLECTION",
     
"fields": [
       
{ "fieldPath": "city", "mode": "ASCENDING" },
       
{ "fieldPath": "numRatings", "mode": "DESCENDING" }
     
]
   
},
   
{
     
"collectionId": "restaurants",
     
"queryScope": "COLLECTION",
     
"fields": [
       
{ "fieldPath": "category", "mode": "ASCENDING" },
       
{ "fieldPath": "numRatings", "mode": "DESCENDING" }
     
]
   
},
   
{
     
"collectionId": "restaurants",
     
"queryScope": "COLLECTION",
     
"fields": [
       
{ "fieldPath": "price", "mode": "ASCENDING" },
       
{ "fieldPath": "numRatings", "mode": "DESCENDING" }
     
]
   
},
   
{
     
"collectionId": "restaurants",
     
"queryScope": "COLLECTION",
     
"fields": [
       
{ "fieldPath": "city", "mode": "ASCENDING" },
       
{ "fieldPath": "price", "mode": "ASCENDING" }
     
]
   
},
   
{
     
"collectionId": "restaurants",
     
"fields": [
       
{ "fieldPath": "category", "mode": "ASCENDING" },
       
{ "fieldPath": "price", "mode": "ASCENDING" }
     
]
   
}
 
],
 
"fieldOverrides": []
}

Per eseguire il deployment di questi indici, esegui questo comando:

$ firebase deploy --only firestore:indexes

Tieni presente che la creazione dell'indice non è istantanea. Puoi monitorare l'avanzamento nella console Firebase.

Configurare l'app

Nei file util/FirestoreInitializer.kt e util/AuthInitializer.kt abbiamo configurato l'SDK Firebase per la connessione agli emulatori in modalità di debug:

    override fun create(context: Context): FirebaseFirestore {
        val firestore
= Firebase.firestore
       
// Use emulators only in debug builds
       
if (BuildConfig.DEBUG) {
            firestore
.useEmulator(FIRESTORE_EMULATOR_HOST, FIRESTORE_EMULATOR_PORT)
       
}
       
return firestore
   
}

Se vuoi testare la tua app con il tuo progetto Firebase reale, puoi:

  1. Crea l'app in modalità di rilascio ed eseguila su un dispositivo.
  2. Sostituisci temporaneamente BuildConfig.DEBUG con false ed esegui di nuovo l'app.

Tieni presente che potresti dover uscire dall'app e accedere di nuovo per connetterti correttamente alla produzione.