Google is committed to advancing racial equity for Black communities. See how.
Diese Seite wurde von der Cloud Translation API übersetzt.
Switch to English

Cloud Firestore Android Codelab

Tore

In diesem Codelab erstellen Sie eine Restaurantempfehlungs-App für Android, die von Cloud Firestore unterstützt wird. Du wirst lernen wie:

  • Lesen und schreiben Sie Daten von einer Android-App in den Firestore
  • Hören Sie Änderungen in Firestore-Daten in Echtzeit ab
  • Verwenden Sie Firebase-Authentifizierungs- und Sicherheitsregeln, um Firestore-Daten zu sichern
  • Schreiben Sie komplexe Firestore-Abfragen

Voraussetzungen

Bevor Sie mit diesem Codelab beginnen, stellen Sie sicher, dass Sie Folgendes haben:

  • Android Studio 4.0 oder höher
  • Ein Android-Emulator
  • Node.js Version 10 oder höher
  • Java Version 8 oder höher
  1. Melden Sie sich mit Ihrem Google-Konto bei der Firebase-Konsole an.
  2. Klicken Sie in der Firebase-Konsole auf Projekt hinzufügen .
  3. Geben Sie, wie in der Abbildung unten gezeigt, einen Namen für Ihr Firebase-Projekt ein (z. B. "Friendly Eats") und klicken Sie auf " Weiter" .

9d2f625aebcab6af.png

  1. Möglicherweise werden Sie aufgefordert, Google Analytics zu aktivieren. Für die Zwecke dieses Codelabs spielt Ihre Auswahl keine Rolle.
  2. Nach ungefähr einer Minute ist Ihr Firebase-Projekt fertig. Klicken Sie auf Weiter .

Laden Sie den Code herunter

Führen Sie den folgenden Befehl aus, um den Beispielcode für dieses Codelab zu klonen. Dadurch wird auf Ihrem Computer ein Ordner mit dem Namen " friendlyeats-android :

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

Wenn Sie kein Git auf Ihrem Computer haben, können Sie den Code auch direkt von GitHub herunterladen.

Importieren Sie das Projekt in Android Studio. Sie werden wahrscheinlich einige Kompilierungsfehler oder eine Warnung vor einer fehlenden Datei google-services.json . Wir werden dies im nächsten Abschnitt korrigieren.

Fügen Sie die Firebase-Konfiguration hinzu

  1. In der Firebase - Konsole , wählen Sie Projektübersicht im linken Navigationsbereich . Klicken Sie auf die Android- Schaltfläche, um die Plattform auszuwählen. Wenn Sie zur com.google.firebase.example.fireeats eines Paketnamens aufgefordert werden, verwenden Sie com.google.firebase.example.fireeats

73d151ed16016421.png

  1. Klicken Sie auf App registrieren und befolgen Sie die Anweisungen, um die Datei google-services.json herunterzuladen und in die app/ Ordner des Beispielcodes zu verschieben. Klicken Sie dann auf Weiter .

In diesem Codelab verwenden Sie die Firebase Emulator Suite , um Cloud Firestore und andere Firebase-Dienste lokal zu emulieren. Dies bietet eine sichere, schnelle und kostenlose lokale Entwicklungsumgebung zum Erstellen Ihrer App.

Installieren Sie die Firebase-CLI

Zuerst müssen Sie die Firebase-CLI installieren. Der einfachste Weg, dies zu tun, ist die Verwendung von npm :

npm install -g firebase-tools

Wenn Sie kein npm oder ein Fehler auftritt, lesen Sie die Installationsanweisungen , um eine eigenständige Binärdatei für Ihre Plattform zu erhalten.

Sobald Sie die CLI installiert haben, sollte beim Ausführen von firebase --version eine Version von 9.0.0 oder höher gemeldet werden:

$ firebase --version
9.0.0

Einloggen

Führen Sie die firebase login , um die CLI mit Ihrem Google-Konto zu verbinden. Dies öffnet ein neues Browserfenster, um den Anmeldevorgang abzuschließen. Stellen Sie sicher, dass Sie dasselbe Konto auswählen, das Sie beim Erstellen Ihres Firebase-Projekts verwendet haben.

