Cloud Firestore Android Codelab

קל לארגן דפים בעזרת אוספים אפשר לשמור ולסווג תוכן על סמך ההעדפות שלך.

1. סקירה כללית

מטרות

במעבדת הקוד הזה תבנו אפליקציית המלצות למסעדות באנדרואיד בגיבוי של Cloud Firestore. תלמד כיצד:

  • קרא וכתוב נתונים ל-Firestore מאפליקציית Android
  • האזן לשינויים בנתוני Firestore בזמן אמת
  • השתמש בכללי אימות Firebase ואבטחה כדי לאבטח את נתוני Firestore
  • כתוב שאילתות מורכבות של Firestore

דרישות מוקדמות

לפני שתתחיל מעבדת קוד זה ודא שיש לך:

  • Android Studio 4.0 ומעלה
  • אמולטור אנדרואיד עם API 19 ומעלה
  • Node.js גרסה 10 ומעלה
  • Java גרסה 8 ומעלה

2. צור פרויקט Firebase

  1. היכנס למסוף Firebase עם חשבון Google שלך.
  2. במסוף Firebase , לחץ על הוסף פרויקט .
  3. כפי שמוצג בצילום המסך למטה, הזן שם לפרויקט Firebase שלך ​​(לדוגמה, "Friendly Eats") ולחץ על המשך .

9d2f625aebcab6af.png

  1. ייתכן שתתבקש להפעיל את Google Analytics, למטרות מעבדת קוד זה הבחירה שלך לא משנה.
  2. לאחר כדקה, פרויקט Firebase שלך ​​יהיה מוכן. לחץ על המשך .

3. הגדר את הפרויקט לדוגמה

הורד את הקוד

הפעל את הפקודה הבאה כדי לשכפל את הקוד לדוגמה עבור מעבדת קוד זה. פעולה זו תיצור תיקייה בשם friendlyeats-android במחשב שלך:

$ git clone https://github.com/firebase/friendlyeats-android

אם אין לך git במחשב שלך, אתה יכול גם להוריד את הקוד ישירות מ-GitHub.

הוסף תצורת Firebase

  1. במסוף Firebase , בחר סקירת פרויקט בניווט השמאלי. לחץ על כפתור אנדרואיד כדי לבחור את הפלטפורמה. כשתתבקש להזין שם חבילה, השתמש ב- com.google.firebase.example.fireeats

73d151ed16016421.png

  1. לחץ על הרשום אפליקציה ובצע את ההוראות להורדת הקובץ google-services.json , והעבר אותו app/ תיקייה של הקוד שהורדת זה עתה. לאחר מכן לחץ על הבא .

ייבא את הפרויקט

פתח את Android Studio. לחץ על קובץ > חדש > ייבוא ​​פרויקט ובחר בתיקייה friendlyeats-android .

4. הגדר את אמולטורי Firebase

במעבדת הקוד הזה תשתמש ב- Firebase Emulator Suite כדי לחקות מקומית את Cloud Firestore ושירותי Firebase אחרים. זה מספק סביבת פיתוח מקומית בטוחה, מהירה וללא עלות לבניית האפליקציה שלך.

התקן את Firebase CLI

ראשית תצטרך להתקין את 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 firebase use --add כדי לחבר את הפרויקט המקומי שלך לפרויקט Firebase שלך. עקוב אחר ההנחיות כדי לבחור את הפרויקט שיצרת קודם לכן, ואם תתבקש לבחור כינוי הזן default .

5. הפעל את האפליקציה

עכשיו הגיע הזמן להפעיל את Firebase Emulator Suite ואת אפליקציית 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.

כעת יש לך סביבת פיתוח מקומית מלאה על המחשב שלך! הקפד להשאיר את הפקודה הזו פועלת לשארית מעבדת הקוד, אפליקציית האנדרואיד שלך תצטרך להתחבר לאמולטורים.

