1. Przegląd
Cele
W tym ćwiczeniu z programowania utworzysz aplikację na Androida do rekomendowania restauracji, która będzie korzystać z Cloud Firestore. Zapoznasz się z tymi zagadnieniami:
- Odczytywanie i zapisywanie danych w Firestore z aplikacji na Androida
- Nasłuchiwanie zmian w danych Firestore w czasie rzeczywistym
- Zabezpieczanie danych Firestore za pomocą uwierzytelniania Firebase i reguł zabezpieczeń
- Pisanie złożonych zapytań do Firestore
Wymagania wstępne
Zanim zaczniesz, upewnij się, że masz:
- Android Studio Flamingo lub nowszy
- emulator 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, korzystając ze swojego konta Google.
- Kliknij przycisk, aby utworzyć nowy projekt, a potem wpisz jego nazwę (np.
FriendlyEats
).
- Kliknij Dalej.
- Po wyświetleniu monitu przeczytaj i zaakceptuj warunki usługi Firebase, a potem kliknij Dalej.
- (Opcjonalnie) Włącz w konsoli Firebase pomoc AI (nazywaną „Gemini w Firebase”).
- W tym samouczku nie potrzebujesz Google Analytics, więc wyłącz opcję Google Analytics.
- Kliknij Utwórz projekt, poczekaj, aż projekt zostanie udostępniony, a następnie kliknij Dalej.
3. Konfigurowanie przykładowego projektu
Pobieranie kodu
Aby skopiować przykładowy kod do tego laboratorium, 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 na komputerze narzędzia git, możesz też pobrać kod bezpośrednio z GitHub.
Dodawanie konfiguracji Firebase
- W konsoli Firebase w menu po lewej stronie wybierz Przegląd projektu. Kliknij przycisk Android, aby wybrać platformę. Gdy pojawi się prośba o podanie nazwy pakietu, użyj
com.google.firebase.example.fireeats
- Kliknij Zarejestruj aplikację i wykonaj instrukcje, aby pobrać plik
google-services.json
, a następnie przenieść go do folderuapp/
w pobranym przed chwilą kodzie. 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 kodowania użyjesz Pakietu emulatorów Firebase do lokalnego emulowania Cloud Firestore i innych usług Firebase. Zapewnia to bezpieczne, szybkie i bezpłatne środowisko programistyczne do tworzenia aplikacji.
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 uzyskać samodzielny plik binarny lub zainstalować go za pomocą npm
.
Po zainstalowaniu interfejsu CLI uruchomienie polecenia firebase --version
powinno zwrócić wersję 9.0.0
lub nowszą:
$ firebase --version 9.0.0
Zaloguj się
Uruchom firebase login
, aby połączyć interfejs CLI z kontem Google. Otworzy się nowe okno przeglądarki, w którym dokończysz proces logowania. Pamiętaj, aby wybrać to samo konto, którego użyto wcześniej do utworzenia 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 możesz po raz pierwszy uruchomić Pakiet emulatorów Firebase i aplikację na Androida FriendlyEats.
Uruchamianie emulatorów
W terminalu w katalogu friendlyeats-android
uruchom polecenie firebase emulators:start
, aby uruchomić emulatory Firebase. Powinny pojawić się dzienniki podobne do tych:
$ 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 Twoim komputerze działa teraz kompletne lokalne środowisko programistyczne. Pozostaw to polecenie uruchomione na czas trwania całego laboratorium, ponieważ aplikacja na Androida będzie musiała łą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 po uruchomieniu aplikacji łączy pakiety SDK Firebase z lokalnymi emulatorami działającymi na Twoim komputerze.
W create()
metody 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 nasza aplikacja działa w trybie debug
. Gdy skompilujemy aplikację w trybie release
, ten warunek będzie fałszywy.
Widzimy, że do połączenia pakietu SDK Firebase z lokalnym emulatorem Firestore używa metody useEmulator(host, port)
. W całej aplikacji będziemy używać FirebaseUtil.getFirestore()
, aby uzyskać dostęp do tej instancji FirebaseFirestore
. Dzięki temu będziemy mieć pewność, że podczas działania w trybie debug
zawsze łączymy się z emulatorem Firestore.
Uruchamianie aplikacji
Jeśli plik google-services.json
został dodany prawidłowo, projekt powinien się teraz skompilować. W Android Studio kliknij Build (Skompiluj) > Rebuild Project (Skompiluj projekt ponownie) i sprawdź, czy nie ma już żadnych błędów.
W Android Studio uruchom aplikację w emulatorze Androida. Najpierw zobaczysz ekran „Zaloguj się”. 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.
Otwórz interfejs emulatorów, wpisując w przeglądarce adres http://localhost:4000. Następnie kliknij kartę Authentication (Uwierzytelnianie). Powinno się wyświetlić utworzone przez Ciebie konto:
Po zakończeniu procesu logowania powinien pojawić się ekran główny aplikacji:
Wkrótce dodamy dane, które wypełnią ekran główny.
6. Zapisywanie danych w Firestore
W tej sekcji zapiszemy w Firestore dane, aby wypełnić obecnie 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żda restauracja będzie przechowywana jako dokument w kolekcji najwyższego poziomu o nazwie "restaurants"
. Więcej informacji o modelu danych Firestore znajdziesz w dokumentacji.
Na potrzeby demonstracji dodamy w aplikacji funkcję tworzenia 10 losowych restauracji po kliknięciu przycisku „Dodaj losowe elementy” w menu dodatkowym. Otwórz plik MainFragment.kt
i zastąp zawartość metody onAddItemsClicked()
tym kodem:
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)
}
}
Oto kilka ważnych uwag dotyczących powyższego kodu:
- Zaczęliśmy od uzyskania odwołania do
"restaurants"
kolekcji. Kolekcje są tworzone niejawnie 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 określać unikalnego identyfikatora dla każdej restauracji.
Uruchom ponownie aplikację i kliknij przycisk „Add Random Items” (Dodaj losowe elementy) w menu rozwijanym (w prawym górnym rogu), aby wywołać napisany przed chwilą kod:
Otwórz interfejs emulatorów, wpisując w przeglądarce adres http://localhost:4000. Następnie kliknij kartę Firestore. Powinny się na niej pojawić dodane przed chwilą dane:
Te dane są w 100% lokalne na Twoim urządzeniu. W rzeczywistym projekcie nie ma jeszcze bazy danych Firestore. Oznacza to, że możesz bez obaw eksperymentować z modyfikowaniem i usuwaniem tych danych.
Gratulacje! Właśnie udało Ci się zapisać dane w 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 odczytywania danych z Firestore jest utworzenie Query
. Otwórz plik MainFragment.kt
i dodaj ten kod na początku metody onViewCreated()
:
// Firestore
firestore = Firebase.firestore
// Get the 50 highest rated restaurants
query = firestore.collection("restaurants")
.orderBy("avgRating", Query.Direction.DESCENDING)
.limit(LIMIT.toLong())
Teraz chcemy posłuchać zapytania, aby uzyskać wszystkie pasujące dokumenty i otrzymywać powiadomienia o przyszłych aktualizacjach w czasie rzeczywistym. Ponieważ naszym ostatecznym celem jest powiązanie tych danych z RecyclerView
, musimy utworzyć klasę RecyclerView.Adapter
, która będzie nasłuchiwać danych.
Otwórz klasę FirestoreAdapter
, która została już częściowo zaimplementowana. Najpierw sprawimy, że adapter będzie implementować interfejs EventListener
, i zdefiniujemy funkcję onEvent
, 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 detektor otrzyma 1 zdarzenie ADDED
dla każdego nowego dokumentu. W miarę jak zbiór wyników zapytania zmienia się z czasem, detektor będzie otrzymywać więcej zdarzeń zawierających te zmiany. Teraz dokończmy implementację odbiornika. 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ć detektor:
fun startListening() {
if (registration == null) {
registration = query.addSnapshotListener(this)
}
}
Aplikacja jest teraz w pełni skonfigurowana do odczytywania danych z Firestore. Uruchom ponownie aplikację. Powinny być widoczne restauracje dodane w poprzednim kroku:
Teraz wróć do interfejsu emulatora w przeglądarce i edytuj jedną z nazw restauracji. Zmiana powinna być widoczna w aplikacji niemal natychmiast.
8. Sortowanie i filtrowanie danych
Obecnie aplikacja wyświetla najlepiej oceniane restauracje z całej kolekcji, ale w prawdziwej aplikacji użytkownik chciałby sortować i filtrować dane. Na przykład aplikacja powinna być w stanie wyświetlić „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 to okno działało:
Edytujmy onFilter()
MainFragment.kt
. Ta metoda przyjmuje obiekt Filters
, który jest obiektem pomocniczym utworzonym przez nas w celu przechwytywania danych wyjściowych okna 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 powyższym fragmencie kodu tworzymy obiekt Query
, dołączając klauzule where
i orderBy
, aby dopasować je do podanych filtrów.
Uruchom ponownie aplikację i wybierz ten filtr, aby wyświetlić najpopularniejsze restauracje w niskich cenach:
Powinna się teraz wyświetlić przefiltrowana lista restauracji zawierająca tylko opcje w niskich cenach:
Jeśli udało Ci się dotrzeć do tego miejsca, oznacza to, że masz już w Firestore w pełni funkcjonalną aplikację do wyświetlania rekomendacji restauracji. Możesz teraz 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 podzbiorach
W tej sekcji dodamy oceny aplikacji, aby użytkownicy mogli oceniać swoje ulubione (lub najmniej ulubione) restauracje.
Kolekcje i podkolekcje
Do tej pory wszystkie dane restauracji były przechowywane w kolekcji najwyższego poziomu o nazwie „restaurants”. Gdy użytkownik oceni restaurację, chcemy dodać do niej nowy obiekt Rating
. W tym zadaniu użyjemy podzbioru. Podkolekcję można traktować jako kolekcję dołączoną do dokumentu. Każdy dokument restauracji będzie więc zawierać podkolekcję ocen z dokumentami ocen. Podzbiory pomagają porządkować dane bez powiększania dokumentów i bez konieczności wykonywania złożonych zapytań.
Aby uzyskać dostęp do podzbioru, wywołaj .collection()
w dokumencie nadrzędnym:
val subRef = firestore.collection("restaurants")
.document("abc123")
.collection("ratings")
Dostęp do podkolekcji i wysyłanie do niej zapytań jest takie samo jak w przypadku kolekcji najwyższego poziomu. Nie ma ograniczeń rozmiaru ani zmian wydajności. Więcej informacji o modelu danych Firestore znajdziesz tutaj.
Zapisywanie danych w transakcji
Dodanie elementu Rating
do odpowiedniej podkolekcji wymaga tylko wywołania funkcji .add()
, ale musimy też zaktualizować średnią ocenę i liczbę ocen obiektu Restaurant
, aby odzwierciedlały nowe dane. Jeśli do wprowadzenia tych 2 zmian użyjemy osobnych operacji, może dojść do wielu sytuacji wyścigu, które spowodują, że dane będą nieaktualne lub nieprawidłowe.
Aby mieć pewność, że oceny są dodawane prawidłowo, użyjemy transakcji do dodania ocen do restauracji. Ta transakcja wykona kilka działań:
- Odczytywanie obecnej oceny restauracji i obliczanie nowej oceny.
- Dodawanie oceny do podkolekcji
- Aktualizowanie średniej oceny restauracji i liczby ocen
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 Task
reprezentujący całą transakcję. W funkcji onRating()
do zadania dodawane są detektory, które reagują na wynik transakcji.
Teraz ponownie uruchom aplikację i kliknij jedną z restauracji. Powinien pojawić się 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 spowoduje rozpoczęcie transakcji. Po zakończeniu transakcji Twoja opinia pojawi się poniżej, a liczba opinii o restauracji zostanie zaktualizowana:
Gratulacje! Masz już aplikację do recenzowania restauracji, która jest oparta na Cloud Firestore i ma funkcje społecznościowe, lokalne i mobilne. Słyszałem, że są teraz bardzo popularne.
10. Zabezpieczanie danych
Do tej pory nie braliśmy pod uwagę bezpieczeństwa tej aplikacji. Skąd wiemy, że użytkownicy mogą tylko odczytywać i zapisywać odpowiednie dane własne? Bazy danych Firestore są zabezpieczone przez plik konfiguracyjny 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 klienci mogli wprowadzać tylko bezpieczne zmiany. Na przykład aktualizacje dokumentu restauracji mogą zmieniać tylko oceny, a nie nazwę ani inne niezmienne dane. Oceny można tworzyć tylko wtedy, gdy identyfikator użytkownika pasuje do zalogowanego użytkownika, co zapobiega podszywaniu się pod inne osoby.
Więcej informacji o regułach zabezpieczeń znajdziesz w dokumentacji.
11. Podsumowanie
Właśnie utworzono w Firestore w pełni funkcjonalną aplikację. Poznaliśmy najważniejsze funkcje Firestore, w tym:
- Dokumenty i kolekcje
- Odczytywanie i zapisywanie danych
- Sortowanie i filtrowanie za pomocą zapytań
- Podkolekcje
- Transakcje
Więcej informacji
Jeśli chcesz dowiedzieć się więcej o Firestore, zacznij od tych materiałów:
Aplikacja restauracji w tym laboratorium została oparta na przykładowej aplikacji „Friendly Eats”. Kod źródłowy tej aplikacji możesz przejrzeć tutaj.
Opcjonalnie: wdrażanie w wersji produkcyjnej
Do tej pory aplikacja korzystała tylko z pakietu emulatorów lokalnych Firebase. Jeśli chcesz dowiedzieć się, jak wdrożyć tę aplikację w prawdziwym projekcie Firebase, przejdź do następnego kroku.
12. (Opcjonalnie) Wdrażanie aplikacji
Dotychczas ta aplikacja działała w całości lokalnie, a wszystkie dane były przechowywane w Pakiecie emulatorów Firebase. W tej sekcji dowiesz się, jak skonfigurować projekt Firebase, aby ta aplikacja działała w środowisku produkcyjnym.
Uwierzytelnianie Firebase
W konsoli Firebase otwórz sekcję Uwierzytelnianie i kliknij Rozpocznij. Otwórz kartę Metoda logowania i w sekcji Dostawcy natywni 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 sekcję Baza danych Firestore w konsoli i kliknij Utwórz bazę danych:
- Gdy pojawi się prośba o wybranie reguł 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 wybór lokalizacji bazy danych jest trwały i aby go zmienić, musisz utworzyć nowy projekt. Więcej informacji o wyborze lokalizacji projektu znajdziesz w dokumentacji.
Reguły wdrażania
Aby wdrożyć napisane wcześniej reguły zabezpieczeń, uruchom w katalogu codelab to polecenie:
$ firebase deploy --only firestore:rules
Spowoduje to wdrożenie zawartości firestore.rules
w projekcie. Możesz to sprawdzić, otwierając kartę 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żesz je utworzyć ręcznie w konsoli Firebase, ale łatwiej jest napisać ich definicje w pliku firestore.indexes.json
i wdrożyć je za pomocą interfejsu wiersza poleceń Firebase.
Jeśli otworzysz plik firestore.indexes.json
, zobaczysz, że wymagane indeksy zostały już podane:
{
"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 natychmiastowe. Postępy możesz śledzić w konsoli Firebase.
Konfigurowanie aplikacji
W plikach util/FirestoreInitializer.kt
i util/AuthInitializer.kt
skonfigurowaliśmy pakiet SDK Firebase tak, aby w trybie debugowania łączył się z emulatorami:
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:
- Skompiluj aplikację w trybie wydania i uruchom ją na urządzeniu.
- Tymczasowo zastąp
BuildConfig.DEBUG
ciągiemfalse
i ponownie uruchom aplikację.
Aby prawidłowo połączyć się z wersją produkcyjną, może być konieczne wylogowanie się z aplikacji i ponowne zalogowanie.