Führen Sie im Ordner firebase use --add friendlyeats-android firebase use --add mit firebase use --add , um Ihr lokales Projekt mit Ihrem Firebase-Projekt zu verbinden. Befolgen Sie die Anweisungen, um das zuvor erstellte Projekt auszuwählen, und geben Sie die default ein, wenn Sie aufgefordert werden, einen Alias ​​auszuwählen.

Jetzt ist es Zeit, die Firebase Emulator Suite und die FriendlyEats Android App zum ersten Mal auszuführen.

Führen Sie die Emulatoren aus

Führen Sie in Ihrem Terminal im Verzeichnis friendlyeats-android firebase emulators:start die Firebase-Emulatoren. Sie sollten folgende Protokolle sehen:

$ 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.

Sie haben jetzt eine vollständige lokale Entwicklungsumgebung auf Ihrem Computer! Stellen Sie sicher, dass dieser Befehl für den Rest des Codelabs ausgeführt wird. Ihre Android-App muss eine Verbindung zu den Emulatoren herstellen.

Verbinden Sie die App mit den Emulatoren

Öffnen Sie die Datei FirebaseUtil.java in Android Studio. Diese Datei enthält die Logik zum Verbinden der Firebase-SDKs mit den lokalen Emulatoren, die auf Ihrem Computer ausgeführt werden.

Untersuchen Sie oben in der Datei diese Zeile:

    /** Use emulators only in debug builds **/
    private static final boolean sUseEmulators = BuildConfig.DEBUG;

Wir verwenden BuildConfig , um sicherzustellen, dass wir nur dann eine Verbindung zu den Emulatoren herstellen, wenn unsere App im debug Modus ausgeführt wird. Wenn wir die App im release Modus kompilieren, ist diese Bedingung falsch.

Schauen Sie sich nun die Methode getFirestore() :

    public static FirebaseFirestore getFirestore() {
        if (FIRESTORE == null) {
            FIRESTORE = FirebaseFirestore.getInstance();

            // Connect to the Cloud Firestore emulator when appropriate. The host '10.0.2.2' is a
            // special IP address to let the Android emulator connect to 'localhost'.
            if (sUseEmulators) {
                FIRESTORE.useEmulator("10.0.2.2", 8080);
            }
        }

        return FIRESTORE;
    }

Wir können sehen, dass es die useEmulator(host, port) Methode useEmulator(host, port) verwendet, um das Firebase SDK mit dem lokalen Firestore-Emulator zu verbinden. In der gesamten App verwenden wir FirebaseUtil.getFirestore() um auf diese Instanz von FirebaseFirestore zuzugreifen, sodass wir sicher sind, dass wir im debug Modus immer eine Verbindung zum Firestore-Emulator herstellen.

Führen Sie die App aus

Wenn Sie die Datei google-services.json ordnungsgemäß hinzugefügt haben, sollte das Projekt jetzt kompiliert werden. Klicken Sie in Android Studio auf Erstellen > Projekt neu erstellen und stellen Sie sicher, dass keine verbleibenden Fehler vorliegen.

In Android Studio Führen Sie die App auf Ihrem Android-Emulator aus. Zunächst wird ein "Anmelden" -Bildschirm angezeigt. Sie können jede E-Mail und jedes Passwort verwenden, um sich bei der App anzumelden. Dieser Anmeldevorgang stellt eine Verbindung zum Firebase-Authentifizierungsemulator her, sodass keine echten Anmeldeinformationen übertragen werden.

Öffnen Sie nun die Emulators-Benutzeroberfläche, indem Sie in Ihrem Webbrowser zu http: // localhost: 4000 navigieren. Klicken Sie dann auf die Registerkarte Authentifizierung, und das gerade erstellte Konto sollte angezeigt werden:

Firebase Auth Emulator

Sobald Sie den Anmeldevorgang abgeschlossen haben, sollte der Startbildschirm der App angezeigt werden:

de06424023ffb4b9.png

In Kürze werden wir einige Daten hinzufügen, um den Startbildschirm zu füllen.