חבר את האפליקציה לאמולטורים

פתח את הקבצים util/FirestoreInitializer.kt ו- util/AuthInitializer.kt ב-Android Studio. קבצים אלה מכילים את ההיגיון לחיבור ה-SDK של Firebase לאמולטורים המקומיים הפועלים במחשב שלך, עם הפעלת האפליקציה.

בשיטת 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 הפעל את האפליקציה באמולטור האנדרואיד שלך. בהתחלה יוצג בפניכם מסך "כניסה". אתה יכול להשתמש בכל אימייל וסיסמה כדי להיכנס לאפליקציה. תהליך הכניסה הזה מתחבר לאמולטור האימות של Firebase, כך שלא מועברים אישורים אמיתיים.

כעת פתח את ממשק המשתמש האמולטורים על ידי ניווט אל http://localhost:4000 בדפדפן האינטרנט שלך. לאחר מכן לחץ על הכרטיסייה אימות ואתה אמור לראות את החשבון שיצרת זה עתה:

Firebase Auth Emulator

לאחר השלמת תהליך הכניסה, אתה אמור לראות את מסך הבית של האפליקציה:

de06424023ffb4b9.png

בקרוב נוסיף כמה נתונים כדי לאכלס את מסך הבית.

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() מוסיפה מסמך לאוסף עם מזהה שנוצר אוטומטית, כך שלא היינו צריכים לציין מזהה ייחודי לכל מסעדה.

כעת הפעל את האפליקציה שוב ולחץ על כפתור "הוסף פריטים אקראיים" בתפריט הגלישה (בפינה השמאלית העליונה) כדי להפעיל את הקוד שזה עתה כתבת:

95691e9b71ba55e3.png

כעת פתח את ממשק המשתמש האמולטורים על ידי ניווט אל http://localhost:4000 בדפדפן האינטרנט שלך. לאחר מכן לחץ על הכרטיסייה Firestore ואתה אמור לראות את הנתונים שזה עתה הוספת:

Firebase Auth Emulator

נתונים אלה הם 100% מקומיים למחשב שלך. למעשה, הפרויקט האמיתי שלך אפילו לא מכיל מסד נתונים של 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. הפעל שוב את האפליקציה ואתה אמור לראות את המסעדות שהוספת בשלב הקודם:

9e45f40faefce5d0.png

כעת חזור לממשק המשתמש של האמולטור בדפדפן שלך וערוך את אחד משמות המסעדות. אתה אמור לראות את זה משתנה באפליקציה כמעט באופן מיידי!

8. מיין וסנן נתונים

האפליקציה מציגה כרגע את המסעדות המדורגות ביותר על פני כל האוסף, אך באפליקציית מסעדות אמיתית המשתמש ירצה למיין ולסנן את הנתונים. לדוגמה, האפליקציה צריכה להיות מסוגלת להציג "מסעדות פירות ים מובילות בפילדלפיה" או "פיצה הכי פחות יקרה".

לחיצה על פס לבן בחלק העליון של האפליקציה מעלה תיבת דו-שיח מסננים. בסעיף זה נשתמש בשאילתות Firestore כדי לגרום לשיח הזה לעבוד:

67898572a35672a5.png

בואו נערוך את שיטת 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 כדי להתאים למסננים הנתונים.

הפעל שוב את האפליקציה ובחר את המסנן הבא כדי להציג את המסעדות הפופולריות ביותר במחיר נמוך:

7a67a8a400c80c50.png

כעת אתה אמור לראות רשימה מסוננת של מסעדות המכילה רק אפשרויות במחיר נמוך:

a670188398c3c59.png

אם הגעתם עד הלום, בניתם כעת אפליקציית צפייה בהמלצות למסעדות ב-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() מתווספים מאזינים למשימה כדי להגיב לתוצאה של העסקה.

