1. Omówienie
Cele
W tym ćwiczeniu z programowania utworzysz aplikację na Androida z rekomendacjami restauracji, która korzysta z Cloud Firestore. Zapoznasz się z tymi zagadnieniami:
- Odczytywanie i zapisywanie danych w Firestore z aplikacji na Androida
- Słuchaj zmian w danych Firestore w czasie rzeczywistym
- Zabezpieczanie danych Firestore za pomocą uwierzytelniania i reguł zabezpieczeń Firebase
- Pisanie złożonych zapytań Firestore
Wymagania wstępne
Zanim zaczniesz korzystać z tego Codelab, upewnij się, że masz:
- Android Studio w wersji Flamingo lub nowszej
- emulatora Androida z interfejsem API w wersji 19 lub nowszej,
- Node.js w wersji 16 lub nowszej.
- Java w wersji 17 lub nowszej.
2. Tworzenie projektu Firebase
- Zaloguj się w konsoli Firebase za pomocą konta Google.
- W konsoli Firebase kliknij Dodaj projekt.
- Jak widać na zrzucie ekranu poniżej, wpisz nazwę projektu Firebase (np. „Friendly Eats”), a potem kliknij Dalej.
- Możesz otrzymać prośbę o włączenie Google Analytics, ale w ramach tego ćwiczenia nie ma to znaczenia.
- Po około minucie Twój projekt Firebase będzie gotowy. Kliknij Dalej.
3. Konfigurowanie przykładowego projektu
Pobieranie kodu
Aby skopiować przykładowy kod do tego ćwiczenia, uruchom to polecenie. Spowoduje to utworzenie na komputerze folderu o nazwie friendlyeats-android
:
$ git clone https://github.com/firebase/friendlyeats-android
Jeśli nie masz git na komputerze, możesz też pobrać kod bezpośrednio z GitHuba.
Dodawanie konfiguracji Firebase
- W konsoli Firebase kliknij Przegląd projektu w menu nawigacyjnym po lewej stronie. Kliknij przycisk Android, aby wybrać platformę. Gdy pojawi się prośba o podanie nazwy pakietu, wpisz
com.google.firebase.example.fireeats
.
- Kliknij Zarejestruj aplikację i postępuj zgodnie z instrukcjami, aby pobrać plik
google-services.json
i przenieść go do folderuapp/
, w którym znajduje się pobrany przez Ciebie kod. Następnie kliknij Dalej.
Importowanie projektu
Otwórz Android Studio. Kliknij Plik > Nowy > Importuj projekt i wybierz folder friendlyeats-android.
4. Konfigurowanie emulatorów Firebase
W tym laboratorium kodu użyjesz pakietu emulatorów Firebase, aby emulować lokalnie Cloud Firestore i inne usługi Firebase. Dzięki temu możesz tworzyć aplikacje w bezpiecznym, szybkim i bezpłatnym środowisku lokalnym.
Instalowanie wiersza poleceń Firebase
Najpierw musisz zainstalować wiersz poleceń Firebase. Jeśli używasz systemu macOS lub Linux, możesz uruchomić to polecenie cURL:
curl -sL https://firebase.tools | bash
Jeśli używasz systemu Windows, przeczytaj instrukcje instalacji, aby pobrać samodzielny plik binarny lub zainstalować program za pomocą npm
.
Po zainstalowaniu interfejsu wiersza poleceń uruchomienie firebase --version
powinno wygenerować wersję 9.0.0
lub nowszą:
$ firebase --version 9.0.0
Zaloguj się
Uruchom firebase login
, aby połączyć interfejs wiersza poleceń z kontem Google. Otworzy się nowe okno przeglądarki, w którym możesz dokończyć proces logowania. Pamiętaj, aby wybrać to samo konto, którego użyto wcześniej podczas tworzenia projektu Firebase.
Łączenie projektu
W folderze friendlyeats-android
uruchom firebase use --add
, aby połączyć projekt lokalny z projektem Firebase. Postępuj zgodnie z instrukcjami, aby wybrać utworzony wcześniej projekt. Jeśli pojawi się prośba o wybranie aliasu, wpisz default
.
5. Uruchamianie aplikacji
Teraz czas na pierwsze uruchomienie pakietu emulatorów Firebase i aplikacji FriendlyEats na Androida.
Uruchamianie emulatorów
Aby uruchomić emulatory Firebase, w terminalu w katalogu friendlyeats-android
uruchom firebase emulators:start
. Powinny pojawić się takie dzienniki:
$ 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.
Na komputerze masz teraz pełne lokalne środowisko programistyczne. Podczas dalszej pracy z tym ćwiczeniem nie zamykaj tego polecenia, ponieważ Twoja aplikacja na Androida musi połączyć się z emulatorami.
Łączenie aplikacji z emulatorami
Otwórz pliki util/FirestoreInitializer.kt
i util/AuthInitializer.kt
w Android Studio. Te pliki zawierają logikę, która łączy pakiety SDK Firebase z lokalnymi emulatorami uruchomionymi na Twoim komputerze po uruchomieniu aplikacji.
W metodzie create()
klasy FirestoreInitializer
sprawdź ten fragment kodu:
// Use emulators only in debug builds
if (BuildConfig.DEBUG) {
firestore.useEmulator(FIRESTORE_EMULATOR_HOST, FIRESTORE_EMULATOR_PORT)
}
Używamy BuildConfig
, aby mieć pewność, że łączymy się z emulatorami tylko wtedy, gdy aplikacja działa w trybie debug
. Gdy skompilujemy aplikację w trybie release
, to warunek będzie fałszywy.
Widzimy, że do połączenia pakietu Firebase SDK z lokalnym emulatorem Firestore używana jest metoda useEmulator(host, port)
. W całej aplikacji używamy funkcji FirebaseUtil.getFirestore()
, aby uzyskać dostęp do tej instancji usługi FirebaseFirestore
. Dzięki temu mamy pewność, że w trybie debug
zawsze łączymy się z emulatorem Firestore.
Uruchamianie aplikacji
Jeśli plik google-services.json
został dodany prawidłowo, projekt powinien się skompilować. W Android Studio kliknij Kompiluj > Ponownie skompiluj projekt i upewnij się, że nie ma żadnych błędów.
W Android Studio uruchom aplikację w emulatorze Androida. Najpierw zobaczysz ekran logowania. Do zalogowania się w aplikacji możesz użyć dowolnego adresu e-mail i hasła. Ten proces logowania łączy się z emulatorem Uwierzytelniania Firebase, więc nie są przesyłane żadne prawdziwe dane logowania.
Teraz otwórz interfejs emulatorów, wpisując w przeglądarce adres http://localhost:4000. Następnie kliknij kartę Uwierzytelnianie. Powinno się wyświetlić utworzone konto:
Po zakończeniu procesu logowania powinien wyświetlić się ekran główny aplikacji:
Wkrótce dodamy dane, aby wypełnić ekran główny.
6. Zapisywanie danych w Firestore
W tej sekcji zapiszemy w Firestore kilka danych, aby wypełnić pusty ekran główny.
Głównym obiektem modelu w naszej aplikacji jest restauracja (patrz model/Restaurant.kt
). Dane Firestore są podzielone na dokumenty, kolekcje i podkolekcje. Każdą restaurację będziemy przechowywać jako dokument w kolekcji najwyższego poziomu o nazwie "restaurants"
. Więcej informacji o modelu danych Firestore znajdziesz w dokumentacji dotyczącej dokumentów i kolekcji.
W ramach demonstracji dodamy w aplikacji funkcję, która po kliknięciu przycisku „Dodaj losowe elementy” w menu przepełnienia spowoduje utworzenie 10 losowych restauracji. Otwórz plik MainFragment.kt
i zastąp zawartość metody onAddItemsClicked()
tym fragmentem kodu:
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)
}
}
W przypadku tego kodu należy zwrócić uwagę na kilka ważnych kwestii:
- Najpierw uzyskaliśmy odwołanie do kolekcji
"restaurants"
. Kolekcje są tworzone domyślnie podczas dodawania dokumentów, więc nie trzeba było tworzyć kolekcji przed zapisaniem danych. - Dokumenty można tworzyć za pomocą klas danych Kotlin, których używamy do tworzenia każdego dokumentu restauracji.
- Metoda
add()
dodaje dokument do kolekcji z automatycznie wygenerowanym identyfikatorem, więc nie musieliśmy podawać unikalnego identyfikatora dla każdej restauracji.
Uruchom ponownie aplikację i w menu rozszerzonym (w prawym górnym rogu) kliknij przycisk „Dodaj losowe elementy”, aby wywołać kod, który właśnie napisałeś:
Teraz otwórz interfejs emulatorów, wpisując w przeglądarce adres http://localhost:4000. Następnie kliknij kartę Firestore. Powinny się tam wyświetlić właśnie dodane dane:
Te dane są w 100% lokalne na Twoim komputerze. W Twoim prawdziwym projekcie nie ma jeszcze bazy danych Firestore. Oznacza to, że możesz bezpiecznie eksperymentować z modyfikowaniem i usuwaniem tych danych bez żadnych konsekwencji.
Gratulacje! Właśnie zapisaliśmy dane do Firestore. W następnym kroku dowiesz się, jak wyświetlać te dane w aplikacji.
7. Wyświetlanie danych z Firestore
W tym kroku dowiesz się, jak pobierać dane z Firestore i wyświetlać je w aplikacji. Pierwszym krokiem do odczytania danych z Firestore jest utworzenie Query
. Otwórz plik MainFragment.kt
i na początku metody onViewCreated()
dodaj ten kod:
// Firestore
firestore = Firebase.firestore
// Get the 50 highest rated restaurants
query = firestore.collection("restaurants")
.orderBy("avgRating", Query.Direction.DESCENDING)
.limit(LIMIT.toLong())
Teraz chcemy przesłuchać zapytanie, aby uzyskać wszystkie pasujące dokumenty i otrzymywać w czasie rzeczywistym powiadomienia o przyszłych aktualizacjach. Naszym ostatecznym celem jest powiązanie tych danych z elementem RecyclerView
, więc musimy utworzyć klasę RecyclerView.Adapter
, która będzie je odbierać.
Otwórz klasę FirestoreAdapter
, która została już częściowo zaimplementowana. Najpierw sprawmy, aby adapter zaimplementował interfejs EventListener
i zdefiniował funkcję onEvent
, tak aby mógł otrzymywać aktualizacje zapytania 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()
}
// ...
}
Podczas początkowego wczytywania detektory otrzymują po jednym zdarzeniu ADDED
dla każdego nowego dokumentu. Gdy z czasem zmienia się zbiór wyników zapytania, detektor będzie otrzymywać więcej zdarzeń zawierających te zmiany. Teraz dokończ implementację listenera. Najpierw dodaj 3 nowe metody: onDocumentAdded
, onDocumentModified
i 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)
}
Następnie wywołaj te nowe metody z poziomu 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()
}
Na koniec zaimplementuj metodę startListening()
, aby dołączyć obiekt do odbiorcy:
fun startListening() {
if (registration == null) {
registration = query.addSnapshotListener(this)
}
}
Aplikacja jest teraz w pełni skonfigurowana do odczytu danych z Firestore. Uruchom aplikację ponownie. Powinny pojawić się restauracje dodane w poprzednim kroku:
Wróć do interfejsu emulatora w przeglądarce i zmodyfikuj nazwę jednej z restauracji. Zmiana powinna nastąpić w aplikacji niemal natychmiast.
8. sortować i filtrować dane,
Aplikacja wyświetla obecnie restauracje z najlepszymi ocenami w całej kolekcji, ale w rzeczywistej aplikacji użytkownik chciałby sortować i filtrować dane. Aplikacja powinna np. wyświetlać „Najlepsze restauracje z owocami morza w Filadelfii” lub „Najtańsza pizza”.
Kliknięcie białego paska u góry aplikacji powoduje wyświetlenie okna filtrów. W tej sekcji użyjemy zapytań Firestore, aby ten dialog działał:
Zmieńmy metodę onFilter()
w klasie MainFragment.kt
. Ta metoda przyjmuje obiekt Filters
, który jest obiektem pomocniczym utworzonym przez nas w celu przechwycenia danych wyjściowych z okna dialogowego filtrów. Zmienimy tę metodę, aby tworzyć zapytanie na podstawie filtrów:
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
}
W kodzie źródłowym powyżej tworzymy obiekt Query
, dołączając klauzule where
i orderBy
, aby dopasować je do podanych filtrów.
Uruchom aplikację ponownie i wybierz filtr, aby wyświetlić najpopularniejsze restauracje w niskiej cenie:
Powinna wyświetlić się lista restauracji zawierająca tylko opcje z niskimi cenami:
Jeśli dotarłeś/-aś do tego miejsca, masz już w Firestore w pełni działającą aplikację do wyświetlania rekomendacji restauracji. Teraz możesz sortować i filtrować restauracje w czasie rzeczywistym. W kolejnych sekcjach dodamy opinie o restauracjach i reguły bezpieczeństwa do aplikacji.
9. Porządkowanie danych w podkolekcjach
W tej sekcji dodamy do aplikacji oceny, aby użytkownicy mogli oceniać swoje ulubione (lub najmniej ulubione) restauracje.
Kolekcje i podkolekcje
Do tej pory wszystkie dane o restauracjach były przechowywane w kolekcji najwyższego poziomu o nazwie „restauracje”. Gdy użytkownik oceni restaurację, chcemy dodać do niej nowy obiekt Rating
. W tym zadaniu użyjemy podkolekcji. Kolekcję podrzędną można traktować jako kolekcję dołączoną do dokumentu. Każdy dokument restauracji będzie zawierał podkolekcją ocen z dokumentami oceny. Podzbiory ułatwiają porządkowanie danych bez nadmiernego rozrastania się dokumentów czy konieczności tworzenia skomplikowanych zapytań.
Aby uzyskać dostęp do podkolekcji, wywołaj funkcję .collection()
w dokumencie nadrzędnym:
val subRef = firestore.collection("restaurants")
.document("abc123")
.collection("ratings")
Możesz uzyskać dostęp do podkolekcji i wysłać zapytanie do niej tak samo jak do kolekcji najwyższego poziomu. Nie ma żadnych ograniczeń rozmiaru ani zmian w skuteczności. Więcej informacji o modelu danych Firestore znajdziesz tutaj.
Zapisywanie danych w transakcji
Dodanie Rating
do odpowiedniej podzbiory wymaga tylko wywołania .add()
, ale musimy też zaktualizować średnią ocen i liczbę ocen obiektu Restaurant
, aby odzwierciedlić nowe dane. Jeśli użyjemy oddzielnych operacji do wprowadzenia tych 2 zmian, może to spowodować wystąpienie kilku warunków wyścigu, które mogą skutkować nieaktualnymi lub nieprawidłowymi danymi.
Aby mieć pewność, że oceny są dodawane prawidłowo, użyjemy transakcji do dodania ocen restauracji. Ta transakcja wykona kilka działań:
- Sprawdź aktualną ocenę restauracji i oblicz nową.
- Dodawanie oceny do podkolekcji
- Zaktualizuj średnią ocenę i liczbę ocen restauracji
Otwórz RestaurantDetailFragment.kt
i wdróż funkcję 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
}
}
Funkcja addRating()
zwraca wartość Task
reprezentującą całą transakcję. Do zadania dodawane są detektory funkcji onRating()
, które reagują na wynik transakcji.
Ponownie uruchom aplikację i kliknij jedną z restauracji, aby wyświetlić ekran z informacjami o niej. Kliknij przycisk +, aby rozpocząć dodawanie opinii. Dodaj opinię, wybierając liczbę gwiazdek i wpisując tekst.
Kliknięcie Prześlij rozpocznie transakcję. Po zakończeniu transakcji Twoja opinia pojawi się poniżej, a liczba opinii o restauracji zostanie zaktualizowana:
Gratulacje! Masz teraz aplikację mobilną z opiniami o restauracjach, która wykorzystuje Cloud Firestore. Podobno są teraz bardzo popularne.
10. Bezpieczeństwo danych
Do tej pory nie zbadaliśmy bezpieczeństwa tej aplikacji. Skąd wiemy, że użytkownicy mogą tylko odczytywać i zapisywać prawidłowe dane? Bazy danych Firestore są chronione przez plik konfiguracji o nazwie Reguły zabezpieczeń.
Otwórz plik firestore.rules
i zastąp jego zawartość tym kodem:
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;
}
}
}
}
Te reguły ograniczają dostęp, aby zapewnić, że klienci wprowadzają tylko bezpieczne zmiany. Na przykład aktualizacje dokumentu restauracji mogą dotyczyć tylko ocen, a nie nazwy ani innych danych, których nie można zmienić. Oceny mogą być tworzone tylko wtedy, gdy identyfikator użytkownika zgadza się z zalogowanym użytkownikiem, co zapobiega podszywanie się pod inną osobę.
Więcej informacji o regułach zabezpieczeń znajdziesz w dokumentacji.
11. Podsumowanie
Utworzyłeś/utworzyłaś w Firestore w pełni funkcjonalną aplikację. Poznasz najważniejsze funkcje Firestore, w tym:
- Dokumenty i kolekcje
- Odczytywanie i zapisywanie danych
- Sortowanie i filtrowanie za pomocą zapytań
- Podkolekcje
- Transakcje
Więcej informacji
Aby dowiedzieć się więcej o Firestore, zapoznaj się z tymi materiałami:
Aplikacja restauracji w tym samouczku została oparta na przykładowej aplikacji „Friendly Eats”. Kod źródłowy tej aplikacji znajdziesz tutaj.
Opcjonalnie: wdróż w gałęzi produkcyjnej
Do tej pory aplikacja korzystała tylko z pakietu emulatorów Firebase. Jeśli chcesz dowiedzieć się, jak wdrożyć tę aplikację do prawdziwego projektu Firebase, przejdź do następnego kroku.
12. (Opcjonalnie) Wdróż aplikację
Dotychczas ta aplikacja była całkowicie lokalna, a wszystkie dane były przechowywane w Pakiecie emulatorów Firebase. W tej sekcji dowiesz się, jak skonfigurować projekt Firebase, aby aplikacja działała w produkcji.
Uwierzytelnianie Firebase
W konsoli Firebase otwórz sekcję Uwierzytelnianie i kliknij Rozpocznij. Otwórz kartę Metoda logowania i w sekcji Natywni dostawcy wybierz opcję E-mail/hasło.
Włącz metodę logowania Adres e-mail/hasło i kliknij Zapisz.
Firestore
Utwórz bazę danych
Otwórz w konsoli sekcję Baza danych Firestore i kliknij Utwórz bazę danych:
- Gdy pojawi się pytanie o reguły bezpieczeństwa, wybierz Tryb produkcyjny. Wkrótce zaktualizujemy te reguły.
- Wybierz lokalizację bazy danych, której chcesz używać w aplikacji. Pamiętaj, że wybranie lokalizacji bazy danych jest trwałą decyzją, a aby ją zmienić, musisz utworzyć nowy projekt. Więcej informacji o wybieraniu lokalizacji projektu znajdziesz w dokumentacji.
Reguły wdrażania
Aby wdrożyć wcześniej napisane reguły bezpieczeństwa, uruchom w katalogu codelab to polecenie:
$ firebase deploy --only firestore:rules
Spowoduje to wdrożenie zawartości pliku firestore.rules
do projektu. Możesz to sprawdzić na karcie Reguły w konsoli.
Wdrażanie indeksów
Aplikacja FriendlyEats ma złożone sortowanie i filtrowanie, które wymaga wielu niestandardowych indeksów złożonych. Można je tworzyć ręcznie w konsoli Firebase, ale łatwiej jest wpisać ich definicje w pliku firestore.indexes.json
i wdrażać je za pomocą interfejsu wiersza poleceń Firebase.
Po otwarciu pliku firestore.indexes.json
zobaczysz, że wymagane indeksy zostały już przesłane:
{
"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": []
}
Aby wdrożyć te indeksy, uruchom to polecenie:
$ firebase deploy --only firestore:indexes
Pamiętaj, że tworzenie indeksu nie jest procesem natychmiastowym. Możesz jednak śledzić jego postępy w konsoli Firebase.
Konfigurowanie aplikacji
W plikach util/FirestoreInitializer.kt
i util/AuthInitializer.kt
skonfigurowaliśmy pakiet SDK Firebase tak, aby łączył się z emulatorami w trybie debugowania:
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
}
Jeśli chcesz przetestować aplikację w prawdziwym projekcie Firebase, możesz:
- Kompiluj aplikację w trybie wersji i uruchamiaj ją na urządzeniu.
- Tymczasowo zastąp
BuildConfig.DEBUG
wartościąfalse
i ponownie uruchom aplikację.
Pamiętaj, że aby prawidłowo połączyć się z wersją produkcyjną, musisz wylogować się z aplikacji i ponownie się zalogować.