1. סקירה כללית
מטרות
במעבדת הקוד הזה תבנו אפליקציית המלצות למסעדות באנדרואיד בגיבוי של Cloud Firestore. תלמד כיצד:
- קרא וכתוב נתונים ל-Firestore מאפליקציית Android
- האזן לשינויים בנתוני Firestore בזמן אמת
- השתמש בכללי אימות Firebase ואבטחה כדי לאבטח את נתוני Firestore
- כתוב שאילתות מורכבות של Firestore
דרישות מוקדמות
לפני שתתחיל מעבדת קוד זה ודא שיש לך:
- Android Studio Flamingo או חדש יותר
- אמולטור אנדרואיד עם API 19 ומעלה
- Node.js גרסה 16 ומעלה
- Java גרסה 17 ומעלה
2. צור פרויקט Firebase
- היכנס למסוף Firebase עם חשבון Google שלך.
- במסוף Firebase , לחץ על הוסף פרויקט .
- כפי שמוצג בצילום המסך למטה, הזן שם לפרויקט Firebase שלך (לדוגמה, "Friendly Eats") ולחץ על המשך .
- ייתכן שתתבקש להפעיל את Google Analytics, למטרות מעבדת קוד זה הבחירה שלך לא משנה.
- לאחר כדקה, פרויקט Firebase שלך יהיה מוכן. לחץ על המשך .
3. הגדר את הפרויקט לדוגמה
הורד את הקוד
הפעל את הפקודה הבאה כדי לשכפל את הקוד לדוגמה עבור מעבדת קוד זה. פעולה זו תיצור תיקייה בשם friendlyeats-android
במחשב שלך:
$ git clone https://github.com/firebase/friendlyeats-android
אם אין לך git במחשב שלך, אתה יכול גם להוריד את הקוד ישירות מ-GitHub.
הוסף תצורת Firebase
- במסוף Firebase , בחר סקירת פרויקט בניווט השמאלי. לחץ על כפתור אנדרואיד כדי לבחור את הפלטפורמה. כשתתבקש להזין שם חבילה, השתמש ב-
com.google.firebase.example.fireeats
- לחץ על הרשום אפליקציה ובצע את ההוראות להורדת הקובץ
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 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 בדפדפן האינטרנט שלך. לאחר מכן לחץ על הכרטיסייה אימות ואתה אמור לראות את החשבון שיצרת זה עתה:
לאחר השלמת תהליך הכניסה, אתה אמור לראות את מסך הבית של האפליקציה:
בקרוב נוסיף כמה נתונים כדי לאכלס את מסך הבית.
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 ואתה אמור לראות את הנתונים שזה עתה הוספת:
נתונים אלה הם 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. הפעל שוב את האפליקציה ואתה אמור לראות את המסעדות שהוספת בשלב הקודם:
כעת חזור לממשק המשתמש של האמולטור בדפדפן שלך וערוך את אחד משמות המסעדות. אתה אמור לראות את זה משתנה באפליקציה כמעט באופן מיידי!
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()
מתווספים מאזינים למשימה כדי להגיב לתוצאה של העסקה.
כעת הפעל שוב את האפליקציה ולחץ על אחת המסעדות, מה שאמור להעלות את מסך פרטי המסעדה. לחץ על הלחצן + כדי להתחיל בהוספת ביקורת. הוסף ביקורת על ידי בחירת מספר כוכבים והזנת טקסט כלשהו.
לחיצה על שלח תניע את העסקה. כאשר העסקה תושלם, תראה את הביקורת שלך מוצגת למטה ועדכון לספירת הביקורות של המסעדה:
מזל טוב! כעת יש לך אפליקציה חברתית, מקומית, ניידת לביקורת מסעדות הבנויה על 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 עבור אל הקטע אימות ולחץ על התחל . נווט אל הכרטיסייה שיטת כניסה ובחר באפשרות דוא"ל/סיסמה מספקים מקומיים .
הפעל את שיטת הכניסה לדוא"ל/סיסמה ולחץ על שמור .
Firestore
צור מסד נתונים
נווט אל הקטע Firestore Database של המסוף ולחץ על Create Database :
- כאשר תתבקש לגבי כללי אבטחה בחר להתחיל במצב ייצור , אנו נעדכן את הכללים הללו בקרוב.
- בחר את מיקום מסד הנתונים שבו תרצה להשתמש עבור האפליקציה שלך. שימו לב שבחירת מיקום מסד נתונים היא החלטה קבועה וכדי לשנות אותו תצטרכו ליצור פרויקט חדש. למידע נוסף על בחירת מיקום פרויקט, עיין בתיעוד .
פריסת כללים
כדי לפרוס את כללי האבטחה שכתבת קודם לכן, הפעל את הפקודה הבאה בספריית 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 האמיתי שלך, תוכל:
- בנה את האפליקציה במצב שחרור והפעל אותה במכשיר.
- החלף באופן זמני
BuildConfig.DEBUG
ב-false
והפעל את האפליקציה שוב.
שים לב שייתכן שתצטרך לצאת מהאפליקציה ולהיכנס שוב כדי להתחבר כראוי לייצור.