In diesem Abschnitt werden wir einige Daten in den Firestore schreiben, damit wir den derzeit leeren Startbildschirm füllen können.

Das Hauptmodellobjekt in unserer App ist ein Restaurant (siehe model/Restaurant.java ). Firestore-Daten werden in Dokumente, Sammlungen und Untersammlungen aufgeteilt. Wir werden jedes Restaurant als Dokument in einer Top-Level-Sammlung namens "restaurants" speichern. Weitere Informationen zum Firestore-Datenmodell finden Sie in der Dokumentation zu Dokumenten und Sammlungen.

Zu Demonstrationszwecken werden wir der App Funktionen hinzufügen, um zehn zufällige Restaurants zu erstellen, wenn wir im Überlaufmenü auf die Schaltfläche "Zufällige Elemente hinzufügen" klicken. Öffnen Sie die Datei MainActivity.java und geben Sie die Methode onAddItemsClicked() :

    private void onAddItemsClicked() {
        // Get a reference to the restaurants collection
        CollectionReference restaurants = mFirestore.collection("restaurants");

        for (int i = 0; i < 10; i++) {
            // Get a random Restaurant POJO
            Restaurant restaurant = RestaurantUtil.getRandom(this);

            // Add a new document to the restaurants collection
            restaurants.add(restaurant);
        }
    }

Es gibt ein paar wichtige Dinge, die Sie über den obigen Code beachten sollten:

  • Wir haben zunächst einen Verweis auf die "restaurants" -Sammlung erhalten. Sammlungen werden implizit erstellt, wenn Dokumente hinzugefügt werden. Daher war es nicht erforderlich, die Sammlung vor dem Schreiben von Daten zu erstellen.
  • Dokumente können mit POJOs erstellt werden, mit denen wir jedes Restaurantdokument erstellen.
  • Die Methode add() fügt einer Sammlung ein Dokument mit einer automatisch generierten ID hinzu, sodass wir nicht für jedes Restaurant eine eindeutige ID angeben mussten.

Führen Sie nun die App erneut aus und klicken Sie im Überlaufmenü auf die Schaltfläche "Zufällige Elemente hinzufügen", um den soeben geschriebenen Code aufzurufen:

95691e9b71ba55e3.png

Öffnen Sie nun die Emulators-Benutzeroberfläche, indem Sie in Ihrem Webbrowser zu http: // localhost: 4000 navigieren. Klicken Sie dann auf die Registerkarte Firestore und Sie sollten die Daten sehen, die Sie gerade hinzugefügt haben:

Firebase Auth Emulator

Diese Daten sind zu 100% lokal für Ihren Computer. Tatsächlich enthält Ihr reales Projekt noch nicht einmal eine Firestore-Datenbank! Dies bedeutet, dass Sie sicher mit dem Ändern und Löschen dieser Daten ohne Konsequenz experimentieren können.

Herzlichen Glückwunsch, Sie haben gerade Daten an Firestore geschrieben! Im nächsten Schritt lernen wir, wie diese Daten in der App angezeigt werden.

In diesem Schritt lernen wir, wie Sie Daten aus dem Firestore abrufen und in unserer App anzeigen. Der erste Schritt zum Lesen von Daten aus dem Firestore besteht darin, eine Query zu erstellen. onCreate() die onCreate() -Methode:

        mFirestore = FirebaseUtil.getFirestore();

        // Get the 50 highest rated restaurants
        mQuery = mFirestore.collection("restaurants")
                .orderBy("avgRating", Query.Direction.DESCENDING)
                .limit(LIMIT);

Jetzt möchten wir die Abfrage abhören, damit wir alle übereinstimmenden Dokumente erhalten und in Echtzeit über zukünftige Aktualisierungen informiert werden. Da unser letztendliches Ziel darin besteht, diese Daten an eine RecyclerView zu binden, müssen wir eine RecyclerView.Adapter Klasse erstellen, um die Daten abzuhören.

Öffnen Sie die FirestoreAdapter Klasse, die teilweise bereits implementiert wurde. Lassen Sie den Adapter zunächst EventListener implementieren und die onEvent Funktion definieren, damit er Aktualisierungen für eine Firestore-Abfrage erhalten kann:

