1. Übersicht
Ziele
In diesem Codelab erstellen Sie eine Restaurantempfehlungs-App für Android, die von Cloud Firestore unterstützt wird. Nach Abschluss können Sie:
- Daten aus einer Android-App in Firestore lesen und schreiben
- Änderungen an Firestore-Daten in Echtzeit überwachen
- Firestore-Daten mit Firebase Authentication und Sicherheitsregeln schützen
- Komplexe Firestore-Abfragen schreiben
Vorbereitung
Bevor Sie mit diesem Codelab beginnen, müssen Sie Folgendes haben:
- Android Studio Flamingo oder höher
- Ein Android-Emulator mit API‑Level 19 oder höher
- Node.js-Version 16 oder höher
- Java-Version 17 oder höher
2. Firebase-Projekt erstellen
- Melden Sie sich mit Ihrem Google-Konto in der Firebase Console an.
- Klicken Sie auf die Schaltfläche, um ein neues Projekt zu erstellen, und geben Sie dann einen Projektnamen ein (z. B.
FriendlyEats
).
- Klicken Sie auf Weiter.
- Lesen und akzeptieren Sie bei Aufforderung die Firebase-Nutzungsbedingungen und klicken Sie dann auf Weiter.
- (Optional) Aktivieren Sie die KI-Unterstützung in der Firebase Console (als „Gemini in Firebase“ bezeichnet).
- Für dieses Codelab benötigen Sie kein Google Analytics. Deaktivieren Sie daher die Google Analytics-Option.
- Klicken Sie auf Projekt erstellen, warten Sie, bis Ihr Projekt bereitgestellt wurde, und klicken Sie dann auf Weiter.
3. Beispielprojekt einrichten
Code herunterladen
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
erstellt:
$ git clone https://github.com/firebase/friendlyeats-android
Wenn Sie Git nicht auf Ihrem Computer haben, können Sie den Code auch direkt von GitHub herunterladen.
Firebase-Konfiguration hinzufügen
- Wählen Sie in der Firebase Console im linken Navigationsbereich Projektübersicht aus. Klicken Sie auf die Schaltfläche Android, um die Plattform auszuwählen. Wenn Sie nach einem Paketnamen gefragt werden, verwenden Sie
com.google.firebase.example.fireeats
.
- Klicken Sie auf App registrieren und folgen Sie der Anleitung, um die Datei
google-services.json
herunterzuladen und in den Ordnerapp/
des gerade heruntergeladenen Codes zu verschieben. Klicken Sie anschließend auf Weiter.
Projekt importieren
Öffnen Sie Android Studio. Klicken Sie auf File > New > Import Project und wählen Sie den Ordner friendlyeats-android aus.
4. Firebase-Emulatoren einrichten
In diesem Codelab verwenden Sie die Firebase Emulator Suite, um Cloud Firestore und andere Firebase-Dienste lokal zu emulieren. So erhalten Sie eine sichere, schnelle und kostenlose lokale Entwicklungsumgebung für die Entwicklung Ihrer App.
Firebase CLI installieren
Zuerst müssen Sie die Firebase CLI installieren. Wenn Sie macOS oder Linux verwenden, können Sie den folgenden cURL-Befehl ausführen:
curl -sL https://firebase.tools | bash
Wenn Sie Windows verwenden, finden Sie hier eine Installationsanleitung, um ein eigenständiges Binärprogramm zu erhalten oder die Installation über npm
vorzunehmen.
Nach der Installation der CLI sollte bei der Ausführung von firebase --version
eine Version von 9.0.0
oder höher angezeigt werden:
$ firebase --version 9.0.0
Anmelden
Führen Sie firebase login
aus, um die CLI mit Ihrem Google-Konto zu verbinden. Dadurch wird ein neues Browserfenster geöffnet, in dem Sie sich anmelden können. Wählen Sie dasselbe Konto aus, das Sie zuvor beim Erstellen Ihres Firebase-Projekts verwendet haben.
Projekt verknüpfen
Führen Sie im Ordner friendlyeats-android
den Befehl firebase use --add
aus, um Ihr lokales Projekt mit Ihrem Firebase-Projekt zu verbinden. Folgen Sie der Anleitung, um das zuvor erstellte Projekt auszuwählen. Wenn Sie aufgefordert werden, einen Alias auszuwählen, geben Sie default
ein.
5. Anwendung ausführen
Jetzt ist es an der Zeit, die Firebase Emulator Suite und die FriendlyEats-Android-App zum ersten Mal auszuführen.
Emulatoren ausführen
Führen Sie in Ihrem Terminal im Verzeichnis friendlyeats-android
den Befehl firebase emulators:start
aus, um die Firebase-Emulatoren zu starten. Die Logs sollten so aussehen:
$ 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. Lassen Sie diesen Befehl für den Rest des Codelabs laufen, da Ihre Android-App eine Verbindung zu den Emulatoren herstellen muss.
App mit den Emulatoren verbinden
Öffnen Sie die Dateien util/FirestoreInitializer.kt
und util/AuthInitializer.kt
in Android Studio. Diese Dateien enthalten die Logik, um die Firebase SDKs beim Start der Anwendung mit den lokalen Emulatoren auf Ihrem Computer zu verbinden.
Sehen Sie sich in der Methode create()
der Klasse FirestoreInitializer
diesen Code an:
// Use emulators only in debug builds
if (BuildConfig.DEBUG) {
firestore.useEmulator(FIRESTORE_EMULATOR_HOST, FIRESTORE_EMULATOR_PORT)
}
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.
Wir sehen, dass die useEmulator(host, port)
-Methode verwendet wird, 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. So stellen wir sicher, dass wir im debug
-Modus immer eine Verbindung zum Firestore-Emulator herstellen.
Anwendung ausführen
Wenn Sie die Datei google-services.json
richtig hinzugefügt haben, sollte das Projekt jetzt kompiliert werden. Klicken Sie in Android Studio auf Build > Rebuild Project (Erstellen > Projekt neu erstellen) und prüfen Sie, ob noch Fehler vorhanden sind.
Führen Sie die App in Android Studio auf Ihrem Android-Emulator aus. Zuerst wird der Bildschirm „Anmelden“ angezeigt. Sie können sich mit einer beliebigen E-Mail-Adresse und einem beliebigen Passwort in der App anmelden. Bei diesem Anmeldevorgang wird eine Verbindung zum Firebase Authentication-Emulator hergestellt, sodass keine echten Anmeldedaten übertragen werden.
Öffnen Sie jetzt die Emulators-Benutzeroberfläche, indem Sie in Ihrem Webbrowser zu http://localhost:4000 gehen. Klicken Sie dann auf den Tab Authentifizierung. Das gerade erstellte Konto sollte angezeigt werden:
Nachdem Sie sich angemeldet haben, sollte der Startbildschirm der App angezeigt werden:
Bald werden wir einige Daten hinzufügen, um den Startbildschirm zu füllen.
6. Daten in Firestore schreiben
In diesem Abschnitt schreiben wir einige Daten in Firestore, damit wir den derzeit leeren Startbildschirm füllen können.
Das Hauptmodellobjekt in unserer App ist ein Restaurant (siehe model/Restaurant.kt
). Firestore-Daten werden in Dokumente, Sammlungen und untergeordnete Sammlungen aufgeteilt. Wir speichern jedes Restaurant als Dokument in einer Sammlung auf oberster Ebene namens "restaurants"
. Weitere Informationen zum Firestore-Datenmodell finden Sie in den Dokumenten und Sammlungen der Dokumentation.
Zu Demonstrationszwecken fügen wir der App eine Funktion hinzu, mit der zehn zufällige Restaurants erstellt werden, wenn wir im Überlaufmenü auf die Schaltfläche „Zufällige Elemente hinzufügen“ klicken. Öffnen Sie die Datei MainFragment.kt
und ersetzen Sie den Inhalt der Methode onAddItemsClicked()
durch Folgendes:
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)
}
}
Hier sind einige wichtige Punkte zum obigen Code:
- Zuerst haben wir einen Verweis auf die
"restaurants"
-Sammlung abgerufen. 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 Kotlin-Datenklassen erstellt werden, die wir zum Erstellen der einzelnen Restaurantdokumente verwenden.
- Mit der Methode
add()
wird einer Sammlung ein Dokument mit einer automatisch generierten ID hinzugefügt. Daher mussten wir keine eindeutige ID für jedes Restaurant angeben.
Führen Sie die App jetzt noch einmal aus und klicken Sie im Überlaufmenü (oben rechts) auf die Schaltfläche „Add Random Items“ (Zufällige Elemente hinzufügen), um den gerade geschriebenen Code aufzurufen:
Öffnen Sie jetzt die Emulators-Benutzeroberfläche, indem Sie in Ihrem Webbrowser zu http://localhost:4000 gehen. Klicken Sie dann auf den Tab Firestore. Dort sollten Sie die gerade hinzugefügten Daten sehen:
Diese Daten sind zu 100% lokal auf Ihrem Computer gespeichert. Ihr echtes Projekt enthält noch nicht einmal eine Firestore-Datenbank. Sie können diese Daten also gefahrlos ändern und löschen.
Glückwunsch! Sie haben gerade Daten in Firestore geschrieben. Im nächsten Schritt erfahren Sie, wie Sie diese Daten in der App anzeigen.
7. Daten aus Firestore anzeigen
In diesem Schritt erfahren wir, wie wir Daten aus Firestore abrufen und in unserer App anzeigen. Der erste Schritt zum Lesen von Daten aus Firestore besteht darin, eine Query
zu erstellen. Öffnen Sie die Datei MainFragment.kt
und fügen Sie den folgenden Code am Anfang der Methode onViewCreated()
ein:
// Firestore
firestore = Firebase.firestore
// Get the 50 highest rated restaurants
query = firestore.collection("restaurants")
.orderBy("avgRating", Query.Direction.DESCENDING)
.limit(LIMIT.toLong())
Jetzt möchten wir die Abfrage überwachen, damit wir alle übereinstimmenden Dokumente erhalten und über zukünftige Aktualisierungen in Echtzeit benachrichtigt werden. Da wir diese Daten letztendlich an ein RecyclerView
binden möchten, müssen wir eine RecyclerView.Adapter
-Klasse erstellen, um die Daten zu erfassen.
Öffnen Sie die Klasse FirestoreAdapter
, die bereits teilweise implementiert wurde. Zuerst muss der Adapter EventListener
implementieren. Außerdem muss die Funktion onEvent
so definiert werden, dass sie Aktualisierungen einer Firestore-Abfrage empfangen kann:
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()
}
// ...
}
Beim ersten Laden erhält der Listener für jedes neue Dokument ein ADDED
-Ereignis. Wenn sich das Ergebnis-Set der Abfrage im Laufe der Zeit ändert, empfängt der Listener weitere Ereignisse mit den Änderungen. Jetzt implementieren wir den Listener fertig. Fügen Sie zuerst drei neue Methoden hinzu: onDocumentAdded
, onDocumentModified
und 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)
}
Rufen Sie dann diese neuen Methoden über onEvent
auf:
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()
}
Implementieren Sie schließlich die Methode startListening()
, um den Listener anzuhängen:
fun startListening() {
if (registration == null) {
registration = query.addSnapshotListener(this)
}
}
Die App ist jetzt vollständig konfiguriert, um Daten aus Firestore zu lesen. Führen Sie die App noch einmal aus. Die Restaurants, die Sie im vorherigen Schritt hinzugefügt haben, sollten angezeigt werden:
Kehren Sie nun zur Emulator-Benutzeroberfläche in Ihrem Browser zurück und bearbeiten Sie einen der Restaurantnamen. Die Änderung sollte in der App fast sofort sichtbar sein.
8. Daten sortieren und filtern
In der App werden derzeit die am besten bewerteten Restaurants in der gesamten Sammlung angezeigt. In einer echten Restaurant-App möchte der Nutzer die Daten jedoch sortieren und filtern. Die App sollte beispielsweise „Top-Fischrestaurants in Philadelphia“ oder „Günstigste Pizza“ anzeigen können.
Wenn Sie oben in der App auf die weiße Leiste klicken, wird ein Filterdialogfeld aufgerufen. In diesem Abschnitt verwenden wir Firestore-Abfragen, um diesen Dialog zu ermöglichen:
Bearbeiten wir die Methode onFilter()
von MainFragment.kt
. Diese Methode akzeptiert ein Filters
-Objekt. Das ist ein Hilfsobjekt, das wir erstellt haben, um die Ausgabe des Filterdialogfelds zu erfassen. Wir ändern diese Methode, um eine Abfrage aus den Filtern zu erstellen:
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
}
Im Snippet oben erstellen wir ein Query
-Objekt, indem wir where
- und orderBy
-Klauseln anhängen, die den angegebenen Filtern entsprechen.
Führen Sie die App noch einmal aus und wählen Sie den folgenden Filter aus, um die beliebtesten Restaurants mit niedrigen Preisen aufzurufen:
Sie sollten jetzt eine gefilterte Liste von Restaurants sehen, die nur Optionen mit niedrigen Preisen enthält:
Wenn Sie bis hierher gekommen sind, haben Sie jetzt eine voll funktionsfähige App zum Anzeigen von Restaurantempfehlungen in Firestore erstellt. Sie können Restaurants jetzt in Echtzeit sortieren und filtern. In den nächsten Abschnitten fügen wir den Restaurants Rezensionen und der App Sicherheitsregeln hinzu.
9. Daten in untergeordneten Sammlungen organisieren
In diesem Abschnitt fügen wir der App Bewertungen hinzu, damit Nutzer ihre Lieblingsrestaurants (oder die Restaurants, die sie am wenigsten mögen) bewerten können.
Sammlungen und Untersammlungen
Bisher haben wir alle Restaurantdaten in einer Sammlung auf oberster Ebene namens „restaurants“ gespeichert. Wenn ein Nutzer ein Restaurant bewertet, möchten wir den Restaurants ein neues Rating
-Objekt hinzufügen. Für diese Aufgabe verwenden wir eine untergeordnete Sammlung. Eine untergeordnete Sammlung ist eine Sammlung, die an ein Dokument angehängt ist. Jedes Restaurantdokument hat also eine untergeordnete Sammlung „Bewertungen“ mit Bewertungsdokumenten. Mit untergeordneten Sammlungen lassen sich Daten organisieren, ohne dass Dokumente aufgebläht werden oder komplexe Abfragen erforderlich sind.
Rufen Sie .collection()
für das übergeordnete Dokument auf, um auf eine untergeordnete Sammlung zuzugreifen:
val subRef = firestore.collection("restaurants")
.document("abc123")
.collection("ratings")
Sie können auf eine Unterkollektion zugreifen und sie abfragen, genau wie bei einer Sammlung der obersten Ebene. Es gibt keine Größenbeschränkungen oder Leistungsänderungen. Weitere Informationen zum Firestore-Datenmodell
Daten in eine Transaktion schreiben
Wenn Sie ein Rating
der richtigen Unterkollektion hinzufügen möchten, müssen Sie nur .add()
aufrufen. Wir müssen aber auch die durchschnittliche Bewertung und die Anzahl der Bewertungen des Restaurant
-Objekts aktualisieren, damit die neuen Daten berücksichtigt werden. Wenn wir separate Vorgänge verwenden, um diese beiden Änderungen vorzunehmen, kann es zu einer Reihe von Race-Bedingungen kommen, die zu veralteten oder falschen Daten führen.
Damit Bewertungen richtig hinzugefügt werden, verwenden wir eine Transaktion, um einem Restaurant Bewertungen hinzuzufügen. Bei dieser Transaktion werden einige Aktionen ausgeführt:
- Aktuelle Bewertung des Restaurants lesen und neue Bewertung berechnen
- Bewertung zur Untergruppe hinzufügen
- Aktualisieren der durchschnittlichen Bewertung und der Anzahl der Bewertungen des Restaurants
Öffnen Sie RestaurantDetailFragment.kt
und implementieren Sie die Funktion 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
}
}
Die Funktion addRating()
gibt ein Task
zurück, das die gesamte Transaktion darstellt. In der Funktion onRating()
werden Listener für die Aufgabe hinzugefügt, um auf das Ergebnis der Transaktion zu reagieren.
Führen Sie die App nun noch einmal aus und klicken Sie auf eines der Restaurants. Dadurch sollte der Detailbildschirm des Restaurants aufgerufen werden. Klicken Sie auf die Schaltfläche +, um eine Rezension hinzuzufügen. Fügen Sie eine Rezension hinzu, indem Sie eine Anzahl von Sternen auswählen und etwas Text eingeben.
Wenn Sie auf Senden klicken, wird die Transaktion gestartet. Wenn die Transaktion abgeschlossen ist, wird Ihre Rezension unten angezeigt und die Anzahl der Rezensionen des Restaurants wird aktualisiert:
Glückwunsch! Sie haben jetzt eine soziale, lokale, mobile Restaurantrezensions-App, die auf Cloud Firestore basiert. Ich habe gehört, dass sie heutzutage sehr beliebt sind.
10. Daten schützen
Bisher haben wir die Sicherheit dieser Anwendung nicht berücksichtigt. Woher wissen wir, dass Nutzer nur die richtigen eigenen Daten lesen und schreiben können? Firestore-Datenbanken werden durch eine Konfigurationsdatei namens Sicherheitsregeln geschützt.
Ö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 schränken den Zugriff ein, damit Clients nur sichere Änderungen vornehmen. Bei Aktualisierungen eines Restaurantdokuments können beispielsweise nur die Bewertungen geändert werden, nicht der Name oder andere unveränderliche Daten. Bewertungen können nur erstellt werden, wenn die Nutzer-ID mit dem angemeldeten Nutzer übereinstimmt. Dadurch wird Spoofing verhindert.
Weitere Informationen zu Sicherheitsregeln finden Sie in der Dokumentation.
11. Fazit
Sie haben jetzt eine voll funktionsfähige App auf Grundlage von Firestore erstellt. Sie haben die wichtigsten Firestore-Funktionen kennengelernt, darunter:
- Dokumente und Sammlungen
- Daten lesen und schreiben
- Sortieren und Filtern mit Abfragen
- Untergeordnete Sammlungen
- Transaktionen
Weitere Informationen
Hier sind einige gute Ausgangspunkte, um mehr über Firestore zu erfahren:
Die Restaurant-App in diesem Codelab basiert auf der Beispielanwendung „Friendly Eats“. Den Quellcode für diese App finden Sie hier.
Optional: Für die Produktion bereitstellen
Bisher wurde in dieser App nur die Firebase Emulator Suite verwendet. Wenn Sie wissen möchten, wie Sie diese App in einem echten Firebase-Projekt bereitstellen, fahren Sie mit dem nächsten Schritt fort.
12. (Optional) Anwendung bereitstellen
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 Authentication
Rufen Sie in der Firebase Console den Abschnitt Authentifizierung auf und klicken Sie auf Jetzt starten. Rufen Sie den Tab Anmeldemethode auf und wählen Sie unter Native Anbieter die Option E-Mail/Passwort aus.
Aktivieren Sie die Anmeldemethode E-Mail-Adresse/Passwort und klicken Sie auf Speichern.
Firestore
Datenbank erstellen
Rufen Sie in der Console den Abschnitt Firestore-Datenbank auf und klicken Sie auf Datenbank erstellen:
- Wenn Sie nach Sicherheitsregeln gefragt werden, wählen Sie Produktionsmodus aus. Wir aktualisieren diese Regeln in Kürze.
- Wählen Sie den Datenbankstandort aus, den Sie für Ihre App verwenden möchten. Die Auswahl eines Datenbankstandorts ist eine dauerhafte Entscheidung. Wenn Sie den Standort ändern möchten, 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 werden die Inhalte von firestore.rules
in Ihrem Projekt bereitgestellt. Sie können dies bestätigen, indem Sie in der Konsole den Tab Regeln aufrufen.
Indexe bereitstellen
Die FriendlyEats-App hat komplexe Sortier- und Filterfunktionen, für die eine Reihe benutzerdefinierter zusammengesetzter Indexe erforderlich sind. Sie können manuell in der Firebase Console erstellt werden, es ist jedoch einfacher, ihre Definitionen in die Datei firestore.indexes.json
zu schreiben und sie mit der Firebase CLI bereitzustellen.
Wenn Sie die Datei firestore.indexes.json
öffnen, sehen Sie, dass die erforderlichen Indexe bereits angegeben 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 Indexe bereitzustellen:
$ firebase deploy --only firestore:indexes
Das Erstellen von Indexen erfolgt nicht sofort. Sie können den Fortschritt in der Firebase Console verfolgen.
Anwendung konfigurieren
In den Dateien util/FirestoreInitializer.kt
und util/AuthInitializer.kt
haben wir das Firebase SDK so konfiguriert, dass es im Debugmodus eine Verbindung zu den Emulatoren herstellt:
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
}
Wenn Sie Ihre App mit Ihrem echten Firebase-Projekt testen möchten, haben Sie folgende Möglichkeiten:
- Erstellen Sie die App im Release-Modus und führen Sie sie auf einem Gerät aus.
- Ersetzen Sie
BuildConfig.DEBUG
vorübergehend durchfalse
und führen Sie die App noch einmal aus.
Möglicherweise müssen Sie sich von der App abmelden und noch einmal anmelden, um eine Verbindung zur Produktion herzustellen.