1. Przegląd
Cele
Podczas tych zajęć z programowania zbudujesz aplikację rekomendującą restauracje na Androida wspieraną przez Cloud Firestore. Dowiesz się jak:
- Odczytuj i zapisuj dane w Firestore z aplikacji na Androida
- Słuchaj zmian w danych Firestore w czasie rzeczywistym
- Użyj uwierzytelniania Firebase i reguł bezpieczeństwa, aby zabezpieczyć dane Firestore
- Pisz złożone zapytania Firestore
Warunki wstępne
Przed rozpoczęciem tych ćwiczeń z kodowania upewnij się, że masz:
- Android Studio Flamingo lub nowszy
- Emulator Androida z API 19 lub nowszym
- Wersja Node.js 16 lub nowsza
- Wersja Java 17 lub nowsza
2. Utwórz projekt Firebase
- Zaloguj się do konsoli Firebase za pomocą swojego konta Google.
- W konsoli Firebase kliknij Dodaj projekt .
- Jak pokazano na zrzucie ekranu poniżej, wprowadź nazwę swojego projektu Firebase (na przykład „Przyjazne jedzenie”) i kliknij Kontynuuj .
- Możesz zostać poproszony o włączenie Google Analytics, dla celów tego ćwiczenia z programowania Twój wybór nie ma znaczenia.
- Po około minucie Twój projekt Firebase będzie gotowy. Kliknij Kontynuuj .
3. Skonfiguruj przykładowy projekt
Pobierz kod
Uruchom następujące polecenie, aby sklonować przykładowy kod dla tego ćwiczenia z programowania. Spowoduje to utworzenie na twoim komputerze folderu o nazwie friendlyeats-android
:
$ git clone https://github.com/firebase/friendlyeats-android
Jeśli nie masz gita na swoim komputerze, możesz także pobrać kod bezpośrednio z GitHuba.
Dodaj konfigurację Firebase
- W konsoli Firebase wybierz Przegląd projektu w lewym panelu nawigacyjnym. Kliknij przycisk Android , aby wybrać platformę. Po wyświetleniu monitu o nazwę pakietu użyj
com.google.firebase.example.fireeats
- Kliknij opcję Zarejestruj aplikację i postępuj zgodnie z instrukcjami, aby pobrać plik
google-services.json
i przenieść go doapp/
folderu z właśnie pobranym kodem. Następnie kliknij Dalej .
Zaimportuj projekt
Otwórz Studio Androida. Kliknij opcję Plik > Nowy > Importuj projekt i wybierz folder Friendlyeats-Android .
4. Skonfiguruj emulatory Firebase
Podczas tych zajęć z programowania będziesz używać pakietu Firebase Emulator Suite do lokalnej emulacji Cloud Firestore i innych usług Firebase. Zapewnia to bezpieczne, szybkie i bezpłatne lokalne środowisko programistyczne do tworzenia aplikacji.
Zainstaluj interfejs wiersza polecenia Firebase
Najpierw musisz zainstalować Firebase CLI . Jeśli używasz systemu macOS lub Linux, możesz uruchomić następujące polecenie cURL:
curl -sL https://firebase.tools | bash
Jeśli używasz systemu Windows, przeczytaj instrukcje instalacji , aby uzyskać samodzielny plik binarny lub zainstalować przez npm
.
Po zainstalowaniu interfejsu CLI uruchomienie firebase --version
powinno zgłosić wersję 9.0.0
lub wyższą:
$ firebase --version 9.0.0
Zaloguj sie
Uruchom firebase login
, aby połączyć interfejs CLI ze swoim kontem Google. Spowoduje to otwarcie nowego okna przeglądarki w celu zakończenia procesu logowania. Pamiętaj, aby wybrać to samo konto, którego użyłeś wcześniej podczas tworzenia projektu Firebase.
Połącz swój projekt
Z folderu friendlyeats-android
uruchom firebase use --add
, aby połączyć swój lokalny projekt z projektem Firebase. Postępuj zgodnie z instrukcjami, aby wybrać wcześniej utworzony projekt i jeśli zostaniesz poproszony o wybranie aliasu, wprowadź default
.
5. Uruchom aplikację
Nadszedł czas, aby po raz pierwszy uruchomić pakiet Firebase Emulator Suite i aplikację FriendlyEats na Androida.
Uruchom emulatory
Na swoim terminalu z katalogu friendlyeats-android
uruchom firebase emulators:start
, aby uruchomić emulatory Firebase. Powinieneś zobaczyć takie logi:
$ 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.
Masz teraz kompletne lokalne środowisko programistyczne działające na swoim komputerze! Pamiętaj, aby pozostawić to polecenie uruchomione do końca ćwiczeń z kodowania. Twoja aplikacja na Androida będzie musiała połączyć się z emulatorami.
Połącz aplikację z emulatorami
Otwórz pliki util/FirestoreInitializer.kt
i util/AuthInitializer.kt
w Android Studio. Pliki te zawierają logikę umożliwiającą połączenie zestawów SDK Firebase z lokalnymi emulatorami działającymi na komputerze po uruchomieniu aplikacji.
W metodzie create()
klasy FirestoreInitializer
przeanalizuj 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
. Kiedy kompilujemy aplikację w trybie release
, warunek ten będzie fałszywy.
Widzimy, że używa metody useEmulator(host, port)
do połączenia zestawu SDK Firebase z lokalnym emulatorem Firestore. W całej aplikacji będziemy używać FirebaseUtil.getFirestore()
, aby uzyskać dostęp do tej instancji FirebaseFirestore
, dzięki czemu mamy pewność, że zawsze łączymy się z emulatorem Firestore podczas działania w trybie debug
.
Uruchom aplikację
Jeśli poprawnie dodałeś plik google-services.json
, projekt powinien się teraz skompilować. W Android Studio kliknij Kompiluj > Odbuduj projekt i upewnij się, że nie ma pozostałych błędów.
W Android Studio Uruchom aplikację na emulatorze Androida. Na początku zostanie wyświetlony ekran „Zaloguj się”. Aby zalogować się do 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 poświadczenia.
Teraz otwórz interfejs emulatorów, przechodząc do http://localhost:4000 w przeglądarce internetowej. Następnie kliknij zakładkę Uwierzytelnianie i powinieneś zobaczyć właśnie utworzone konto:
Po zakończeniu procesu logowania powinieneś zobaczyć ekran główny aplikacji:
Wkrótce dodamy trochę danych do wypełnienia ekranu głównego.
6. Zapisz dane w Firestore
W tej sekcji zapiszemy trochę danych w Firestore, abyśmy mogli zapełnić aktualnie pusty ekran główny.
Głównym obiektem modelowym 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"
. Aby dowiedzieć się więcej o modelu danych Firestore, przeczytaj o dokumentach i zbiorach w dokumentacji .
W celach demonstracyjnych dodamy do aplikacji funkcję tworzenia dziesięciu losowych restauracji po kliknięciu przycisku „Dodaj losowe elementy” w rozszerzonym menu. Otwórz plik MainFragment.kt
i zamień zawartość metody onAddItemsClicked()
na:
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)
}
}
Jest kilka ważnych rzeczy, na które warto zwrócić uwagę w związku z powyższym kodem:
- Zaczęliśmy od uzyskania odniesienia do kolekcji
"restaurants"
. Kolekcje tworzone są domyślnie podczas dodawania dokumentów, więc nie było potrzeby tworzenia kolekcji przed zapisaniem danych. - Dokumenty można tworzyć przy użyciu klas danych Kotlin, których używamy do tworzenia każdego dokumentu Restauracji.
- Metoda
add()
dodaje do kolekcji dokument z automatycznie wygenerowanym identyfikatorem, dzięki czemu nie musieliśmy podawać unikalnego identyfikatora dla każdej Restauracji.
Teraz uruchom aplikację ponownie i kliknij przycisk „Dodaj losowe elementy” w rozszerzonym menu (w prawym górnym rogu), aby wywołać właśnie napisany kod:
Teraz otwórz interfejs emulatorów, przechodząc do http://localhost:4000 w przeglądarce internetowej. Następnie kliknij kartę Firestore i powinieneś zobaczyć właśnie dodane dane:
Dane te są w 100% lokalne dla Twojej maszyny. Tak naprawdę twój prawdziwy projekt nie zawiera jeszcze bazy danych Firestore! Oznacza to, że można bezpiecznie eksperymentować z modyfikowaniem i usuwaniem tych danych bez konsekwencji.
Gratulacje, właśnie zapisałeś dane do Firestore! W kolejnym kroku dowiemy się jak wyświetlić te dane w aplikacji.
7. Wyświetl dane z Firestore
W tym kroku dowiemy się, jak odzyskać dane z Firestore i wyświetlić je w naszej aplikacji. Pierwszym krokiem do odczytania danych z Firestore jest utworzenie Query
. Otwórz plik MainFragment.kt
i dodaj następujący 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 odsłuchać zapytanie, abyśmy otrzymali wszystkie pasujące dokumenty i byli powiadamiani o przyszłych aktualizacjach w czasie rzeczywistym. Ponieważ naszym ostatecznym celem jest powiązanie tych danych z RecyclerView
, musimy utworzyć klasę RecyclerView.Adapter
, aby nasłuchiwać danych.
Otwórz klasę FirestoreAdapter
, która została już częściowo zaimplementowana. Najpierw zaimplementujmy w adapterze EventListener
i zdefiniujmy funkcję onEvent
, aby mogła odbierać 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()
}
// ...
}
Przy początkowym ładowaniu słuchacz otrzyma jedno zdarzenie ADDED
dla każdego nowego dokumentu. W miarę jak zestaw wyników zapytania będzie się zmieniał w czasie, słuchacz otrzyma więcej zdarzeń zawierających zmiany. Teraz dokończmy implementację słuchacza. Najpierw dodaj trzy 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 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ć słuchacza:
fun startListening() {
if (registration == null) {
registration = query.addSnapshotListener(this)
}
}
Teraz aplikacja jest w pełni skonfigurowana do odczytu danych z Firestore. Uruchom aplikację ponownie i powinieneś zobaczyć restauracje dodane w poprzednim kroku:
Teraz wróć do interfejsu emulatora w przeglądarce i edytuj jedną z nazw restauracji. Powinieneś zobaczyć zmianę w aplikacji niemal natychmiast!
8. Sortuj i filtruj dane
Aplikacja wyświetla obecnie najwyżej oceniane restauracje z całej kolekcji, ale w prawdziwej aplikacji restauracyjnej użytkownik chciałby sortować i filtrować dane. Na przykład aplikacja powinna wyświetlać „Najlepsze restauracje serwujące owoce morza w Filadelfii” lub „Najtańszą pizzę”.
Kliknięcie białego paska u góry aplikacji powoduje wyświetlenie okna dialogowego filtrów. W tej sekcji użyjemy zapytań Firestore, aby to okno dialogowe działało:
Zmodyfikujmy metodę onFilter()
pliku MainFragment.kt
. Ta metoda akceptuje obiekt Filters
, który jest obiektem pomocniczym, który utworzyliśmy w celu przechwytywania danych wyjściowych okna dialogowego filtrów. Zmienimy tę metodę, aby skonstruować zapytanie z 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 budujemy obiekt Query
, dołączając klauzule where
i orderBy
, aby dopasować je do podanych filtrów.
Uruchom aplikację ponownie i wybierz następujący filtr, aby wyświetlić najpopularniejsze tanie restauracje:
Powinieneś teraz zobaczyć przefiltrowaną listę restauracji zawierającą tylko opcje o niskiej cenie:
Jeśli dotarłeś tak daleko, stworzyłeś w pełni funkcjonalną aplikację do przeglądania rekomendacji restauracji w Firestore! Możesz teraz sortować i filtrować restauracje w czasie rzeczywistym. W kolejnych rozdziałach dodamy recenzje restauracji i dodamy zasady bezpieczeństwa do aplikacji.
9. Organizuj dane w podkolekcjach
W tej sekcji dodamy oceny do aplikacji, aby użytkownicy mogli oceniać swoje ulubione (lub najmniej ulubione) restauracje.
Kolekcje i podzbiory
Do tej pory wszystkie dane dotyczące restauracji przechowywaliśmy w zbiorze najwyższego poziomu o nazwie „restauracje”. Kiedy użytkownik ocenia restaurację, chcemy dodać do niej nowy obiekt Rating
. Do tego zadania użyjemy podkolekcji. Można myśleć o podkolekcji jako o kolekcji dołączonej do dokumentu. Zatem każdy dokument restauracji będzie miał podkolekcję ocen pełną dokumentów ocen. Podkolekcje pomagają organizować dane bez obciążania dokumentów i konieczności stosowania 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 uzyskiwać dostęp do podkolekcji i wysyłać do niej zapytania, tak jak w przypadku kolekcji najwyższego poziomu, nie ma żadnych ograniczeń dotyczących rozmiaru ani zmian wydajności. Więcej o modelu danych Firestore możesz przeczytać tutaj .
Zapisywanie danych w transakcji
Dodanie Rating
do odpowiedniej podkolekcji wymaga jedynie wywołania metody .add()
, ale musimy także zaktualizować średnią ocenę i liczbę ocen obiektu Restaurant
, aby odzwierciedlały nowe dane. Jeśli do wprowadzenia tych dwóch zmian użyjemy oddzielnych operacji, istnieje wiele sytuacji wyścigu, które mogą skutkować nieaktualnymi lub nieprawidłowymi danymi.
Aby mieć pewność, że oceny zostaną dodane prawidłowo, wykorzystamy transakcję w celu dodania ocen do restauracji. Ta transakcja wykona kilka działań:
- Przeczytaj aktualną ocenę restauracji i oblicz nową
- Dodaj ocenę do podkolekcji
- Zaktualizuj średnią ocenę i liczbę ocen restauracji
Otwórz RestaurantDetailFragment.kt
i zaimplementuj 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ące całą transakcję. W funkcji onRating()
do zadania dodawane są słuchacze, którzy mają odpowiedzieć na wynik transakcji.
Teraz uruchom aplikację ponownie i kliknij jedną z restauracji, co powinno wyświetlić ekran szczegółów restauracji. Kliknij przycisk + , aby rozpocząć dodawanie recenzji. Dodaj recenzję, wybierając liczbę gwiazdek i wpisując tekst.
Naciśnięcie przycisku Wyślij rozpocznie transakcję. Po zakończeniu transakcji zobaczysz poniżej swoją recenzję i aktualizację liczby recenzji restauracji:
Gratulacje! Masz teraz społecznościową, lokalną i mobilną aplikację do recenzowania restauracji zbudowaną na platformie Cloud Firestore. Słyszałem, że są one obecnie bardzo popularne.
10. Zabezpiecz swoje dane
Jak dotąd nie rozważaliśmy bezpieczeństwa tej aplikacji. Skąd wiemy, że użytkownicy mogą tylko czytać i zapisywać prawidłowe własne dane? Bazy danych Firestore są zabezpieczone plikiem konfiguracyjnym o nazwie Reguły bezpieczeństwa .
Otwórz plik firestore.rules
. Powinieneś zobaczyć następujące informacje:
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;
}
}
}
Zmieńmy te reguły, aby zapobiec niepożądanemu dostępowi do danych lub zmianom, otwórz plik firestore.rules
i zamień zawartość na następującą:
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;
}
}
}
}
Reguły te ograniczają dostęp, aby zapewnić, że klienci będą wprowadzać tylko bezpieczne zmiany. Na przykład aktualizacje dokumentu restauracji mogą zmienić jedynie oceny, a nie nazwę lub inne niezmienne dane. Oceny można tworzyć tylko wtedy, gdy identyfikator użytkownika jest zgodny z identyfikatorem zalogowanego użytkownika, co zapobiega podszywaniu się.
Aby przeczytać więcej na temat Reguł Bezpieczeństwa, odwiedź dokumentację .
11. Wniosek
Utworzyłeś teraz w pełni funkcjonalną aplikację na Firestore. Poznałeś najważniejsze funkcje Firestore, w tym:
- Dokumenty i zbiory
- Odczyt i zapis danych
- Sortowanie i filtrowanie za pomocą zapytań
- Podkolekcje
- Transakcje
Ucz się więcej
Aby dalej uczyć się o Firestore, oto kilka dobrych miejsc, od których możesz zacząć:
Aplikacja restauracyjna w tym laboratorium została oparta na przykładowej aplikacji „Friendly Eats”. Tutaj możesz przeglądać kod źródłowy tej aplikacji.
Opcjonalnie: wdrożenie w środowisku produkcyjnym
Do tej pory ta aplikacja korzystała tylko z pakietu emulatorów Firebase. Jeśli chcesz dowiedzieć się, jak wdrożyć tę aplikację w prawdziwym projekcie Firebase, przejdź do następnego kroku.
12. (Opcjonalnie) Wdróż aplikację
Jak dotąd ta aplikacja była całkowicie lokalna, wszystkie dane znajdują się w pakiecie Firebase Emulator Suite. W tej sekcji dowiesz się, jak skonfigurować projekt Firebase, aby ta aplikacja działała w środowisku produkcyjnym.
Uwierzytelnianie Firebase
W konsoli Firebase przejdź do sekcji Uwierzytelnianie i kliknij Rozpocznij . Przejdź do karty Metoda logowania i wybierz opcję E-mail/hasło od dostawców natywnych .
Włącz metodę logowania za pomocą adresu e-mail/hasła i kliknij przycisk Zapisz .
Sklep z ogniem
Utwórz bazę danych
Przejdź do sekcji Baza danych Firestore w konsoli i kliknij Utwórz bazę danych :
- Po wyświetleniu monitu o reguły bezpieczeństwa wybierz opcję uruchomienia w trybie produkcyjnym , wkrótce zaktualizujemy te reguły.
- Wybierz lokalizację bazy danych, której chcesz używać w swojej aplikacji. Należy pamiętać, że wybór lokalizacji bazy danych jest decyzją stałą i aby ją zmienić, konieczne będzie utworzenie nowego projektu. Więcej informacji na temat wyboru lokalizacji projektu znajdziesz w dokumentacji .
Wdrażaj reguły
Aby wdrożyć reguły zabezpieczeń, które napisałeś wcześniej, uruchom następującą komendę w katalogu codelab:
$ firebase deploy --only firestore:rules
Spowoduje to wdrożenie zawartości firestore.rules
w Twoim projekcie, co możesz potwierdzić, przechodząc do karty Reguły w konsoli.
Wdrażaj indeksy
Aplikacja FriendlyEats umożliwia złożone sortowanie i filtrowanie, co wymaga szeregu niestandardowych indeksów złożonych. Można je utworzyć ręcznie w konsoli Firebase, ale łatwiej jest zapisać ich definicje w pliku firestore.indexes.json
i wdrożyć je za pomocą interfejsu wiersza polecenia Firebase.
Jeśli otworzysz plik firestore.indexes.json
, zobaczysz, że wymagane indeksy zostały już dostarczone:
{
"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 następującą komendę:
$ firebase deploy --only firestore:indexes
Pamiętaj, że tworzenie indeksu nie jest natychmiastowe, możesz monitorować postęp w konsoli Firebase.
Skonfiguruj aplikację
W plikach util/FirestoreInitializer.kt
i util/AuthInitializer.kt
skonfigurowaliśmy zestaw 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ć swoją aplikację w prawdziwym projekcie Firebase, możesz:
- Zbuduj aplikację w trybie wydania i uruchom ją na urządzeniu.
- Tymczasowo zastąp
BuildConfig.DEBUG
wartościąfalse
i uruchom aplikację ponownie.
Pamiętaj, że w celu prawidłowego połączenia z wersją produkcyjną może być konieczne wylogowanie się z aplikacji i zalogowanie się ponownie.