public abstract class FirestoreAdapter<VH extends RecyclerView.ViewHolder>
        extends RecyclerView.Adapter<VH>
        implements EventListener<QuerySnapshot> { // Add this "implements"

    // ...

    // Add this method
    @Override
    public void onEvent(QuerySnapshot documentSnapshots,
                        FirebaseFirestoreException e) {

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

        // Dispatch the event
        for (DocumentChange change : documentSnapshots.getDocumentChanges()) {
            // Snapshot of the changed document
            DocumentSnapshot snapshot = change.getDocument();

            switch (change.getType()) {
                case ADDED:
                    // TODO: handle document added
                    break;
                case MODIFIED:
                    // TODO: handle document modified
                    break;
                case REMOVED:
                    // TODO: handle document removed
                    break;
            }
        }

        onDataChanged();
    }

  // ...
}

Beim ersten Laden erhält der Listener ein ADDED Ereignis für jedes neue Dokument. Wenn sich die Ergebnismenge der Abfrage im Laufe der Zeit ändert, erhält der Listener weitere Ereignisse, die die Änderungen enthalten. Lassen Sie uns nun die Implementierung des Listeners beenden. onDocumentAdded Sie zunächst drei neue Methoden hinzu: onDocumentAdded , onDocumentModified und onDocumentRemoved :

    protected void onDocumentAdded(DocumentChange change) {
        mSnapshots.add(change.getNewIndex(), change.getDocument());
        notifyItemInserted(change.getNewIndex());
    }

    protected void onDocumentModified(DocumentChange change) {
        if (change.getOldIndex() == change.getNewIndex()) {
            // Item changed but remained in same position
            mSnapshots.set(change.getOldIndex(), change.getDocument());
            notifyItemChanged(change.getOldIndex());
        } else {
            // Item changed and changed position
            mSnapshots.remove(change.getOldIndex());
            mSnapshots.add(change.getNewIndex(), change.getDocument());
            notifyItemMoved(change.getOldIndex(), change.getNewIndex());
        }
    }

    protected void onDocumentRemoved(DocumentChange change) {
        mSnapshots.remove(change.getOldIndex());
        notifyItemRemoved(change.getOldIndex());
    }

Rufen Sie dann diese neuen Methoden von onEvent :

    @Override
    public void onEvent(QuerySnapshot documentSnapshots,
                        FirebaseFirestoreException e) {

        // ...

        // Dispatch the event
        for (DocumentChange change : documentSnapshots.getDocumentChanges()) {
            // Snapshot of the changed document
            DocumentSnapshot snapshot = change.getDocument();

            switch (change.getType()) {
                case ADDED:
                    onDocumentAdded(change); // Add this line
                    break;
                case MODIFIED:
                    onDocumentModified(change); // Add this line
                    break;
                case REMOVED:
                    onDocumentRemoved(change); // Add this line
                    break;
            }
        }

        onDataChanged();
    }

Implementieren Sie startListening() Methode startListening() , um den Listener anzuhängen:

    public void startListening() {
        if (mQuery != null && mRegistration == null) {
            mRegistration = mQuery.addSnapshotListener(this);
        }
    }

Jetzt ist die App vollständig konfiguriert, um Daten aus dem Firestore zu lesen. Führen Sie die App erneut aus und Sie sollten die Restaurants sehen, die Sie im vorherigen Schritt hinzugefügt haben:

9e45f40faefce5d0.png

Kehren Sie nun in Ihrem Browser zur Emulator-Benutzeroberfläche zurück und bearbeiten Sie einen der Restaurantnamen. Sie sollten sehen, dass es sich in der App fast sofort ändert!

Die App zeigt derzeit die am besten bewerteten Restaurants in der gesamten Sammlung an. In einer echten Restaurant-App möchte der Benutzer die Daten jedoch sortieren und filtern. Zum Beispiel sollte die App in der Lage sein, "Top-Fischrestaurants in Philadelphia" oder "Am wenigsten teure Pizza" anzuzeigen.

