1. סקירה כללית
מטרות עסקיות
בקודלאב הזה תלמדו ליצור אפליקציה להמלצות על מסעדות ל-Android שמבוססת על Cloud Firestore. תלמדו איך:
- קריאה וכתיבה של נתונים ב-Firestore מאפליקציית Android
- האזנה לשינויים בנתונים של Firestore בזמן אמת
- שימוש באימות ובכללי אבטחה של Firebase לאבטחת נתוני Firestore
- כתיבת שאילתות מורכבות ב-Firestore
דרישות מוקדמות
לפני שמתחילים את סדנת הקוד, צריך לוודא שיש לכם:
- Android Studio מגרסה Flamingo ואילך
- אמולטור Android עם API מגרסה 19 ואילך
- Node.js בגרסה 16 ואילך
- Java בגרסה 17 ואילך
2. יצירת פרויקט Firebase
- נכנסים למסוף Firebase באמצעות חשבון Google.
- במסוף Firebase, לוחצים על Add project (הוספת פרויקט).
- כפי שמוצג בצילום המסך שבהמשך, מזינים שם לפרויקט ב-Firebase (לדוגמה, 'Friendly Eats') ולוחצים על Continue (המשך).
- יכול להיות שתתבקשו להפעיל את Google Analytics. לצורכי הקודלאב הזה, הבחירה שלכם לא חשובה.
- אחרי דקה בערך, פרויקט Firebase יהיה מוכן. לוחצים על המשך.
3. הגדרת פרויקט לדוגמה
מורידים את הקוד
מריצים את הפקודה הבאה כדי לשכפל את קוד הדוגמה של סדנת הקוד הזו. הפקודה הזו תיצור במחשב תיקייה בשם friendlyeats-android
:
$ git clone https://github.com/firebase/friendlyeats-android
אם אין לכם את git במחשב, אתם יכולים גם להוריד את הקוד ישירות מ-GitHub.
הוספת הגדרות של Firebase
- במסוף Firebase, בוחרים באפשרות סקירה כללית של הפרויקט בתפריט הניווט הימני. לוחצים על הלחצן Android כדי לבחור את הפלטפורמה. כשמוצגת בקשה להזין שם חבילה, מזינים
com.google.firebase.example.fireeats
- לוחצים על רישום אפליקציה ופועלים לפי ההוראות כדי להוריד את הקובץ
google-services.json
ולהעביר אותו לתיקייהapp/
של הקוד שהורדתם. לאחר מכן לוחצים על Next.
מייבאים את הפרויקט
פותחים את Android Studio. לוחצים על קובץ > חדש > ייבוא פרויקט ובוחרים בתיקייה friendlyeats-android.
4. הגדרת אמולטורים של Firebase
ב-codelab הזה תשתמשו ב-Firebase Emulator Suite כדי לדמות באופן מקומי את Cloud Firestore ושירותי Firebase אחרים. כך תוכלו ליצור סביבה מקומית לפיתוח מהירה, בטוחה וללא עלות, שבה תוכלו לפתח את האפליקציה.
התקנת ה-CLI של Firebase
קודם כול צריך להתקין את Firebase CLI. אם אתם משתמשים ב-macOS או ב-Linux, אתם יכולים להריץ את פקודת ה-cURL הבאה:
curl -sL https://firebase.tools | bash
אם אתם משתמשים ב-Windows, כדאי לקרוא את הוראות ההתקנה כדי לקבל קובץ בינארי עצמאי או כדי להתקין דרך npm
.
אחרי שתתקינו את ה-CLI, הפעלת firebase --version
אמורה לדווח על גרסה 9.0.0
ואילך:
$ firebase --version 9.0.0
התחברות
מריצים את הפקודה firebase login
כדי לקשר את CLI לחשבון Google. ייפתח חלון חדש בדפדפן כדי להשלים את תהליך ההתחברות. חשוב לבחור באותו חשבון שבו השתמשתם כשיצרתם את פרויקט Firebase מקודם.
קישור הפרויקט
בתיקייה friendlyeats-android
, מריצים את הפקודה firebase use --add
כדי לקשר את הפרויקט המקומי לפרויקט Firebase. פועלים לפי ההנחיות כדי לבחור את הפרויקט שיצרתם מקודם. אם מוצגת בקשה לבחור כינוי, מזינים default
.
5. הפעלת האפליקציה
עכשיו הגיע הזמן להפעיל את ערכת האמולטורים של Firebase ואת אפליקציית FriendlyEats ל-Android בפעם הראשונה.
הפעלת האמולטורים
בטרמינל, מתוך הספרייה friendlyeats-android
, מריצים את הפקודה firebase emulators:start
כדי להפעיל את אמולרטורים של Firebase. היומנים אמורים להיראות כך:
$ 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.
עכשיו יש לכם סביבת פיתוח מקומית מלאה שפועלת במחשב. חשוב להשאיר את הפקודה הזו פועלת במהלך כל שאר הקודלאב, כי אפליקציית Android תצטרך להתחבר למהדמנים.
קישור האפליקציה לאמולטורים
פותחים את הקבצים util/FirestoreInitializer.kt
ו-util/AuthInitializer.kt
ב-Android Studio. הקבצים האלה מכילים את הלוגיקה לחיבור ערכות ה-SDK של Firebase למהדמנים המקומיים שפועלים במחשב, בזמן הפעלת האפליקציה.
ב-method create()
של הכיתה FirestoreInitializer
, בודקים את קטע הקוד הזה:
// Use emulators only in debug builds
if (BuildConfig.DEBUG) {
firestore.useEmulator(FIRESTORE_EMULATOR_HOST, FIRESTORE_EMULATOR_PORT)
}
אנחנו משתמשים ב-BuildConfig
כדי לוודא שנתחבר לאמולטורים רק כשהאפליקציה שלנו פועלת במצב debug
. כשאנחנו קוראים את האפליקציה במצב release
, התנאי הזה יהיה שקר.
אפשר לראות שהשיטה useEmulator(host, port)
משמשת לחיבור Firebase SDK למהדמ של Firestore המקומי. לאורך האפליקציה נשתמש ב-FirebaseUtil.getFirestore()
כדי לגשת למכונה הזו של FirebaseFirestore
, כדי שנוכל לוודא שאנחנו תמיד מתחברים לאמולטור של Firestore כשאנחנו מריצים במצב debug
.
הפעלת האפליקציה
אם הוספתם את הקובץ google-services.json
בצורה נכונה, עכשיו הפרויקט אמור להיערך. ב-Android Studio, לוחצים על Build (פיתוח) > Rebuild Project (פיתוח מחדש של הפרויקט) ומוודאים שאין שגיאות נוספות.
ב-Android Studio, מריצים את האפליקציה במהדמנת Android. קודם תוצג לכם מסך 'כניסה'. אפשר להשתמש בכל כתובת אימייל וסיסמה כדי להיכנס לאפליקציה. תהליך הכניסה הזה מתחבר למהדר של אימות Firebase, כך שלא מועברים פרטי כניסה אמיתיים.
עכשיו פותחים את ממשק המשתמש של המהדמנים. לשם כך, עוברים לכתובת http://localhost:4000 בדפדפן האינטרנט. לאחר מכן לוחצים על הכרטיסייה Authentication (אימות) ואמור להופיע החשבון שיצרתם:
אחרי שתשלימו את תהליך הכניסה, אמור להופיע מסך הבית של האפליקציה:
בקרוב נוסיף נתונים כדי לאכלס את מסך הבית.
6. כתיבת נתונים ב-Firestore
בקטע הזה נכתוב נתונים מסוימים ב-Firestore כדי שנוכל לאכלס את מסך הבית הריק.
אובייקט המודל הראשי באפליקציה שלנו הוא מסעדה (ראו model/Restaurant.kt
). הנתונים ב-Firestore מחולקים למסמכים, לקולקציות ולקולקציות משנה. נשמור כל מסעדה כמסמך באוסף ברמה העליונה שנקרא "restaurants"
. מידע נוסף על מודל הנתונים של Firestore זמין במסמכי העזרה.
למטרות הדגמה, נוסיף לאפליקציה פונקציונליות שתאפשר ליצור עשרה מסעדות אקראיות בלחיצה על הלחצן 'הוספת פריטים אקראיים' בתפריט הנפתח. פותחים את הקובץ MainFragment.kt
ומחליפים את התוכן בשיטה onAddItemsClicked()
בקוד הבא:
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)
}
}
יש כמה דברים חשובים שצריך לזכור לגבי הקוד שלמעלה:
- התחלנו בקבלת הפניה לאוסף
"restaurants"
. האוספים נוצרים באופן משתמע כשמוסיפים מסמכים, כך שלא היה צורך ליצור את האוסף לפני כתיבת הנתונים. - אפשר ליצור מסמכים באמצעות כיתות נתונים של Kotlin, שבהן אנחנו משתמשים כדי ליצור כל מסמך מסוג מסעדה.
- השיטה
add()
מוסיפה מסמך לקולקציה עם מזהה שנוצר באופן אוטומטי, כך שלא נדרשנו לציין מזהה ייחודי לכל מסעדה.
עכשיו מריצים שוב את האפליקציה ולוחצים על הלחצן 'הוספת פריטים אקראיים' בתפריט הנפתח (בפינה השמאלית העליונה) כדי להפעיל את הקוד שכתבתם:
עכשיו פותחים את ממשק המשתמש של המהדמנים. לשם כך, עוברים לכתובת http://localhost:4000 בדפדפן האינטרנט. לאחר מכן לוחצים על הכרטיסייה Firestore ואמורים להופיע הנתונים שהוספתם:
הנתונים האלה הם מקומיים במחשב שלכם בלבד. למעשה, הפרויקט האמיתי שלכם עדיין לא מכיל מסד נתונים של Firestore. כלומר, אפשר להתנסות בשינוי ובמחיקה של הנתונים האלה ללא חשש.
כל הכבוד, כתבתם נתונים ב-Firestore! בשלב הבא נסביר איך להציג את הנתונים האלה באפליקציה.
7. הצגת נתונים מ-Firestore
בשלב הזה תלמדו איך לאחזר נתונים מ-Firestore ולהציג אותם באפליקציה. השלב הראשון בקריאת נתונים מ-Firestore הוא ליצור Query
. פותחים את הקובץ MainFragment.kt
ומוסיפים את הקוד הבא לתחילת השיטה onViewCreated()
:
// Firestore
firestore = Firebase.firestore
// Get the 50 highest rated restaurants
query = firestore.collection("restaurants")
.orderBy("avgRating", Query.Direction.DESCENDING)
.limit(LIMIT.toLong())
עכשיו אנחנו רוצים להאזין לשאילתה, כדי שנקבל את כל המסמכים התואמים ונקבל התראות על עדכונים עתידיים בזמן אמת. המטרה הסופית שלנו היא לקשר את הנתונים האלה ל-RecyclerView
, לכן אנחנו צריכים ליצור כיתה RecyclerView.Adapter
כדי להאזין לנתונים.
פותחים את הכיתה FirestoreAdapter
, שכבר הופעלה חלקית. קודם כול, נגרום למתאם להטמיע את EventListener
ולהגדיר את הפונקציה onEvent
כך שתוכל לקבל עדכונים לשאילתה ב-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()
}
// ...
}
בטעינה הראשונית, המאזין יקבל אירוע ADDED
אחד לכל מסמך חדש. כאשר קבוצת התוצאות של השאילתה משתנה לאורך זמן, המאזין יקבל יותר אירועים שמכילים את השינויים. עכשיו נסיים את הטמעת המאזין. קודם מוסיפים שלוש שיטות חדשות: onDocumentAdded
, onDocumentModified
ו-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)
}
לאחר מכן, קוראים לשיטות החדשות האלה מ-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()
}
לבסוף, מטמיעים את השיטה startListening()
כדי לצרף את המאזין:
fun startListening() {
if (registration == null) {
registration = query.addSnapshotListener(this)
}
}
עכשיו האפליקציה מוגדרת באופן מלא לקריאת נתונים מ-Firestore. מריצים שוב את האפליקציה, ואמורים להופיע בה המסעדות שהוספתם בשלב הקודם:
עכשיו חוזרים לממשק המשתמש של המהדר בדפדפן ועורכים את אחד משמות המסעדות. השינוי אמור להופיע באפליקציה כמעט באופן מיידי.
8. מיון וסינון של נתונים
נכון לעכשיו, האפליקציה מציגה את המסעדות עם הדירוג הגבוה ביותר מתוך כל האוסף, אבל באפליקציה אמיתית של מסעדות, המשתמשים רוצים למיין ולסנן את הנתונים. לדוגמה, האפליקציה אמורה להיות מסוגלת להציג את האפשרויות 'מסעדות הדגים והמאכלי הים המובילות בפילדלפיה' או 'הפיצה הזולה ביותר'.
לחיצה על הסרגל הלבן בחלק העליון של האפליקציה תציג תיבת דו-שיח של מסננים. בקטע הזה נשתמש בשאילתות של Firestore כדי להפעיל את תיבת הדו-שיח הזו:
נערוך את השיטה onFilter()
של MainFragment.kt
. השיטה הזו מקבלת אובייקט Filters
שהוא אובייקט עזר שיצרנו כדי לתעד את הפלט של תיבת הדו-שיח של המסננים. נשנה את השיטה הזו כדי ליצור שאילתות מהמסננים:
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
}
בקטע הקוד שלמעלה אנחנו יוצרים אובייקט Query
על ידי צירוף תנאי where
ו-orderBy
כדי להתאים למסננים הנתונים.
מריצים שוב את האפליקציה ובוחרים את המסנן הבא כדי להציג את המסעדות הפופולריות ביותר במחירים נמוכים:
עכשיו אמורה להופיע רשימה מסוננת של מסעדות שמכילה רק אפשרויות במחירים נמוכים:
אם הגעתם עד כאן, סימן שיצרתם אפליקציה פונקציונלית לחלוטין להצגת המלצות למסעדות ב-Firestore. עכשיו אפשר למיין ולסנן מסעדות בזמן אמת. בחלקים הבאים נוסיף ביקורות למסעדות ונוסיף כללי אבטחה לאפליקציה.
9. ארגון נתונים באוספים משניים
בקטע הזה נוסיף דירוגים לאפליקציה כדי שהמשתמשים יוכלו לכתוב ביקורות על המסעדות האהובות עליהם (או הכי פחות אהובות).
אוספים ואוספים משניים
עד עכשיו שמרתם את כל נתוני המסעדות באוסף ברמה העליונה שנקרא 'מסעדות'. כשמשתמש נותן דירוג למסעדה, אנחנו רוצים להוסיף אובייקט Rating
חדש למסעדות. במשימה הזו נשתמש באוסף משנה. אוסף משנה הוא אוסף שמצורף למסמך. לכן לכל מסמך מסעדה תהיה אוסף משנה של דירוגים שמכיל מסמכי דירוג. אוספים משניים עוזרים לארגן את הנתונים בלי להגדיל את נפח המסמכים או לדרוש שאילתות מורכבות.
כדי לגשת לאוסף משנה, צריך להפעיל את .collection()
במסמך ההורה:
val subRef = firestore.collection("restaurants")
.document("abc123")
.collection("ratings")
אפשר לגשת לאוסף משנה ולבצע בו שאילתות בדיוק כמו באוסף ברמה העליונה, ללא הגבלות גודל או שינויים בביצועים. כאן אפשר לקרוא מידע נוסף על מודל הנתונים של Firestore.
כתיבת נתונים בעסקה
כדי להוסיף Rating
לאוסף המשנה המתאים, צריך רק להפעיל את .add()
, אבל צריך גם לעדכן את הדירוג הממוצע ואת מספר הדירוגים של האובייקט Restaurant
כך שישקפו את הנתונים החדשים. אם נשתמש בפעולות נפרדות כדי לבצע את שני השינויים האלה, יש כמה תנאי תחרות שעלולים לגרום לנתונים לא עדכניים או שגויים.
כדי לוודא שהדירוגים מתווספים בצורה תקינה, נשתמש בעסקה כדי להוסיף דירוגים למסעדה. העסקה הזו תבצע כמה פעולות:
- קוראים את הדירוג הנוכחי של המסעדה ומחשבים את הדירוג החדש
- מוסיפים את הדירוג לאוסף המשנה
- עדכון הדירוג הממוצע ומספר הדירוגים של המסעדה
פותחים את RestaurantDetailFragment.kt
ומטמיעים את הפונקציה 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
}
}
הפונקציה addRating()
מחזירה Task
שמייצג את העסקה כולה. בפונקציה onRating()
, מאזינים מתווספים למשימה כדי להגיב לתוצאה של העסקה.
עכשיו מריצים שוב את האפליקציה ולוחצים על אחת מהמסעדות. המסך עם פרטי המסעדה אמור להופיע. לוחצים על הלחצן + כדי להתחיל להוסיף ביקורת. כדי להוסיף ביקורת, בוחרים מספר כוכבים ומזינים טקסט.
לחיצה על Submit תפעיל את העסקה. כשהעסקה תושלם, הביקורת שלכם תוצג למטה ותופיע עדכון למספר הביקורות של המסעדה:
מזל טוב! עכשיו יש לכם אפליקציה לנייד עם ביקורות על מסעדות, שמבוססת על Cloud Firestore. אני שומע שהם פופולריים מאוד בימים האלה.
10. אבטחת הנתונים
עד כה לא התייחסנו לאבטחה של האפליקציה הזו. איך אנחנו יודעים שהמשתמשים יכולים לקרוא ולכתוב רק את הנתונים הנכונים שלהם? מסדי הנתונים של Firestore מאובטחים באמצעות קובץ תצורה שנקרא Security Rules.
פותחים את הקובץ firestore.rules
ומחליפים את התוכן בקוד הבא:
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;
}
}
}
}
הכללים האלה מגבילים את הגישה כדי לוודא שהלקוחות מבצעים רק שינויים בטוחים. לדוגמה, עדכונים במסמך של מסעדה יכולים לשנות רק את הדירוגים, ולא את השם או נתונים אחרים שלא ניתן לשנות. אפשר ליצור דירוגים רק אם מזהה המשתמש תואם למשתמש שמחובר לחשבון, וכך למנוע זיופים.
מידע נוסף על כללי אבטחה זמין במסמכי התיעוד.
11. סיכום
עכשיו יצרתם אפליקציה עם כל התכונות שמבוססת על Firestore. למדתם על התכונות החשובות ביותר של Firestore, כולל:
- מסמכים ואוספים
- קריאה וכתיבה של נתונים
- מיון וסינון באמצעות שאילתות
- אוספי משנה
- עסקאות
מידע נוסף
כדי להמשיך ללמוד על Firestore, ריכזנו כאן כמה מקורות מידע שיכולים לעזור לכם להתחיל:
אפליקציית המסעדות בקודלאב הזה מבוססת על אפליקציית הדוגמה 'Friendly Eats'. אפשר לעיין בקוד המקור של האפליקציה הזו כאן.
אופציונלי: פריסה בסביבת הייצור
עד כה, באפליקציה הזו נעשה שימוש רק בחבילת הכלים של אמולטור Firebase. כדי ללמוד איך לפרוס את האפליקציה הזו בפרויקט Firebase אמיתי, ממשיכים לשלב הבא.
12. (אופציונלי) פריסת האפליקציה
עד כה האפליקציה הזו הייתה מקומית לחלוטין, וכל הנתונים נכללים ב-Firebase Emulator Suite. בקטע הזה תלמדו איך להגדיר את פרויקט Firebase כך שהאפליקציה הזו תפעל בסביבת הייצור.
אימות ב-Firebase
במסוף Firebase, עוברים לקטע Authentication ולוחצים על Get started. עוברים לכרטיסייה שיטת כניסה ובוחרים באפשרות אימייל/סיסמה בקטע ספקים מקומיים.
מפעילים את אמצעי הכניסה כתובת אימייל/סיסמה ולוחצים על שמירה.
Firestore
יצירת מסד נתונים
עוברים לקטע Firestore Database במסוף ולוחצים על Create Database:
- כשמוצגת בקשה לגבי כללי האבטחה, בוחרים להתחיל במצב ייצור. בקרוב נעדכן את הכללים האלה.
- בוחרים את המיקום של מסד הנתונים שבו רוצים להשתמש באפליקציה. חשוב לזכור שבחירת מיקום של מסד נתונים היא החלטה קבועה, וכדי לשנות אותה תצטרכו ליצור פרויקט חדש. מידע נוסף על בחירת מיקום לפרויקט זמין במסמכי העזרה.
פריסה של כללים
כדי לפרוס את כללי האבטחה שכתבתם מקודם, מריצים את הפקודה הבאה בספרייה של codelab:
$ firebase deploy --only firestore:rules
הפקודה הזו פורסת את התוכן של firestore.rules
בפרויקט. כדי לוודא זאת, עוברים לכרטיסייה Rules במסוף.
פריסת מדדים
באפליקציית FriendlyEats יש מיון ומסננים מורכבים, שדורשים מספר מדדים מורכבים בהתאמה אישית. אפשר ליצור אותם באופן ידני במסוף Firebase, אבל קל יותר לכתוב את ההגדרות שלהם בקובץ firestore.indexes.json
ולפרוס אותם באמצעות ה-CLI של Firebase.
אם פותחים את הקובץ firestore.indexes.json
, רואים שכבר סיפקתם את האינדקסים הנדרשים:
{
"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": []
}
כדי לפרוס את המדדים האלה, מריצים את הפקודה הבאה:
$ firebase deploy --only firestore:indexes
חשוב לזכור יצירת האינדקס לא מתבצעת באופן מיידי. אפשר לעקוב אחרי ההתקדמות במסוף Firebase.
הגדרת האפליקציה
בקבצים util/FirestoreInitializer.kt
ו-util/AuthInitializer.kt
הגדרנו את Firebase SDK להתחבר למהדמנים במצב ניפוי באגים:
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
}
אם רוצים לבדוק את האפליקציה עם פרויקט Firebase האמיתי, אפשר:
- יוצרים את האפליקציה במצב build לגרסת build ומריצים אותה במכשיר.
- מחליפים את
BuildConfig.DEBUG
באופן זמני ב-false
ומפעילים את האפליקציה שוב.
שימו לב: יכול להיות שתצטרכו לצאת מהאפליקציה ולהיכנס שוב כדי להתחבר כראוי לסביבת הייצור.