כעת הפעל שוב את האפליקציה ולחץ על אחת המסעדות, מה שאמור להעלות את מסך פרטי המסעדה. לחץ על הלחצן + כדי להתחיל בהוספת ביקורת. הוסף ביקורת על ידי בחירת מספר כוכבים והזנת טקסט כלשהו.

78fa16cdf8ef435a.png

לחיצה על שלח תניע את העסקה. כאשר העסקה תושלם, תראה את הביקורת שלך מוצגת למטה ועדכון לספירת הביקורות של המסעדה:

f9e670f40bd615b0.png

מזל טוב! כעת יש לך אפליקציה חברתית, מקומית, ניידת לביקורת מסעדות הבנויה על Cloud Firestore. שמעתי שהם מאוד פופולריים בימינו.

10. אבטח את הנתונים שלך

עד כה לא שקלנו את האבטחה של יישום זה. איך נדע שמשתמשים יכולים לקרוא ולכתוב רק את הנתונים הנכונים? מסדי נתונים של Firestore מאובטחים על ידי קובץ תצורה בשם כללי אבטחה .

פתח את הקובץ firestore.rules , אתה אמור לראות את הדברים הבאים:

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;
    }
  }
}

הבה נשנה את הכללים האלה כדי למנוע גישה או שינויים לא רצויים לנתונים, נפתח את הקובץ 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 Emulator Suite. אם אתה רוצה ללמוד כיצד לפרוס את האפליקציה הזו לפרויקט Firebase אמיתי, המשך לשלב הבא.

12. (אופציונלי) פרוס את האפליקציה שלך

עד כה האפליקציה הזו הייתה מקומית לחלוטין, כל הנתונים כלולים ב-Firebase Emulator Suite. בסעיף זה תלמד כיצד להגדיר את פרויקט Firebase שלך ​​כך שהאפליקציה הזו תעבוד בייצור.

אימות Firebase

במסוף Firebase עבור אל הקטע אימות ולחץ על התחל . נווט אל הכרטיסייה שיטת כניסה ובחר באפשרות דוא"ל/סיסמה מספקים מקומיים .

הפעל את שיטת הכניסה לדוא"ל/סיסמה ולחץ על שמור .

sign-in-providers.png

Firestore

צור מסד נתונים

נווט אל הקטע Firestore Database של המסוף ולחץ על Create Database :

  1. כאשר תתבקש לגבי כללי אבטחה בחר להתחיל במצב ייצור , אנו נעדכן את הכללים הללו בקרוב.
  2. בחר את מיקום מסד הנתונים שבו תרצה להשתמש עבור האפליקציה שלך. שימו לב שבחירת מיקום מסד נתונים היא החלטה קבועה וכדי לשנות אותו תצטרכו ליצור פרויקט חדש. למידע נוסף על בחירת מיקום פרויקט, עיין בתיעוד .

פריסת כללים

כדי לפרוס את כללי האבטחה שכתבת קודם לכן, הפעל את הפקודה הבאה בספריית codelab:

$ firebase deploy --only firestore:rules

פעולה זו תפרוס את התוכן של firestore.rules לפרויקט שלך, אותו תוכל לאשר על ידי ניווט ללשונית כללים במסוף.

פריסת אינדקסים

לאפליקציית FriendlyEats יש מיון וסינון מורכבים הדורשים מספר אינדקסים מורכבים מותאמים אישית. ניתן ליצור אותם ביד במסוף Firebase אך קל יותר לכתוב את ההגדרות שלהם בקובץ firestore.indexes.json ולפרוס אותם באמצעות Firebase CLI.

אם תפתח את הקובץ 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 האמיתי שלך, תוכל:

  1. בנה את האפליקציה במצב שחרור והפעל אותה במכשיר.
  2. החלף באופן זמני את BuildConfig.DEBUG ב- false והפעל את האפליקציה שוב.

שים לב שייתכן שתצטרך לצאת מהאפליקציה ולהיכנס שוב כדי להתחבר כראוי לייצור.