Wenn Sie oben in der App auf den weißen Balken klicken, wird ein Filterdialog angezeigt. In diesem Abschnitt verwenden wir Firestore-Abfragen, damit dieser Dialog funktioniert:

67898572a35672a5.png

Lassen Sie uns die onFilter() -Methode von MainActivity.java . Diese Methode akzeptiert ein Filters Objekt, bei dem es sich um ein Hilfsobjekt handelt, das wir erstellt haben, um die Ausgabe des Filterdialogs zu erfassen. Wir werden diese Methode ändern, um eine Abfrage aus den Filtern zu erstellen:

    @Override
    public void onFilter(Filters filters) {
        // Construct query basic query
        Query query = mFirestore.collection("restaurants");

        // Category (equality filter)
        if (filters.hasCategory()) {
            query = query.whereEqualTo("category", filters.getCategory());
        }

        // City (equality filter)
        if (filters.hasCity()) {
            query = query.whereEqualTo("city", filters.getCity());
        }

        // Price (equality filter)
        if (filters.hasPrice()) {
            query = query.whereEqualTo("price", filters.getPrice());
        }

        // Sort by (orderBy with direction)
        if (filters.hasSortBy()) {
            query = query.orderBy(filters.getSortBy(), filters.getSortDirection());
        }

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

        // Update the query
        mQuery = query;
        mAdapter.setQuery(query);

        // Set header
        mCurrentSearchView.setText(Html.fromHtml(filters.getSearchDescription(this)));
        mCurrentSortByView.setText(filters.getOrderDescription(this));

        // Save filters
        mViewModel.setFilters(filters);
    }

Im Snippet oben bauen wir eine Query Objekt durch das Anbringen where und orderBy Klauseln die angegebenen Filter entsprechen.

Führen Sie die App erneut aus und wählen Sie den folgenden Filter aus, um die beliebtesten Niedrigpreisrestaurants anzuzeigen:

7a67a8a400c80c50.png

Sie sollten nun eine gefilterte Liste von Restaurants sehen, die nur günstige Optionen enthalten:

a670188398c3c59.png

Wenn Sie es bis hierher geschafft haben, haben Sie jetzt eine voll funktionsfähige App zum Anzeigen von Restaurantempfehlungen im Firestore erstellt! Sie können jetzt Restaurants in Echtzeit sortieren und filtern. In den nächsten Abschnitten veröffentlichen wir Bewertungen und Sicherheit in der App.

In diesem Abschnitt fügen wir der App Bewertungen hinzu, damit Benutzer ihre Lieblingsrestaurants (oder am wenigsten Lieblingsrestaurants) überprüfen können.

Sammlungen und Untersammlungen

Bisher haben wir alle Restaurantdaten in einer Top-Level-Sammlung namens "Restaurants" gespeichert. Wenn ein Benutzer ein Restaurant bewertet, möchten wir den Restaurants ein neues Rating hinzufügen. Für diese Aufgabe verwenden wir eine Untersammlung. Sie können sich eine Untersammlung als eine Sammlung vorstellen, die an ein Dokument angehängt ist. Jedes Restaurantdokument verfügt also über eine Bewertungssammlung mit Bewertungsdokumenten. Untersammlungen helfen beim Organisieren von Daten, ohne unsere Dokumente aufzublähen oder komplexe Abfragen zu erfordern.

Um auf eine .collection() zuzugreifen, rufen .collection() im übergeordneten Dokument .collection() auf:

CollectionReference subRef = mFirestore.collection("restaurants")
        .document("abc123")
        .collection("ratings");

Sie können wie bei einer Sammlung der obersten Ebene auf eine Untersammlung zugreifen und diese abfragen. Es gibt keine Größenbeschränkungen oder Leistungsänderungen. Weitere Informationen zum Firestore-Datenmodell finden Sie hier .

Daten in eine Transaktion schreiben

Das Hinzufügen einer Rating zur richtigen .add() erfordert nur den Aufruf von .add() . Wir müssen jedoch auch die durchschnittliche Bewertung und die Anzahl der Bewertungen des Restaurant aktualisieren, um die neuen Daten widerzuspiegeln. Wenn wir diese beiden Änderungen separat ausführen, gibt es eine Reihe von Rennbedingungen, die zu veralteten oder falschen Daten führen können.

Um sicherzustellen, dass die Bewertungen ordnungsgemäß hinzugefügt werden, verwenden wir eine Transaktion, um einem Restaurant Bewertungen hinzuzufügen. Diese Transaktion führt einige Aktionen aus:

  • Lesen Sie die aktuelle Bewertung des Restaurants und berechnen Sie die neue
  • Fügen Sie die Bewertung zur Untersammlung hinzu
  • Aktualisieren Sie die durchschnittliche Bewertung des Restaurants und die Anzahl der Bewertungen

Öffnen Sie RestaurantDetailActivity.java und implementieren Sie die Funktion addRating :

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

        // In a transaction, add the new rating and update the aggregate totals
        return mFirestore.runTransaction(new Transaction.Function<Void>() {
            @Override
            public Void apply(Transaction transaction)
                    throws FirebaseFirestoreException {

                Restaurant restaurant = transaction.get(restaurantRef)
                        .toObject(Restaurant.class);

                // Compute new number of ratings
                int newNumRatings = restaurant.getNumRatings() + 1;

                // Compute new average rating
                double oldRatingTotal = restaurant.getAvgRating() *
                        restaurant.getNumRatings();
                double newAvgRating = (oldRatingTotal + rating.getRating()) /
                        newNumRatings;

                // Set new restaurant info
                restaurant.setNumRatings(newNumRatings);
                restaurant.setAvgRating(newAvgRating);

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

                return null;
            }
        });
    }

Die Funktion addRating() gibt eine Task die die gesamte Transaktion darstellt. In der Funktion onRating() werden der Aufgabe Listener hinzugefügt, um auf das Ergebnis der Transaktion zu antworten.

Führen Sie nun die App erneut aus und klicken Sie auf eines der Restaurants, um den Bildschirm mit den Restaurantdetails aufzurufen. Klicken Sie auf die Schaltfläche + , um eine Bewertung hinzuzufügen. Fügen Sie eine Bewertung hinzu, indem Sie eine Reihe von Sternen auswählen und Text eingeben.

78fa16cdf8ef435a.png

Wenn Sie auf Senden klicken, wird die Transaktion gestartet . Wenn die Transaktion abgeschlossen ist, wird unten Ihre Bewertung angezeigt und die Anzahl der Bewertungen des Restaurants aktualisiert:

f9e670f40bd615b0.png

Glückwunsch! Sie haben jetzt eine soziale, lokale, mobile Restaurant-Bewertungs-App, die auf Cloud Firestore basiert. Ich höre, dass diese heutzutage sehr beliebt sind.

Bisher haben wir die Sicherheit dieser Anwendung nicht berücksichtigt. Woher wissen wir, dass Benutzer nur die richtigen eigenen Daten lesen und schreiben können? Firestore-Datenbanken werden durch eine Konfigurationsdatei namens Sicherheitsregeln gesichert.

Öffnen Sie die Datei firestore.rules . Sie sollten Folgendes sehen:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      //
      // WARNING: These rules are insecure! We will replace them with
      // more secure rules later in the codelab
      //
      allow read, write: if request.auth != null;
    }
  }
}

Lassen Sie uns diese Regeln ändern, um unerwünschte Datenzugriffe oder -änderungen zu verhindern. Öffnen Sie die Datei firestore.rules und ersetzen Sie den Inhalt durch Folgendes:

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

Diese Regeln beschränken den Zugriff, um sicherzustellen, dass Clients nur sichere Änderungen vornehmen. Beispielsweise können Aktualisierungen eines Restaurantdokuments nur die Bewertungen ändern, nicht den Namen oder andere unveränderliche Daten. Bewertungen können nur erstellt werden, wenn die Benutzer-ID mit dem angemeldeten Benutzer übereinstimmt, wodurch Spoofing verhindert wird.

Weitere Informationen zu Sicherheitsregeln finden Sie in der Dokumentation .

Sie haben jetzt eine voll funktionsfähige App über Firestore erstellt. Sie haben die wichtigsten Firestore-Funktionen kennengelernt, darunter:

  • Dokumente und Sammlungen
  • Daten lesen und schreiben
  • Sortieren und Filtern mit Abfragen
  • Untersammlungen
  • Transaktionen

Erfahren Sie mehr

Um mehr über Firestore zu erfahren, sind hier einige gute Orte, um loszulegen:

Die Restaurant-App in diesem Codelab basierte auf der Beispielanwendung "Friendly Eats". Sie können den Quellcode für diese App hier durchsuchen.

Optional: In der Produktion bereitstellen

Bisher hat diese App nur die Firebase Emulator Suite verwendet. Wenn Sie erfahren möchten, wie Sie diese App für ein echtes Firebase-Projekt bereitstellen, fahren Sie mit dem nächsten Schritt fort.

Bisher war diese App vollständig lokal, alle Daten sind in der Firebase Emulator Suite enthalten. In diesem Abschnitt erfahren Sie, wie Sie Ihr Firebase-Projekt so konfigurieren, dass diese App in der Produktion funktioniert.

Firebase-Authentifizierung

Gehen Sie im Firebase-Konsle zum Abschnitt Authentifizierung und navigieren Sie zur Registerkarte Anmeldeanbieter.

Aktivieren Sie die E-Mail-Anmeldemethode:

334ef7f6ff4da4ce.png

Firestore

Datenbank erstellen

Navigieren Sie zum Abschnitt Firestore der Konsole und klicken Sie auf Datenbank erstellen :

  1. Wenn Sie zu Sicherheitsregeln aufgefordert werden, im gesperrten Modus zu starten, werden diese Regeln bald aktualisiert.
  2. Wählen Sie den Datenbankspeicherort aus, den Sie für Ihre App verwenden möchten. Beachten Sie, dass die Auswahl eines Datenbankspeicherorts eine permanente Entscheidung ist. Um ihn zu ändern, müssen Sie ein neues Projekt erstellen. Weitere Informationen zur Auswahl eines Projektstandorts finden Sie in der Dokumentation .

Regeln bereitstellen

Führen Sie den folgenden Befehl im Codelab-Verzeichnis aus, um die zuvor geschriebenen Sicherheitsregeln bereitzustellen:

$ firebase deploy --only firestore:rules

Dadurch wird der Inhalt von firestore.rules für Ihr Projekt firestore.rules Dies können Sie bestätigen, indem Sie in der Konsole zur Registerkarte Regeln navigieren.

Indizes bereitstellen

Die FriendlyEats-App verfügt über eine komplexe Sortierung und Filterung, die eine Reihe von benutzerdefinierten zusammengesetzten Indizes erfordert. Diese können von Hand in der Firebase-Konsole erstellt werden. Es ist jedoch einfacher, ihre Definitionen in die Datei firestore.indexes.json zu schreiben und sie über die Firebase-CLI bereitzustellen.

Wenn Sie die Datei firestore.indexes.json öffnen, werden Sie feststellen, dass die erforderlichen Indizes bereits bereitgestellt wurden:

{
  "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": []
}

Führen Sie den folgenden Befehl aus, um diese Indizes bereitzustellen:

$ firebase deploy --only firestore:indexes

Beachten Sie, dass die Indexerstellung nicht sofort erfolgt. Sie können den Fortschritt in der Firebase-Konsole überwachen.

Konfigurieren Sie die App

In der FirebaseUtil Klasse haben wir das Firebase SDK so konfiguriert, dass es im Debug-Modus eine Verbindung zu den Emulatoren herstellt:

public class FirebaseUtil {

    /** Use emulators only in debug builds **/
    private static final boolean sUseEmulators = BuildConfig.DEBUG;

    // ...
}

Wenn Sie Ihre App mit Ihrem echten Firebase-Projekt testen möchten, können Sie entweder:

  1. Erstellen Sie die App im Release-Modus und führen Sie sie auf einem Gerät aus.
  2. Ändern Sie sUseEmulators vorübergehend in false und führen Sie die App erneut aus.

Beachten Sie, dass Sie aus der App müssen sich anmelden , und melden Sie sich erneut, um richtig zu Produktion zu verbinden.